Doug Kandl
Doug Kandl

Reputation: 11

mass-assignment issues in Rails 4

I keep getting the following error even and unable to correct it can someone please help.

ActiveModel::MassAssignmentSecurity::Error in HomePageController#add_to_cart Can't mass-assign protected attributes for CartItem: customer_id, product_id, quantity_ordered

Extracted source (around line #7):

def add_product(id, product_id, quantity_ordered) cart_item =CartItem.new( :customer_id => id, :product_id => product_id, :quantity_ordered => quantity_ordered)

class Customer < ActiveRecord::Base
  has_many  :cart_items,  :dependent=> :destroy
  attr_accessible :customer_id, :product_id, :quantity_ordered


  def add_product(id, product_id, quantity_ordered)
    cart_item =CartItem.new(
      :customer_id => id, 
      :product_id => product_id, 
      :quantity_ordered => quantity_ordered)
    cart_items  <<  cart_item     #appends a value
    cart_item             #returns a value
 end

  def total_price
    cart_items.to_a.sum { |item| item.sub_total }
  end
end

Upvotes: 1

Views: 81

Answers (5)

Малъ Скрылевъ
Малъ Скрылевъ

Reputation: 16507

It is strangely why do you get the ActiveModel::MassAssignmentSecurity::Error exception. Although, the mass assignment is a probable vulnerability of you site, it is need to be fixed with a few steps:

  1. Replace declaration of all ids in a model from attr_accessible to attr_protected operator:

    attr_protected :customer_id, :product_id

  2. Do not pass id fields into the constructor of the model, which can be new, 'create', etc:

    cart_item = CartItem.new quantity_ordered: quantity_ordered

  3. Possibly, do not assign ids fields directly, use idless assignments instead:

    cart_item.customer = customer cart_item.product = product

  4. Also, you shell specify customer_id, product_id fields for CartItem model, not for the Customer.

As result we get the following code for the CartItem model:

class CartItem < ActiveRecord::Base
  attr_protected :customer_id, :product_id, :quantity_ordered
end

And for the Customer model:

class Customer < ActiveRecord::Base
  has_many :cart_items, :dependent => :destroy

  def add_product customer, product, quantity_ordered
    cart_item = CartItem.new quantity_ordered: quantity_ordered
    cart_item.customer = customer
    cart_item.product = product
    cart_item.save!
    cart_items << cart_item     #appends the value
    cart_item                   #returns the value
  end

  def total_price
    cart_items.to_a.sum { |item| item.sub_total }
  end
end

Additionally, please check out more accurately about mass-assignment vulnerability here and here.

Upvotes: 0

Gjaldon
Gjaldon

Reputation: 5644

If you want to use the Rails-3-style protected attributes, you'll need to install the protected_attributes gem.

As pointed out by Rafael Fiuza, you will have to use strong_parameters in Rails 4 if you don't want to install another gem just to get the Rails-3 way of protecting attributes.

If you use strong parameters, your code in HomePageController will look something like:

def add_to_cart
  #code for defining @customer
  @customer.cart_items.create(cart_item_params)
end

def cart_item_params
  params.require(:cart_item).permit(:product_id, :quantity_ordered)
end

You don't need to define #add_product in your Customer model or you could refactor it to make use of cart_items.create(cart_item_attributes instead to make it a lot shorter and cleaner.

If you're already using the protected_attributes gem, you'll need to add below code in your CartItem model instead of in your Customer model:

class CartItem < ActiveRecord::Base
  attr_accessible :customer_id, :product_id, :quantity_ordered

  #other code
end

Hope it helps!

Upvotes: 1

Rafael Fiuza
Rafael Fiuza

Reputation: 21

In rails 4,mass assignments protection is in controllers using strong params. Check out http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html.

Upvotes: 0

RustyToms
RustyToms

Reputation: 7810

At the top of your CartItem.rb file you should have something like this:

class CartItem < ActiveRecord::Base
  belongs_to :customer 
  attr_accessible :customer_id, :product_id, :quantity_ordered

The attr_accessible is necessary in your CartItem model file, so that you can assign those attributes when you create a new instance of CartItem.

Upvotes: 0

Dhaulagiri
Dhaulagiri

Reputation: 3291

It looks like your attr_accessible line should be in your CartItem model, not the Customer model

Upvotes: 0

Related Questions