Hassen
Hassen

Reputation: 7664

Rails: How to create a new entry in the join table

Let's consider a practical example: A product that has many reviews, written by clients. We have a many-to-many relationship between product and client through reviews.

class Product < ActiveRecord::Base
    has_many :reviews
    has_many :clients, :through => :reviews
end

class Client < ActiveRecord::Base
    has_many :reviews
    has_many :products, :through => :reviews
end

class Reviews < ActiveRecord::Base
    belongs_to :product
    belongs_to :client
end

Here, I'm using the has_many :through to create the many-to-many relation, because the review table needs to have extra attributes, like the score, content, likes,...

The user logs into my app, so I can get his data through:

client = Client.find_by_id current_user.id

He goes to the product page, so I can get product data:

product = Product.find_by_id params[:id]

How can I create client review of the product?

I tried:

review = Review.create :client => client, :product => product, :comment => params[:review][:comment]

but it gives me: MassAssignSecurity: can't mass-assign protected attributes: product, client

Any idea? Thanks in advance.

Upvotes: 2

Views: 2136

Answers (3)

tokenvolt
tokenvolt

Reputation: 1494

As soon as you create a Review object and explicitly pass arguments you need to make them accessible in your Review model. In this case it must be foreign keys

class Reviews < ActiveRecord::Base

    belongs_to :product
    belongs_to :client

    attr_accessible :client_id, :product_id
end

That should work, but this's bad practice, which causes security issues. Instead of making foreign keys accessible and explicitly passing them in Review.create, I recommend to replace review.create with the following:

review = Review.new
review.client = client
review.product = product
review.comment = params[:review][:comment]
review.save

That will create a new Review object avoiding mass-assignment. Hope this helps.

Upvotes: 3

Giorgio Previtera
Giorgio Previtera

Reputation: 393

The :client and :product attributes are private, you have to make them accesible on each class setting attr_accessible :client and attr_accessible :product respectively like:

class Reviews < ActiveRecord::Base
    belongs_to :product
    belongs_to :client

    attr_accessible :client, :product
end

Hope this helps

Upvotes: 0

Prasad Surase
Prasad Surase

Reputation: 6574

Add to ur model where the attributes are :product and :client

attr_accessible :product, :client

http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html

Upvotes: 0

Related Questions