Rails 4 Strong Parameters Failing When Creating Instances in Rails Console

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 from HashWithIndifferentAccess.

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:

  1. Fix your controllers to make sure they get real hashes out of params.
  2. 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



Leave a reply



Submit