collection_select method gives error in Rails 3.1.1 - ruby-on-rails-3

I have a Model called Category and other Model Product. They have has_many and belongs_to relation.
But code in my view
<p><%= f.collection_select(:product, :category_id, Category.all, :id, :name)%>
is giving me
undefined method `merge' for :name:Symbol
Any clue what is wrong with it?

Chances are you have something like this:
<%= form_for #product do |f| %>
Because f is already tied to product, you don't need to include it as your first argument, so it should just be:
<%= f.collection_select :category_id, Category.all, :id, :name %>
Or, you could not use f.:
<%= collection_select :product, :category_id, Category.all, :id, :name %>

Related

undefined method `collection_check_boxes'

I'm trying to make an invoicing app. The form to create an invoice should include a collection of check boxes so the user can choose which lessons to invoice, but I'm getting this error: undefined method 'collection_check_boxes'.
Here are the models involved:
class Lesson < ActiveRecord::Base
attr_accessible :lesson_time, :lesson_date, :invoice_id
belongs_to :invoice
end
class Invoice < ActiveRecord::Base
attr_accessible :amount, :due_date
has_many :lessons
end
And the view:
<%= form_for(#invoice) do |f| %>
<fieldset>
<%= f.label :lessons %>
<%= f.collection_check_boxes(:lessons, Lesson.all, :id, :lesson_date) %>
<%= f.submit %>
</fieldset>
<% end %>
collection_check_boxes is not a method of form_builder. Either put:
<%= collection_check_boxes(:lessons, Lesson.all, :id, :lesson_date) %>
This will generate html which won't associate with your model (you won't be able to use MyModel.new(params[my_model]) and expect to get proper response. You would either have to manually call my_model.lessons = params[:lessons] or you can pass a html name parameter to conform your check box name to rails convention).
Or, if you are using formtastic as you tagged it, you can use this:
<%= f.input :lessons, :as => :check_boxes, :collection => Lesson.all %>
I suspect that since you tagged your post ruby-on-rails-3, you might be trying to use a rails 4 method inside a rails 3 project.
http://makandracards.com/makandra/32147-rails-4-introduced-collection_check_boxes
You'll likely need to use good old check_box_tag instead.

Rails nested form with multiple entries

