Probably doing something stupid here, but here's my basic cookie cutter class:
class League < ActiveRecord::Base
private
def league_params
params.require(:full_name).permit!
end
end
And when creating a new instance of League:
2.0.0-p0 :001 > l = League.new(full_name: 'foo', short_name: 'bar')
WARNING: Can't mass-assign protected attributes for League: full_name, short_name
What exactly am I doing wrong here? This is a Rails 4.0.0.beta1 build + Ruby 2.0
** UPDATE **
I realize now that strong parameters are enforced in the Controller now and not in the model. The original question still stands. If they are permitted on the controller level, how can I properly whitelist attributes if I'm creating instances in the Rails console? Wouldn't I need to also use attr_accessible
in this case also thereby completely duplicating what strong parameters is trying to "fix"?
Two things. The league_params
definition goes in the controller, not the model. And params.require()
should contain the name of the model that is required to be present in the parameters, not the attributes. The attribute presence check should still be in the model validations. And be sure you really want to allow access to all attributes in the League model before you use permit!
. So, it should look like this:
class LeaguesController < ApplicationController
private
def league_params
params.require(:league).permit!
end
end
Update:
Yes, if you want the attributes to be restricted when accessing the model directly, you would need to switch back to using the attr_accessible
in the model. That functionality has been moved into this gem: https://github.com/rails/protected_attributes.
I think it is assumed that if you are working with the model directly in the console, you don't need the attributes to be protected as you know exactly what is being entered. As the console has full access to your app, it would be just as easy to hose the entire database as it would be to maliciously assign an attribute.
The basic security reason for the existence of both strong parameters and attr_accessible is that there are certain attributes in the model that should not be allow to be changed unless it is the explicit intention of your code.
The slight difference between them is the perspective form which they do their jobs.
StrongParameters focus on the use case: each controller's action can be fine tuned to allow or disallow certain parameters, taking in consideration any condition. Total flexibility.
attr_accessible takes a different perspective. Instead of focusing on the use case, it focus on roles. So for example, depending on the role of the user certain attributes can be changed or not.
The way to use StrongParameters is to apply the require
and permit
keywords on the param hash.
require
states that a key must be present on the params hash. require
will raise an exception if there is not such a key.
permit
states that a field is allowed. Any key that is not allowed will be removed from the hash and hence will not be passed to the model by means of mass-assignment.
Model
class League
attr_protected :final_price # Nobody can mass-assign the final price
attr_accessible :winner_name, :as => :jury
end
And the controller
class LeaguesController < ApplicationController
These two actions use StrongParameters
# A common user can create a league
def create
league = League.new(league_params)
league.final_price = 1000
league.save
redirect_to(league)
end
# But only the admin can publish a league
def publish_league
league = League.find(params[:id]
league.update_attributes(league_params_as_admin)
end
This one uses attr_accessible
def publish_the_winner
league = League.find(params[:id]
# We would expect the current_user.role to return :jury.
league.assign_attributes(params[:league], :as => current_user.role)
end
private
def league_params
params.require(:league).permit(:name)
end
def league_params_as_admin
params.require(:league).permit(:name, :status)
end
end
In my experience:
Use the flexibility of Strong Parameters to fine tune what attributes can be mass-assigned in each of your controllers.
Use the omnipresence of attr_accesible to make sure that certain attributes can not be mass-assigned no matter what. For example, in a Resque Task you may pass user input as a parameter. You would check that some attributes are not mass-assigned using attr_accesible.
More info:
http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html
https://github.com/rails/strong_parameters
It seems the whitelisting is active, even though you are running Rails 4. Did you upgrade to Rails 4 from a Rails 3 app? Do you have this in your config/application.rb
?
config.active_record.whitelist_attributes = true
Double-check that strong parameters are in force on all your models. If they are, you can change this setting to false
.
Also, double-check that there is no attr_accessible
in your model.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With