#371 Strong Parameters pro
The strong_parameters gem is an improvement over attr_accessible to securely handle mass assignment even when you have complex authorization logic. The functionality will likely be added to Rails 4 so it is a good idea to learn how it works.
- Download:
- source code
- mp4
- m4v
- webm
- ogv
I enjoyed this episode very much. I especially liked the idea of using a PermittedParameters class.
I'm not sure I like filtering the view using PermittedParameters. I can't say exactly what I don't like about it. I feel that is a job for cancan, or other authorization gem.
I was wondering about that too. Is this supposed to be a replacement or alternative to using CanCan?
Cancan works on a more coarse level than this. It grants/denies access to entire actions and also loads instance variables. So this can be used in addition, it doesn't replace CanCan.
+1
CanCan seems to have a big flaw by not handling mass assignment: https://github.com/ryanb/cancan/issues/571
There is this very interesting Gem that is basically around 100 lines of code using Strong Parameters: https://github.com/colinyoung/cancan_strong_parameters
Thanks Ryan for that Railscast !
I also get troubles trying to make it work with cancan.
hackeron, did you manage to use the cancan_strong_parameters gem ?
I miss an enhanced doc on it ( You see what I mean ;-) )
Would be cool to abstract the PermittedParams class even more, so that it's methods are not tied to one model only. It might be even cool to have a CanCan like gem for attributes to more easily specify permissions - or combine this with CanCan. ;-)
What would be sweeter than cancan getting down with strong_parameters under the covers?
I am asking myself if I should remove CanCan from my Gemfile, use strong_parameters and implement everything else, CanCan did for me (like loading and authorizing the resources), from scratch.
What do you think?
Yes, it looks like CanCan can be implemented in around 100 lines of code when using Strong Parameters! < https://github.com/colinyoung/cancan_strong_parameters
Where is the require method defined on the params hash? It seems like a useful method, but I couldn't find it in the rails API or the ruby hash documentation.
It's actually defined in Strong Parameters:
https://github.com/rails/strong_parameters/blob/master/lib/action_controller/parameters.rb#L29
great RailsCast!
Having to write a private method for every model where parameters are modified, and to hard-code the roles in there, seems to be very cumbersome and well, hard-coded. I like how you extracted this into a class.
I wish there was a tight integration with
declarative_authorization
, where the roles and permissions live in a separate configuration file and can be more easily changed in one location.I find this solution pretty interesting. I also wrote a gem which handles attr_accessible to be more comfortable.
https://github.com/parcydo/alfred
looks great! it's nice how this is still in the models, but uses the roles which are maintained somewhere else.
thanks.. it work's really nice for me, I think it can compare wit strong_parameters
it only supports ActiveRecord for now but I'm also writing on a MongoID adapter
a uniform interface for ActiveRecord and Mongoid would be awesome!
According to a pull request, it looks like 4.0 will accept arrays in permit() params as hash values too, therefore in the example, you can write this:
Hi Rian,
great railscast as usual. One note though.
In your cast you're caching the PermittedParams, which doesn't seem to be a good idea, since you're passing the params as an argument.
In development this will work, but in production you will end up with the PermittedParams holding the params from the very first request. Of course this applies to the user as well.
Maybe I'm missing something, so I'm glad to hear your opinion.
This shouldn't be a problem since a new instance of the controller is generated for every request.
To anyone proposing solutions for improving access controls, (or doing updated rairscasts)
please include a simple DRY way for seeds.rb and test fixtures/factories to operate with minimal interference. For example, my customer requires several read-only lookup tables in the database . Even though they are read-only in steady state, i'm forced to list each column name with attr_accessible in each model, just to have a simple seeds.rb file. Would be helpful to have a way to turn off all the controls in special cases like that, without having to list each attribute name for each model.
You don't have to. If you're not using strong_parameters, just use
:without_protection => true
. See the last example at http://api.rubyonrails.org/classes/ActiveRecord/AttributeAssignment.html#method-i-assign_attributeshas anyone come across conflict with object based authorization and strong-parameters?
I use declarative-auth, I believe cancan also does this, where they will load the object before getting to the :create action. The problem is, I get the ActiveModel::ForbiddenAttributes when submitting to create - since the auth layer is doing the SomeObject.new call without the "permitted_params.some_object".
I suppose monkey-patching the gem is best idea.
I think I may be having the same problem. However, I'm not sure, because when I use:
it works just fine. But, when I use:
it gives the ActiveModel::ForbiddenAttributes exception.
I monkey patched it as stated above... there may be a better solution but on the controller i threw a public method call new_#{controller.to_s.singularize}_from_params. There may be a better way to do this than on each controller but my code for a topic would look like this
Then just do all your normal stuff in the create method. This method should pass it along. Hope it helps someone!
I just found a issue in version 0.2.0 where it only permits attributes that belong to your model any additional fields are ignored. If any body else is facing this issue you can downgrade the gem by doing
and then running bundle
If you use this with more than 1 model here is an example of how you could refactor your PermittedParams class to allow more flexibility:
Sorry for sounding obtuse, but does that solve the issue with nested properties?
No, Pierre's code simply saves you from having to define a method called topic, and a different one called user, with mostly the same implementation.
Is it just me or is having a topic_attributes method on every class a terrible thing to do? It means you will have references to other classes, particularly global things like current_user, which should never be accessed inside your model, inside every single model you have.
I can see the code quickly devolving into spaghetti with references to relations and methods of current_user. It's adding inter-model dependencies for no reason, and moving a lot of the logic back into the model that strong parameters was designed specifically to avoid.
You don't have a topic_attributes method on every class. You have only one shared method in all controllers and views, called permitted_params. The object returned by that method has methods like topic_attributes inside of it.
Keep in mind that in controllers there is already a shared method called params. I think this solution is very much inline with rails' way of doing things (which you might or might not like).
If you are using MongoID, than do this in your initializer:
Mongoid::Document.send(:include, ActiveModel::ForbiddenAttributesProtection)
Great episode, actually haven't seen it until it was referenced in episode #415.
However, if rails 4's default behavior will now rely on strong parameters instead of attr_accessible, I suppose this episode will become pretty essential rails 4 users. Will you be making this episode public, or will it remain a pro episode?
I am trying to use Strong_parameters with Ajax & I get the following
Unpermitted parameters: utf8, if I do not include it in the permitted or
ActiveRecord::UnknownAttributeError (unknown attribute: authenticity_token): if I do
Is this me or a Work in progress I can make it work for a html form.
puts "<%= simple_form_for(@venue, remote: true ) do |f| %>"
my mistake the log says "Unpermitted parameters: utf8, authenticity_token, venue, commit" but I had an error in my code which compounded things
What was the error in your code?
AT 10:48 when you change the sticky of a topic to NOT be sticky, it doesn't change the status from sticky to non.
It actually does, but since it becomes unstickied it moves down the list.
hell let loose
hell let loose game
all hell let loose
hell let loose gameplay
hell let loose kickstarter
max hastings all hell let loose review
all hell let loose book review
all hell let loose max hastings reviews
hell let loose release date
let hell loose
hell let loose game release date