Controlling attribute mass assignment in the controller

Rails nicely lets me do this in a controller:

     @user = User.new(params[:user])

and provides the attr_protected (and attr_accessible) model methods to hide attributes from this sort of the mass assignment.

Problem is, I quite often want to control which attributes are assigned on a per-action basis, which leaves me doing things like:

     @user = User.new
     @user.name = params[:user][:name]
     @user.address = params[:user][:address]

Not very DRY. The alternative that I've been using recently is this:

     @user = User.new(params[:user].only(:name, :address))

where the "only" method is defined as:

     class Hash
       def only(*keys)
         keys.map!(&:to_s)
         Hash[*self.select {|key, value| keys.include?(key) }.flatten]
       end
     end

Do you think this is a nice way to do it? Got suggestions for alternatives or improvements?

Regards,

Pete Yandell
http://notahat.com/

Pete :

Not very DRY. The alternative that I've been using recently is this:

     @user = User.new(params[:user].only(:name, :address))

where the "only" method is defined as:

     class Hash
       def only(*keys)
         keys.map!(&:to_s)
         Hash[*self.select {|key, value| keys.include?(key) }.flatten]
       end
     end

Do you think this is a nice way to do it? Got suggestions for
alternatives or improvements?

Have a look at ActiveSupport's Hash#slice in Edge :

http://dev.rubyonrails.org/browser/trunk/activesupport/lib/active_support/core_ext/hash/slice.rb

Hash#assert_valid_keys as a guard can also be useful.

   -- Jean-François.