Rails simple_form grouped collection not working - ruby-on-rails-3

In my Rails app, I'm using simple_form.
I'm trying to use grouped collection selects.
Without simple_form, this works:
<%= f.label :employee_id, "Lead3:" %>
<%= f.grouped_collection_select :employee_id, Workgroup.order(:id) , :employees, :group, :id, :employee_full_name %>
But, my simple_form attempt doesn't - the dropdown is empty:
<%= f.input :employee, collection: #workgroups, as: :grouped_select, group_method: :employees, :label => 'Lead2:' %>
OR
<%= f.association :employee, collection: #workgroups, as: :grouped_select, group_method: :employees, :label => 'Lead2:' %>

I would suggest to check your #workgroups definition in the controller. It probably returns nil or is not specified. Depending on what action calls your form, you should have something like this:
#workgroups = Workgroup.all(order: id)

Related

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

Rails 3 + Simple Form: Specifiy label class when using f.association

How can I specify the label class when using f.association instead of f.input in simple_form?
For example, this works:
f.input :name, :label_html => { :class => 'some-class' }
But this doesn't
f.association :periods, :as => :check_boxes, :label_html => { :class => 'some-class' }
Meaning that the label related to :name will have some-class as part of its class, but the label related to :periods won't. Any way to do this without changing f.association to f.input? Thank!
I think you can't add custom class to each label but you can do it for each item wrapper, e.g:
<%= simple_form_for(#user) do |f| %>
<%= f.association :group, as: :check_boxes, item_wrapper_class: 'custom-class' %>
<%= f.button :submit %>
<% end %>

Passing Rails Parameters into Form

I'm trying to pass in two variables for a Nested Model form to use, but I'm getting an error. It's probably an easy syntax error that someone experienced could see right away, but I don't see it.
I have a template showing users, if you click one, it should take the user_id and community _id for use in the form. Both community and user are properly declared in the controller.
link to form:
<%= link_to "award badge", award_badge_badges_path, :user_id => user.id, :community_id => #community.id %>
The form uses two models - badge and badge winners. The user_id and community_id are needed for badge_winners which is nested in badges. The error I'm getting is "undefined local variable or method 'user_id' for #<#<Class:0x77544c0>:0x7714230>" so I think that something is wrong with the 2nd and 3rd lines in the form. Here's the form:
<%= form_for(#badge) do |f| %>
<%= f.hidden_field :user_id ,:value => user_id %>
<%= f.hidden_field :community_id ,:value => community_id %>
<%= f.label :Description %>
<%= f.text_area :description %>
<%= f.fields_for :badge_winners do |builder| %>
<%= render "badge_winner", :f => builder, :locals => {:user_id => user_id, :community_id => community_id} %>
<% end %>
<%= f.submit "Give Badge" %>
<% end %>
the show template in the controller:
def award_badge
#badge = Badge.new
badge_winners = #badge.badge_winners.build
end
the badge winner partial
<%= f.hidden_field :user_id ,:value => user_id %>
<%= f.hidden_field :community_id ,:value => community_id %>

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?

In Rails 3, using Formtastic and Devise, generic routes producing errors when adding a new entry for a model

I have a very simple rails 3 program with 2 models: a user model for Devise and a writing model that captures a text field and the user's id.
My routes file is pretty basic:
devise_for :users
resources :users, :writings
root :to => "users#index"
And my form for writings, using Formtastic, is as well:
<% semantic_form_for(#writing, :html => {:method => :put}) do |f| %>
<%= f.input :main %>
<%= f.input :user_id, :collection => current_user, :as => :hidden %>
<%= f.buttons %>
<% end %>
When I try to create a new writing, the form looks great, but then when I hit submit, I get the following error:
No route matches "/writings"
I've run rake routes, and everything else seems to be working on, and I am using the default generate scaffold from rails, so the controller is the out of the box controller.
Any ideas on where I went astray?
Chris, try putting the declaration of the form like this
<% semantic_form_for #writing do |f| %>
<%= f.input :main %>
<%= f.input :user_id, :collection => current_user, :as => :hidden %>
<%= f.buttons %>
<% end %>
I've the idea that when you specify the :html parameter, you "override" some defaults in formtastic. Sorry, I'm not an expert on formtastic. I've used a bit and then decided to go for simple_form :).