Using "pluck" -> undefined method for nil:NilClass - ruby-on-rails

I tried using pluck as a shortcut to select one or more attributes without loading a bunch of records just to grab the attributes I want. Which is pretty much 1:1 the intended use (see here: Pluck).
There are 2 tables: "demands" and "parents".
the idea is to create a new entry in the table "demands". The table "demands" contains a column "parent_id" and the demand/parent models are properly associated through belongs_to and has_many.
this is my code using the pluck method:
<%= form.label :parent_id %><br>
<% if can? :optimize, Matching %> <----TEST FOR ADMIN RIGHTS
<%= form.collection_select :parent_id, Parent.all, :id, :fullname %>
<% else %>
<%= #parent.pluck(:name) %> <-----ERROR ERROR ERROR
<%= form.hidden_field :parent_id, value: #parent.pluck(:id) %>
<% end %><br><br>
The corresponding datatable "parents" obviously contains all three of these values, firstname, name and id.
However, this is my error:
undefined method `pluck' for nil:NilClass
error occurs in /app/views/demands/_form.html.erb
update: this is the complete _form.html.erb
<%= form_for Demand.new do |form| %>
<%= form.label :parent_id %><br>
<% if can? :optimize, Matching %>
<%= form.collection_select :parent_id, Parent.all, :id, :fullname %>
<% else %>
<%= #parent.pluck(:name) %>
<%= form.hidden_field :parent_id, value: #parent.pluck(:id) %>
<% end %><br><br>
<%= form.label :demand %><br>
<%= form.number_field :demand %>
<%= form.label :shift_id %><br>
<%= form.collection_select :shift_id, Shift.all, :id, :description %>
<div class="actions">
<%= form.submit 'Post a new job', {:class => "btn btn-primary"} %>
</div>
<% end %>
This is the demand controller action "create"
def new
#demands = Demand.new
if cannot? :optimize, Matching
#parent = Parent.where(parents: {firstname: current_user.firstname, name: current_user.name})
end
end
def create
#demand = Demand.new(demand_params)
respond_to do |format|
if #demand.save
format.html { redirect_to #demand, notice: 'Demand was successfully created.' }
format.json { render :show, status: :created, location: #demand }
else
format.html { render :new }
format.json { render json: #demand.errors, status: :unprocessable_entity }
end
end
end
Thanks in advance for any advice!

Your #parent instance var is only defined in the create action. So, if #demand.save returns false (Invalid object), the exception occurs because #parent is nil

Related

Access to a param in another controller sended by render :template

So im sending a param from a view to a view of another controller
<%= render template: 'dishes/new', :id => #restaurant.id %>
and this is my other controller view:
def new
#dish = Dish.new
#id = params[:id]
end
def create
#dish = Dish.new(dish_params)
respond_to do |format|
if #dish.save
format.html { redirect_to #restaurant, notice: 'dish was successfully created.' }
format.json { render action: 'show', status: :created, location: :restaurant }
else
format.html { render action: 'show', location: :restaurant }
format.json { render json: #restaurant.errors, status: :unprocessable_entity }
end
end
end
private
def dish_params
params.require(:dish).permit( :avatar, :name, :description, [:id])
end
and this is my view who calls the form:
#new.html.erb
<h1>Add a new dish</h1>
<%= render 'dishes/dish_form' %>
then here is the form:
<%= form_for #dish, :url => { :controller => "dishes", action_name => "create" } do |f| %>
<div class="field">
<%= f.label :dish_name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.label :image %>
<%= f.file_field :avatar %>
</div>
<div class="actions">
<%= f.submit 'Add new dish' %>
</div>
<% end %>
but when i try to save it i got this error:
I think your problem comes in when you are expecting your render template: 'dishes/new' to hit your DishesController. That is not what is happening when you are calling the render.
What you're doing is telling rails to load into your current view the template for 'dishes/new', and you're passing 'dishes/new' a variable that it can access when rendering. You aren't sending a param to a controller.
If you want to keep the current set up you have right now, you can make it work with some tweaking.
I'm going to assume that your Dish model belongs to Restaurant, and therefore has restaurant_id as a column. If that is true, then you can add a hidden field to your form for dishes, called restaurant_id, and update your permitted params in your controller to allow the restaurant id to be set on the dish.
Your form would look like this:
<%= form_for #dish, :url => { :controller => "dishes", action_name => "create" } do |f| %>
<%= f.hidden_field :restaurant_id, value: id %>
...
<% end %>
Your permitted params in your controller would look like this:
def dish_params
params.require(:dish).permit(:avatar, :name, :description, :restaurant_id)
end
You can get more information on how the rails rendering is working here
The error is saying that your controller named Restaurants does not have an action named "Show".
One solution would be to add the Action with the name "Show" to the restaurant controller.
The other option may be that you actually created the action you wanted, but you named it something other than "Show".

how do i get nested form value to input to database table, instead of nil?

I have a nested form in my rails app. The field that is nested is not adding values to the database.
I want an address added into my Places table. The address field is nested within a form that corresponds to the Post table.
I just pushed full code to github... http://goo.gl/wzjLK2
I think I am not doing something in my Posts Controller #CREATE
def create
#post = Post.new(post_params)
#place = Place.new params[:address]
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
For reference, my Posts form:
<%= form_for(#post) do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :status %><br>
<%= f.text_field :status %>
</div>
<div class="field">
<%= f.label :upload %><br>
<%= f.text_field :upload %>
</div>
<%= f.fields_for #post.place do |p| %>
<div class="field">
<%= p.label :address %><br>
<%= p.text_field :address %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
My Posts model...
class Post < ActiveRecord::Base
belongs_to :place
belongs_to :user
has_many :comments
has_many :commenters, through: :comments, source: :user
accepts_nested_attributes_for :place
def place_for_form
collection = places.where(place_id: id)
collection.any? ? collection : places.build
end
end
Any help is so much appreciated. I've been stuck on this for two days now.
After running the code, I notice there is an error in the server console:
Unpermitted parameters: place
After change this #post.place in
<%= f.fields_for #post.place do |p| %>
<div class="field">
<%= p.label :address %><br>
<%= p.text_field :address %>
</div>
<% end %>
to :place, everything works fine.

How do I display error messages for nested resource validations?

I'm creating a basic blog application and I'm running into issues displaying error messages when a user tries to submit a blank comment. Instead of getting a nice looking error message, an active record error message with the correct validation erorrs. Such as
ActiveRecord::RecordInvalid in CommentsController#create
Validation failed: Name can't be blank, Email can't be blank
In my article/show view I have the following code:
<%= form_for([#article, #article.comments.build]) do |f| %>
<%= render "shared/error_messages", :target => #article %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<p><%= f.submit %></p>
<% end %>
My error messages partial looks like this:
<% if target.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(target.errors.count, "error") %> prohibited this record from being saved:</h2>
<ul>
<% target.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
I know the answer is simple but I can't figure it out.
Create action in comments controller:
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to(#article, :notice => 'Comment was successfully created.') }
format.xml { render :xml => #article, :status => :created, :location => #article }
else
format.html { render :action => "articles/show" }
format.xml { render :xml => #comment.errors, :status => :unprocessable_entity }
end
end
I had a similar problem. everything seemed to work fine, but I was not getting any errors
The solution i found is to build the comment in article#show instead of the view:
#article = Article.find(params[:id])
#comment = #article.comments.build(params[:comment])
and in your articles#show don't use #article.comments.build but #comment:
<%= form_for([#article, #comment]) do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<p><%= f.submit %></p>
<% end %>
make sure you build the comment in your comment#create as well (you really have no choice though :P)
also, I don't know if it matters (i'm pretty new to ruby), but I think you need to pass f.object instead of #comment.
I think you're saying that you get the big grey-on-white error page, right?
Check the backtrace, but I suspect that this is coming from the create action in the controller, not the view.
If your controller uses save! with the ! at the end, that means that it will raise an error if the record is invalid. save, on the other hand, returns true or false and lets you use simple branch logic to decide how to react.
If my hunch on save! isn't right, though, please post controller code so we can dig deeper :) Thanks!
The solution was to direct the comments created action back to the correct controller/action and target #comment in my error message partial.
Final view
<%= form_for([#article, #article.comments.build]) do |f| %>
<%= render "shared/error_messages", :target => #comment %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<p><%= f.submit %></p>
<% end %>
Final create action in comments controller
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to(#article, :notice => 'Comment was successfully created.') }
format.xml { render :xml => #article, :status => :created, :location => #article }
else
format.html { render :action => "articles/show" }
format.xml { render :xml => #comment.errors, :status => :unprocessable_entity }
end
end

How to use a nested form for multiple models in one form?

I'm struggling to come up with the proper way to design a form that will allow me to input data for two different models. The form is for an 'Incident', which has the following relationships:
belongs_to :customer
belongs_to :user
has_one :incident_status
has_many :incident_notes
accepts_nested_attributes_for :incident_notes, :allow_destroy => false
So an incident is assigned to a 'Customer' and a 'User', and the user is able to add 'Notes' to the incident. I'm having trouble with the notes part of the form. Here how the form is being submitted:
{"commit"=>"Create",
"authenticity_token"=>"ECH5Ziv7JAuzs53kt5m/njT9w39UJhfJEs2x0Ms2NA0=",
"customer_id"=>"4",
"incident"=>{"title"=>"Something bad",
"incident_status_id"=>"2",
"user_id"=>"2",
"other_id"=>"AAA01-042310-001",
"incident_note"=>{"note"=>"This is a note"}}}
It appears to be attempting to add the incident_note as a field under 'Incident', rather than creating a new entry in the incident_note table with an incident_id foreign key linking back to the incident.
Here is the 'IncidentNote' model:
belongs_to :incident
belongs_to :user
Here is the form for 'Incident':
<% form_for([#customer,#incident]) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :other_id, "ID" %><br />
<%= f.text_field :capc_id %>
</p>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= label_tag 'user', 'Assign to user?' %>
<%= f.select :user_id, #users.collect {|u| [u.name, u.id]} %>
</p>
<p>
<%= f.label :incident_status, 'Status?' %>
<%= f.select :incident_status_id, #statuses.collect {|s| [s.name, s.id]} %>
</p>
<p>
<% f.fields_for :incident_note do |inote_form| %>
<%= inote_form.label :note, 'Add a Note' %>
<%= inote_form.text_area :note, :cols => 40, :rows => 20 %>
<% end %>
</p>
<p>
<%= f.submit "Create" %>
</p>
<% end %>
And finally, here are the incident_controller entries for New and Create.
New:
def new
#customer = current_user.customer
#incident = Incident.new
#users = #customer.users
#statuses = IncidentStatus.find(:all)
#incident_note = IncidentNote.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #incident }
end
end
Create:
def create
#users = #customer.users
#statuses = IncidentStatus.find(:all)
#incident = Incident.new(params[:incident])
#incident.customer = #customer
#incident_note = #incident.incident_note.build(params[:incident_note])
#incident_note.user = current_user
respond_to do |format|
if #incident.save
flash[:notice] = 'Incident was successfully created.'
format.html { redirect_to(#incident) }
format.xml { render :xml => #incident, :status => :created, :location => #incident }
else
format.html { render :action => "new" }
format.xml { render :xml => #incident.errors, :status => :unprocessable_entity }
end
end
end
I'm not really sure where to look at this point. I'm sure it's just a limitation of my current Rails skill (I don't know much). So if anyone can point me in the right direction I would be very appreciative. Please let me know if more information is needed!
Thanks!
Check api for fields_for method and scroll to one-to-many section.
Your model has many :incident_notes, not one incident_note, that is why it doesn't understand relationship and tries to find a field with this name.
So it should be:
<% f.fields_for :incident_notes do |inote_form| %>
<%= inote_form.label :note, 'Add a Note' %>
<%= inote_form.text_area :note, :cols => 40, :rows => 20 %>
<% end %>
It iterates through all incident_notes assigned to incident and produces fields for each of them.
You also have to build at least one note in you new action, otherwise there will be none:
def new
#incident = Incident.new
#incident.incident_notes.build
# ...
end

How can I refactor this rails code - a key/value model

I have the following models:
class FieldEntryValue < ActiveRecord::Base
belongs_to :field_entry
end
and
class FieldEntry < ActiveRecord::Base
belongs_to :field
belongs_to :media
has_many :field_entry_values, :dependent => :destroy
accepts_nested_attributes_for :field_entry_values, :allow_destroy => true
end
The FieldEntriesController has the following methods:
def new
#field_entry = FieldEntry.new
session[:media_id] = params[:media_id]
session[:field_id] = params[:field_id]
#field_entry.field = Field.find(params[:field_id])
generate_fields(true)
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #field_entry }
end
end
def create
#field_entry = FieldEntry.new(params[:field_entry])
#field_entry.media_id = session[:media_id]
#field_entry.field_id = session[:field_id]
generate_fields(false)
respond_to do |format|
if #field_entry.save
flash[:notice] = 'FieldEntry was successfully created.'
format.html { redirect_to(#field_entry) }
format.xml { render :xml => #field_entry, :status => :created, :locati$
else
format.html { render :action => "new" }
format.xml { render :xml => #field_entry.errors, :status => :unprocess$
end
end
end
def generate_fields(do_build)
#ftype = #field_entry.field.field_type.name
if #ftype == 'string'
#field_entry.field_entry_values.build if do_build
#field_entry.field_entry_values[0].key='name'
elsif #ftype == 'url'
2.times{ #field_entry.field_entry_values.build } if do_build
#field_entry.field_entry_values[0].key='name'
#field_entry.field_entry_values[1].key='url'
elsif #ftype == 'imdb'
1.times{ #field_entry.field_entry_values.build } if do_build
#field_entry.field_entry_values[0].key='value'
end
end
And I have a partial that is loaded by new and edit:
<% form_for(#field_entry) do |f| %>
<%= f.error_messages %>
<% f.fields_for :field_entry_values do |fv_f| %>
<p>
<%= fv_f.label :key %><br />
<%= fv_f.text_field :value %>
</p>
<% end %>
<p>
<%= f.submit 'Save' %>
</p>
<% end %>
The view should show a variable count fields depending on the type and with a given attribute key as label and value for the data.
For the type string as an example I need a label "Name" (that should be the key) and value
This works mostly except "fv_f.label :key" shows the string key and not the value of the key-field.
How can I show the value of #field_entry.field_entry_values.key as label in the view?
How can I make the Controller better/shorter. As an example, do I really need to set #field_entry.field_entry_values[0].key='name' in the new and the create method to to get it displayed in the view and saved in the database?
thanx for suggestions ;) I am a Rails newby I hope I did it not too wrong ;)
try this for 1.
<% form_for(#field_entry) do |f| %>
<%= f.error_messages %>
<% #field_entry.field_entry_values.each do |fv| %>
<% f.fields_for fv do |fv_f| %>
<p>
<%= fv_f.label :value, fv.key %><br />
<%= fv_f.text_field :value %>
<%= # this will eliminate the need for generate_fields in create %>
<%= fv_f.hidden_field :key %>
</p>
<% end %>
<% end %>
<p>
<%= f.submit 'Save' %>
</p>
<% end %>
I found a better solution for my Problem 1, in rails 2.3 there is a object attribute for the fields_for loop target to get the object of the field:
<% form_for(#field_entry) do |f| %>
<%= f.error_messages %>
<% f.fields_for :field_entry_values do |fv_f| %>
<p>
<%= fv_f.label :value, fv_f.object.key%>
<br />
<%= fv_f.text_field :value %>
<%= fv_f.hidden_field :key %>
</p>
<% end %>
<p>
<%= submit_tag %>
</p>
<% end %>
Point 2 can not be improved much, maybe the generate_fields method could be loaded as a filter. But other than that, I donĀ“t see anything at the moment, at least with this database structure.
But thanks for the help: so1o, at least the thing with hidden_field was helpfully.

Resources