Rails 4 strong parameters failing when creating instances in rails console
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.
Why am I getting strong parameter errors in the Rails Console in rails 5?
What's Happening and Why
ActionController::Parameters
(which is what params
works with in controllers) used to inherit from HashWithIndifferentAccess
which inherits from Hash
. So ActionController::Parameters < Hash
used to be true as would something like:
params.require(:x).permit(some_hash: %i[key1 key2]).is_a? Hash
If you were digging a Hash
out of params
:
some_hash = params.require(:x).permit(some_hash: ...)
and serializing that in a model:
class M < ApplicationRecord # Or ActiveRecord::Base in the past
serialize :h, Hash
end
#...
m.h = some_hash
you could end up with some YAML like this in your database:
--- !ruby/object:ActionController::Parameters
...
rather than the expected plain YAMLized hash.
But then Rails5 comes along and ActionController::Parameters
no longer inherits from Hash
:
- Make
ActionController::Parameters
no longer inherits fromHashWithIndifferentAccess
.
and calling to_h
or to_hash
on an ActionController::Parameters
now raises an exception.
If you upgrade your code and try to load a model with serialized data in it:
serialize :h, Hash
then the model will load the text from h
, parse the YAML to get an ActionController::Parameters
instance, and call to_h
on it to make sure it has a Hash, and you get an exception.
What To Do About It
There are a couple things you need to do:
- Fix your controllers to make sure they get real hashes out of
params
. - Fix your data so that you have serialized hashes rather than
ActionController::Parameters
instances.
Fixing the controllers is a simple matter of calling to_unsafe_h
on the parameters that aren't yet real hashes.
Fixing the data is uglier. I'd probably go through the tables using the low level database interface (i.e. no ActiveRecord anywhere), read the YAML out from each row, YAML.load
it, convert it to a hash by calling to_unsafe_h
on it, and then writing back the_real_hash.to_yaml
text. You could use a like '--- !ruby/object:ActionController::Parameters%'
filter in the WHERE clause to only deal with the broken rows.
I'd also strongly recommend that you stop using serialize
while you're there. serialize
is a bit of a kludge and there's no sane way to work with YAML inside the database; there's also little need for it now that both PostgreSQL and MySQL have native JSON support (but I'm not sure how well ActiveRecord supports MySQL's JSON).
Rails 4 strong parameters: check whether a param is in the whitelist, without actually updating it
I'd define the list of params that you're permitting in a constant and then check that. Here's a similar SO post that does this.
In short:
# In your model object (e.g. MyModel)
PERMITTED_FIELDS = %w(field1 field2 field3)
# In your controller
def my_object_params
params.require(:user).permit(MyModel::PERMITTED_FIELDS)
end
Then you can access MyModel::PERMITTED_FIELDS
as needed elsewhere.
Rails 4 strong params - Undefined method name on model
You still do need the attr_accessor
defining which attributes your model has.
There's also a ActiveModel::Model
module you can include rather than including separate modules:
class Message
include ActiveModel::Model
attr_accessor :name, :email, :body
validates :name, :email, :body, :presence => true
def persisted?
false
end
end
See the ActiveModel documentation for more information.
Rails 5.0.0.1: can not create a class instance from the console?
Rails 5 requires belongs_to
associations by default since this PR.
You can specify that the field is optional by using belongs_to :user, optional: true
.
Also, if your model fails to save, it's often helpful to take a look at its errors
object.
You can do this by doing something like puts car.errors
.
Strong parameters won't affect anything you do in the console. The whole point of them was to move mass-assignment protection out of models and into controllers.
Rails 4: using both strong params and normal params
You should always use Strong Parameters.
Strong params was created to avoid the issue of Mass Assignment.
This means that if you directly use your params
hash, you run into the risk of someone sending a request with parameters they aren't supposed to use and successfully overwrite them in your models.
This means that, for example, someone could gain admin privileges on your site from their "settings" page by maliciously crafting a request that modifies a hypothetical admin
attributes in your User
model.
Using strong params gives you the guarantee that only the parameters explicitly allowed by you will pass through to the model, so no attacker should be able to bend your application's restrictions.
How to get a list of permitted params for a specific controller action
You basically can't do that due to the nature of strong parameters.
What you define in some_resource_attributes
is meant to filter parameters hash of the request. If you look at the method definition, you will see params.require(:some_resource).permit..
- it operates on the params
object, which is only present during a request.
So having such method seems to be of very little use.
If you really want to programatically access your whitelisted attributes in the some_resource_attributes
, you can go with:
class ResourceController < ApplicationController
LIST = %i(foo bar baz)
private
def resource_attributes
params.require(:resource).permit(*LIST)
end
end
ResourceController::LIST
#=> [:foo, :bar, :baz]
But I dot see a point in this since you can just open controller's code and check it.
Related Topics
Ruby Time Object Converted from Float Doesn't Equal to Orignial Time Object
Ruby: Merge Two Hash as One and with Value Connected
Capistrano 3 + Sprockets 3 + Rails 4.2.1 Won't Deploy
Ruby Gem Listed, But Won't Load (Gem in User Dir, Not Ruby Dir)
How to Enable Ssl for a Standalone Sinatra App
What's the Difference Between "=" & "=>" and "@Variable", "@@Variable" and ":Variable" in Ruby
Ruby: How to Send a JSON Post Request Using Curb
How to Get the File Extension from a Url
Whenever Gem: I Set :Output But the Logfile Doesn't Show Up Where I'D Expect It To
Trouble on Rendering a Template Passing a Local Variable
How to Store Enum as String to Database in Rails
Difference Between String.Scan and String.Split
Ruby Imap Idle Concurrency - How to Tackle
Heroku Rejecting Push in Mature Application (Pre-Receive Hook Declined)