I have a Sezzion model:
attr_accessible :description
has_many :session_instructors, :dependent => :destroy
has_many :instructors, :through => :session_instructors
accepts_nested_attributes_for :session_instructors
accepts_nested_attributes_for :instructors
Instructor model:
attr_accessible :bio
has_many :sezzions, :through => :session_instructors
has_many :session_instructors, :dependent => :destroy
SessionInstructor model:
attr_accessible :instructor_id, :sezzion_id
belongs_to :sezzion
belongs_to :instructor
Lastly, User model:
has_many :sezzions
has_many :instructors
I'm trying to create a form for Sezzion with nested form for SessionInstructor which has multiple select option for Instructors.
How can I do the following:
nested form for SessionInstructor
use multiple select option to get all the selected Instructor's instructor_id
hidden field to pass in the created/updated session_id with each select instructor
I have the following code as of now:
<%= form_for(#sezzion) do |f| %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.label :instructors %>
<%= fields_for :session_instructors do |f| %>
<select multiple>
<% current_user.instructors.each do |instructor| %>
<option><%= instructor.name %></option>
<% end %>
</select>
<% end %>
<%= f.submit %>
<% end %>
Thank you so much!
This is something that seems ridiculously hard in Rails.
I think something like this might work:
<%= f.fields_for :session_instructors do |si| %>
<%= si.collection_select :instructor_ids, current_user.instructors, :id, :name, multiple: true>
<% end %>
This should create a form element which will set sezzion[session_instructors_attributes][instructor_ids].
Although I'm not sure if that's actually what you want. I've never tried this using a multi select. If it doesn't work, you could also try getting rid of the fields_for and just using f.collection_select. If you're willing to use a checkbox, I can show you how to do that for sure.
I hope that helps.
Edit:
Here's how I would usually do it with a check_box:
<%= f.fields_for :session_instructors do |si| %>
<%= si.hidden_field "instructor_ids[]" %>
<% current_user.instructors.each do |i| %>
<%= si.check_box "instructor_ids[]", i.id, i.sezzions.include?(#sezzion), id: "instructor_ids_#{i.id}" %>
<%= label_tag "instructor_ids_#{i.id}", i.name %>
<% end %>
<% end%>
There are a couple "gotchas!" with this method. When editing a model, if you deselect all checkboxes then it won't send the parameter at all. That's why the hidden_field is necessary. Also, you need to make sure each form element has a unique id field. Otherwise only the last entry is sent. That's why I manually set the value myself.
I copy pasted and then edited. Hopefully I got the syntax close enough where you can get it to work.
FINAL EDIT:
Per Sayanee's comment below, the answer was a bit simpler than I thought:
<%= f.collection_select :instructor_ids, current_user.instructors, :id, :name, {}, {:multiple => true} %>
#Sayanee, can you post how your instructors, sezzions table look like. Also for note, you can not get instructor_ids from Instructor object, hence you are getting "undefined method" error. With the current association that you shared, you can get instructor_ids from a Sezzion object. So you need to loop through current_user.sezzions in stead of current_user.instructors.
This is a way to implement fields_for nested form with html multiple_select in case of a has_many :through association. Solved it by doing something like this. The form view:
<%= form_for(#sezzion) do |f| %>
...
<%= fields_for :session_instructors do |g| %>
<%= g.label :instructor, "Instructees List (Ctrl+Click to select multiple)" %>:
<%= g.select(:instructor_id, Instructor.all.collect { |m| [m.name, m.id] }, {}, { :multiple => true, :size => 5 }) %>
<%= g.hidden_field :your_chosen_variable_id, value: your_chosen.id %>
<% end %>
...
<%= f.submit %>
<% end %>
Note:Since the #sezzion would not be saved at the time of generating the form you cannot pass that id (#sezzion.id) in place of your_chosen.id through the form. You could handle that save in the controller.
Make sure that your controller Initializes the Variables while generating the form: Your def new could look something like this:
def new
#sezzion = Sezzion.new
#sezzion.session_instructor.build
#sezzion.instructors.build
end
Now the create controller has to be able to accept the strong params required for the multiple select, so the sezzion_params method may look something like this:
def sezzion_params
params.require(:sezzion).permit(:description, :any_other_fields,
:session_instructors_attributes =>
[:instructor_id => [], :your_chosen_id => Integer])
end
In the create function, the first session_instructor variable is linked to the #sezzion instance variable through our new function. The other session_instructors in our multiple select must be built after the Sezzion instance is saved, if you want to pass in the created #sezzion.id with each select instructor. .
def create
#sezzion = Sezzion.new(sezzion_params)
#startcount=1 #The first element of the array passed back from the form with multiple select is blank
#sezzion.session_instructors.each do |m|
m.instructor_id = sezzion_params["session_instructors_attributes"]["0"]["instructor_id"][#startcount]
m.your_chosen_variable_id = your_chosen.id
#startcount +=1
end
if #sezzion.save
sezzion_params["session_instructors_attributes"]["0"]["instructor_id"].drop(#startcount).each do |m|
#sezzion.session_instructors.build(:instructor_id => sezzion_params["session_instructors_attributes"]["0"]["instructor_id"][#startcount],
:your_chosen_variable_id => your_chosen.id).save
#startcount += 1
end
flash[:success] = "Sezzion created!"
redirect_to root_url
else
flash[:danger] = "There were errors in your submission"
redirect_to new_sezzion_path
end
end

Formtastic nested form field not building has_one association?

Given a User who can possibly be an Artist:
class User < ActiveRecord::Base
has_one :artist
end
I've got a User & Artist nested form (using Formtastic gem):
<h1>Artist registration</h1>
<% #user.build_artist unless #user.artist %>
<%= semantic_form_for #user, :url => create_artist_path do |f| %>
<%= f.inputs :username %>
<%= f.semantic_fields_for :artist do |a| %>
<%= a.input :bio %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button 'Register as Artist' %>
<% end %>
<% end %>
The problem is the :artist fields are not rendered.
I've also tried f.inputs :for => :artist do |a|.
For some reason, using #user.build_artist does not display the artist's fields in the form. If I try #user.artist = Artist.new I get an error, because it tries to save the Artist and validation fails.
How should I initialize the Artist model so I get the benefit of formtastic generators in a nested form? (Note that #user here is not a :new_record?)
Did you remember to set accepts_nested_attributes_for :artist in user.rb?

Problem using nested_form gem when save data

It's my first time here, and first time I use nested_form gem. Everything seemed to be ok, but the data from my "parent" model doesn't save.
Here is my code
<%= nested_form_for #project do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :tasks %>
<p><%= f.link_to_add "Add a task", :tasks %></p>
<%= f.submit %>
<% end %>
so, when I "submit", just the tasks are saved ok, but not the project name.
Any clue for me? did I miss something??
You need to add the attribute. eg name to attr_accessible.
# app/models/project.rb
class Project < ActiveRecord::Base
has_many :tasks, :dependent => :destroy
accepts_nested_attributes_for :tasks, :allow_destroy => true
attr_accessible :name,:tasks_attributes ## <-- you need this line
end
Your fields_for declaration isn't quite right
<%= f.fields_for :tasks %>
Should be
<%= f.fields_for :tasks do |task_builder| %>
you are also missing an end for that declaration and a render to render the partial that has the nested fields for the associated object.
So you should end up with something like this
<%= f.fields_for :tasks do |task_builder| %>
<%= render 'task_fields', :f => task_builder %>
<% end %>
<p><%= f.link_to_add "Add a task", :tasks %></p>
That should do the trick. all you need to do now is create a _task_field.html.erb partial and add the task fields to it in the usual way using f.label, f.text_field etc...
p.s.
Your code could not possibly have ever worked. You would have had errors so something is probably missing from your opening post.

Difference between two f.select option

Hopefully this is just a quicky....
I have a form to edit a product and each product belongs to a category.
In the form_for(#product) I can populate a select box for the categories in a couple of ways:
<%= f.select :category_id, Category.find(:all).collect{|c| [c.category, c.id]}, :prompt => "Pick a Category" %>
or:
<%= f.select :category_id, options_from_collection_for_select(Category.find(:all), :id, :category) %>
The first option remembers the category when editing the product, the second option doesn't.
Can anybody enlighten me as to why? Is there a way to use the options_from_collection_for_select in this scenario and have it remember the category upon editing?
Cheers,
Adam
The Codeglot's answer should have been:
<%= f.collection_select :category_id, Category.all, :id , :name %>
(See Rails: undefined method `map' for Ingredient for explanation)
<%= f.collection_select :category_id, Category, :id , :name %>
make sure you change :name to the field that you want displayed. It's probably :name or :title
Try this:
<%= f.select :category_id, options_from_collection_for_select(Category.find(:all), :id, :category, params[:category_id].to_i) %>