Specifically, I have a form for creating a User. One of the fields is Group, which is a separate model. During the User#create action I call Group.find_or_create_by_name to check and see if the Group already exists by pulling out params[:user][:group], and create the Group if it doesn’t exist.
But, when I create the User, I can’t pass params[:user], because params[:user][:group] is not a group, it’s a String. This would be a lot easier if I could supply params[:user] and params[:group] to my controller, instead of everything bundled under a single variable, but I don’t know how to do that.
Relevant code:
User#create
@group = Group.find_or_create_by_name(params[:user][:group])
@group.save!
@user = @group.users.build(params[:user])
Partial User Schema
create_table "users", :force => true do |t|
t.string "name", :default => "", :null => false
t.string "email", :null => false
t.integer "group_id"
Partial Group Schema
create_table "groups", :force => true do |t|
t.string "name"
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
Params Dump from form submission
{"commit"=>"Register",
"authenticity_token"=>"x1KgPdpJop5H2NldsPtk0+mBDtrmpM/oNABOxjpabIU=",
"utf8"=>"✓",
"user"=>{"name"=>"aName",
"group"=>"aGroupName",
"password_confirmation"=>"[FILTERED]",
"password"=>"[FILTERED]",
"email"=>"anEmail"}}
The best explanation I’ve run across is this question.
I don’t really want to start rearranging the params has inside of my controller as that really makes me queasy, and seems like terrible programming. Which really makes me question whether I’ve got a bigger problem.
If it goes against Rails conventions to do this, what then is the best way to do it, and why should I not?
So, I’m going to spell out everything I’ve learned, in case other people are having trouble understanding this like I did. Also, if I get anything wrong here, please correct me.
If you’re using a form that creates multiple model instances at once (preferably associated ones), you first need to use the helper
accepts_nested_attributes_forin your model definition (probably right underneath your declared associations). The reason for this is it creates a setter method that knows how to write that type of associated model. (Note: you can also define this method yourself in your main model). Once you’ve done that you can nest afields_forinside of aform_for, and Rails will know how to make the proper assignments.I initially thought that
accepts_nested_attributes_forwas referring to nested resources, which is definitely not the case. If you’re looking for more information, refer to section 11.8.3 (pp 343-347) of The Rails 3 Way.