Search code examples
ruby-on-railsstrong-parameters

how to allow all of the attributes of a model when


I am migrating a Rails 3.2 app to strong_parameters and don't have much experience.

I have a model called Item which has_many attributes. In our item#update I'd like to be able to do like the following:

# Model
class Item < ActiveRecord::Base
  include ActiveModel::ForbiddenAttributesProtection
  has_many :assets, :as => :assetable, :dependent => :destroy
...

#in items_controller.rb

def update
  @item=Item.find(params[:id])
  if @item.update_attributes(params[:item])

...
private

def item_params
  params.require(:item).permit(:assets_attributes).permit!
end

How would I specify the item_params to allow an asset to be created through this update statement?

edit 1

so if I pull a list of attributes via:

a=Asset.first
a.attributes

I get:

{"id"=>4424,
 "name"=>nil,
 "created_at"=>Fri, 24 Jan 2014 15:49:17 PST -08:00,
 "updated_at"=>Fri, 24 Jan 2014 15:49:17 PST -08:00,
 "asset_file_name"=>"br-3.jpg",
 "asset_content_type"=>"image/jpeg",
 "asset_file_size"=>198085,
 "asset_updated_at"=>Fri, 24 Jan 2014 15:49:16 PST -08:00,
 "menu_item_id"=>nil,
 "assetable_id"=>1,
 "assetable_type"=>"LocationProfileAlbum",
 "global_id"=>9394,
 "description"=>nil,
 "associated_global_id"=>9393,
 "user_id"=>nil,
 "position"=>0.0,
 "hash_val"=>nil,
 "is_instore"=>false,
 "location_id"=>nil,
 "filepicker_url"=>nil}

if I then put it in:

  def item_params
    params.require(:item).permit(
        :assets_attributes[
            :id, :name, :created_at, :updated_at , :asset_file_name, :asset_content_type, :asset_file_size, :asset_updated_at, :menu_item_id, :assetable_id, :assetable_type, :global_id, :description, :associated_global_id, :user_id, :position, :hash_val, :is_instore, :location_id, :filepicker_url
        ]
    )

and then add a file, I get the error:

ArgumentError (wrong number of arguments (20 for 1..2)):
  app/controllers/items_controller.rb:218:in `[]'
  app/controllers/items_controller.rb:218:in `item_params'

Solution

  • First, you need to specify which attributes for the nested assets are allowed, e.g.:

    def item_params
      params.require(:item).permit(assets_attributes: [:col1, :col2, :col3])
    end
    

    Then, make sure you use this private method when updating @item:

    @item.update_attributes item_params
    

    ETA (based on your edit1): paperclip POSTs the actual file, not its attributes, so you would:

    params.require(:item).permit(assets_attributes: [:asset])
    

    For future reference you can find the parameters being passed to an action in the logs. It would look something like:

      Parameters: {"utf8"=>"✓", "item"=>{"assets_attributes"=>[{"asset"=>#<ActionDispatch::Http::UploadedFile…>}]}
    

    The logs will also include notice that any parameters have been excluded by strong params. This can be very helpful for determining which parameters need to be permitted.

    I also want to strongly discourage adding all parameters to the permitted list. Strong parameters is motivated by serious security concerns, namely attackers being able to edit fields that they should not have access to. Basically, keep in mind that anyone with access to the web page will be able to post any value for any parameter in the permitted list.