views:

1838

answers:

6

I have a User model and a Role model. They are joined by a has_and_belongs_to_many relationship. When an admin creates a user I want them to be able to assign a role to the user and have it saved when I call @user.save

The thing is though is that I get a warning that I can't mass-assign the roles relationship.

Any suggestions on how to go about this, I am on Rails 2.3.2

Thanks.

Edit: Code as requested.

user.rb

class User < ActiveRecord::Base
  has_and_belongs_to_many :roles,
                          :join_table => "users_roles",
                          :foreign_key => "role_id",
                          :associated_foreign_key => "user_id"
end

role.rb

class Role < ActiveRecord::Base
  has_and_belongs_to_many :users,
                          :join_table => "users_roles", 
                          :foreign_key => "user_id", 
                          :association_foreign_key => "role_id"
end

View: new.html.haml

- form_for(@user, users_path(:subdomain => current_account.subdomain)) do |f|
  .input_set
    = f.label(:login, "Username")
    = f.text_field(:login)
  .input_set
    = f.label(:name)
    = f.text_field(:name)
  .input_set
    = f.label(:email)
    = f.text_field(:email)
    - fields_for("user[roles][]", Role)do |user_role|
      .input_set
        %label Role
        = user_role.select(:name, Role.all.map{|r| [r.name, r.id] })
  .input_set
    = f.label(:password)
    = f.password_field(:password)
  .input_set
    = f.label(:password_confirmation, "Password Again")
    = f.password_field(:password_confirmation)
  .input_set
    %label
    = f.submit "Add User"

And I want the Role to be saved to the user by calling @user.save in my create option. Is that possible? Or is this a relationship I can't use that way, would it need to a has_many relationship for me to be able to do this.

A: 

Are you using the new accepts_nested_attributes_for method?

It will probably look something like this:

class User < ActiveRecord::Base 
  accepts_nested_attributes_for :roles, :allow_destroy => true
end

Check out this sample app for more detail.

chap
No that doesn't work, I still get can't mass-assign warning/error.
railsninja
+1  A: 

I believe you need to call attr_accessible on the attributes in the model that you want to save in order to avoid the mass-assign error.

insane.dreamer
A: 

I believe :autosave is what you are looking for:

has_and_belongs_to_many :roles,
                      :autosave => true,
                      :join_table => "users_roles",
                      :foreign_key => "role_id",
                      :associated_foreign_key => "user_id"

Haven't tested it though.

Redbeard
A: 

You cannot use accepts_nested_attributes_for for a habtm relationship.

You can however set the role_ids, see Railscast Episode 17 for details

In your case the problem is that you set only a single role but have a habtm relationship, why not a belongs_to?

nasmorn
A: 

Given the time since the question was asked, you've probably worked this out on your own...

The thing is though is that I get a warning that I can't mass-assign the roles relationship.

This is caused by one of two things in your User model.

  1. You called attr_accessible and the list of symbols provide does not include :roles
  2. You called attr_protected and the list of symbols includes :roles

Either add :roles to your attr_accessible call or remove it from the attr_protected call.

EmFi
A: 

If I could edit/add to an answer I would. I had something similar required to what @EmFi mentioned. I had attr_accessible set, and had to add the equivalent of

:role_ids

to the attr_accessible of the user model. Note the pluralization. The following options did not work:

  • :role
  • :roles
  • :role_id

Just to be clear about the error message that I got:

WARNING: Can't mass-assign these protected attributes: role_ids

The warning didn't make a lot of sense to me since I'm using a habtm relationship. Nevertheless, it was correct.

dpb