Reputation: 11799
I'm trying to create user roles for my user using a form,
<%= form_for @user do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :username %><br />
<%= f.text_field :username %>
</p>
<p>
<%= f.label :email, "Email Address" %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %><br />
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation, "Confirm Password" %><br />
<%= f.password_field :password_confirmation %>
</p>
<% # f.select :roles, Role.all.map {|r| [r.title]} %>
<% Role.all.each do |role| %>
<div>
<%= check_box_tag :role_ids, role.id, @user.roles.include?(role), :name => 'user[role_ids][]' -%>
<%= label_tag :role_ids, role.title -%>
</div>
<% end -%>
<p><%= f.submit (@user.new_record? ? "Sign up" : "Update"), :id => :sign_up %></p>
<% end %>
This is the association that I have in my model
class user < ActiveRecord::Base
has_many :assignments
has_many :roles, :through => :assignments
end
class assignment < ActiveRecord::Base
belongs_to :user
belongs_to :role
end
class role < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments
end
What's the way to create the assignment between the user and the role by using the form that I presented in the beginning ?
My create action in my user controller looks like:
def create
@user = User.new(params[:user])
if @user.save
session[:user_id] = @user.id
render :action => 'dashboard'
else
render :action => 'new'
end
end
When I send my form I get the error:
ActiveRecord::AssociationTypeMismatch in UsersController#create
Role(#70331681817580) expected, got String(#70331650003400)
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"WHpOW+DmymZ2pWmY9NHSuodf2vjyKdgMNZcc8NvCNa0=",
"user"=>{"username"=>"ioio",
"email"=>"[email protected]",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]",
"roles"=>["2"]}, #### <<< ==== This is the checkbox that I selected for this request.
"commit"=>"Sign up"}
Any help is welcome.
Upvotes: 2
Views: 1914
Reputation: 4499
Using your current form and based on:
<%= check_box_tag :role_ids, role.id, @user.roles.include?(role), :name => 'user[role_ids][]' -%>
On submit, your params should look like (note 'role_ids' and not 'roles'):
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"WHpOW+DmymZ2pWmY9NHSuodf2vjyKdgMNZcc8NvCNa0=",
"user"=>{"username"=>"ioio",
"email"=>"[email protected]",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]",
"role_ids"=>["2"]}, #### <<< ==== This is the checkbox that I selected for this request.
"commit"=>"Sign up"}
if this is the case, you will have to instance your roles and set them for the user in the controller:
def create
@user = User.new(params[:user])
roles = Role.find(params[:user][:role_ids]) rescue []
@user.roles = roles
if @user.save
session[:user_id] = @user.id
render :action => 'dashboard'
else
render :action => 'new'
end
end
...and similarly:
def update
@user = User.where(:username=>params[:id]).first
roles = Role.find(params[:user][:role_ids]) rescue []
@user.roles = roles
if @user.update_attributes(params[:user])
redirect_to users_url, :notice => "Successfully updated user."
else
render :action => 'edit'
end
end
Upvotes: 4
Reputation: 11198
The error message gives you the hint: To be able to save the user object you first need to create the associated Role objects somehow. At the moment you only have an array of strings that are Role ids.
You need to use the accepts_nested_attributes_for method on the user model.
Upvotes: 0