Question

I am getting the following error:

Can't mass-assign protected attributes: Admin, Student

when I run rake db:seed command with the following seed.rb file:

roles = [
    Admin: 'Unlimited Access',
    Student: 'Default user role for each user created by sign-in interface.'
]

roles.each do |role, description|
  SecurityUsersRole.find_or_create_by_role_and_description(role,description)
end

where my model looks like:

class SecurityUsersRole < ActiveRecord::Base

  # Accessible columns
  attr_accessible :description,
                  :role

  # Relationships
  ...

  # Validations
  validates :description, presence: true, length: { in: 4..32 }, uniqueness: true
  validates :role, length: {  maximum: 256 }, presence: true

end

I have read a lot about this and it seems that for latest rails versions Mass Assignment if turn off in order to prevent hackers atack like this:

def signup
  params[:user] # => {:name => “ow3ned”, :admin => true}
  @user = User.new(params[:user])
end

There are a lot of SO questions about this and the answers is always to set attr_accessible to the fields, but I have already done this.

EDIT:

If I am using the following syntax( {} instead []) the first pair is added:

roles = {
    Admin: 'Unlimited Access',
    Student: 'Default user role for each user created by sign-in interface.'
}

Nothing changes if I am doing this:

SecurityUsersRole.find_or_create_by_role_and_description('Admin','Unlimited Access')
SecurityUsersRole.find_or_create_by_role_and_description('Student','Default user role for each user created by sign-in interface.')

After some reading it seems that the find_or_create_by helpers have been depreciated in Rails 4.0. I am using Rails 3.2 but decided to try other techniques too:

roles = {
    Admin: 'Unlimited Access',
    Student: 'Default user role for each user created by sign-in interface.',
    Test:'wtf'
}

roles.each do |role, description|
  SecurityUsersRole.where(role:role,description:description).first_or_create
  #puts role
  #puts description
end

The statement above is still creating only the first record. I have decided to executed the statement in the rails console and this is the output I am getting:

  SecurityUsersRole Load (5.0ms)  SELECT security_users_roles.* FROM security_users_roles WHERE security_users_roles.role = 'Admin' AND security_users_roles.description = 'Unlimited Access' FETCH FIRST ROW ONLY
  SecurityUsersRole Load (3.0ms)  SELECT security_users_roles.* FROM security_users_roles WHERE security_users_roles.role = 'Student' AND security_users_roles.description = 'Default user role for each user created by sign-in interface.' FETCH FIRST ROW ONLY
  SecurityUsersRole Exists (1.0ms)  SELECT 1 AS one FROM security_users_roles WHERE security_users_roles.description = 'Default user role for each user created by sign-in interface.' FETCH FIRST ROW ONLY
  SecurityUsersRole Load (1.0ms)  SELECT security_users_roles.* FROM security_users_roles WHERE security_users_roles.role = 'Test' AND security_users_roles.description = 'wtf' FETCH FIRST ROW ONLY
  SecurityUsersRole Exists (1.0ms)  SELECT 1 AS one FROM security_users_roles WHERE security_users_roles.description = 'wtf' FETCH FIRST ROW ONLY
=> {:Admin=>"Unlimited Access", :Student=>"Default user role for each user created by sign-in interface.", :Test=>"wtf"}

I am not able to understand what exactly is going on but selecting all users from the console returns me only the first one. So, if the other roles are searched for, why they are not created as they do not exist?

Can anyone advice what I can try?

Was it helpful?

Solution

The issue was caused by my model validations rules, where

  # Validations
  validates :description, presence: true, length: { in: 4..32 }, uniqueness: true
  validates :role, length: {  maximum: 256 }, presence: true

should be

  # Validations
  validates :role, presence: true, length: { in: 4..32 }, uniqueness: true
  validates :description, length: {  maximum: 256 }, presence: true

I have changed the places of the :role and :description fields. So, the rake db:seed command inserts the first records, but a error appears on the second one and the insertion is aborted. The result is that I have always have the first record imported.

In order to get validations errors when you are using seeds you should use the !method versions like this:

SecurityUsersRole.where(role:role,description:description).first_or_create!
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top