My features
file looks at this:
Given there are the following users:
| email | password | admin |
| admin@ticketee.com | password | true |
And my user
model doesn't declare the admin attribute as attr_accessible
to prevent mass assignment. Accordingly, I've made changes to the user_steps.rb
file to tackle this.
Given /^there are the following users:$/ do |table|
table.hashes.each do |attributes|
unconfirmed = attributes.delete("unconfirmed") == "true"
@user = User.create!(attributes)
@user.update_attribute("admin", attributes["admin"] == "true")
@user.confirm! unless unconfirmed
end
end
Now this is supposed to work according to the book - Rails3 in action. I checked the code on their online repo as well. Running this with cucumber gives the following error:
Can't mass-assign protected attributes: admin (ActiveModel::MassAssignmentSecurity::Error)
./features/step_definitions/user_steps.rb:4:in `block (2 levels) in <top (required)>'
./features/step_definitions/user_steps.rb:2:in `each'
./features/step_definitions/user_steps.rb:2:in `/^there are the following users:$/'
features/creating_projects.feature:7:in `Given there are the following users:'
Any help would be greatly appreciated. I really cant figure what's wrong here.
Thanks a lot!
I think the most easy way to do this is:
This way you'll delete the admin attribute from the attributes so you can create the new user; without the mass-assign attributes error. But for the "test" purpose we keep the admin variable to assign the user.admin attribute if the admin was true. The thing here is that you won't make the admin accessible on the User model to protect your site from a hack, but we're doing this to pass our test only. On your website you have to implement a secure way to update the user after it was created.
Assuming this is based on "Rails 3 in Action", the sample code actually has the same problem. From the log:
However, in the config/environments/development.rb file, the mass_assignment_sanitizer is not set. By default a new rails 3.2 project will set this. If it is commented out, the code will execute. The default setting is:
The sample code then sets the attribute using a private method set_admin. Is this a good coding practice? I'm not sure but it works.
It's a great book, by the way.
In the user model add:
Update:
The
admin
attribute can be mass assigned and any hacker can set it easily by sending it with the parameters.I got this to work by changing the step definition:
Why not just use
@user.admin = attributes["admin"] == "true"
?You will need to get rid of the admin value from the attributes hash - so the full code would be
I changed User.create! to User.new + @user.save because you are setting an attribute but not saving the model after. If @user.confirm! saves the model you won't see any errors, but it's not good practice to rely on side effects from other methods like that. Better to be explicit.