开发者

Rails :has_many explanation

Trying to understand the effects of :has_many as its introduced in the Agile Web Development book 4th Edition

The following relationship is set up for the cart

class Cart < ActiveRecord::Base
  has_many :line_items, :dependent => :destroy
end

this compliments the associated LineItem class

class LineItem < ActiveRecord::Base
  belongs_to :product
  belongs_to :cart
end

All is fine, I fully understand the relationship modelling, and just trying to accept that it just 'works开发者_StackOverflow中文版'. However, in code the author, instead of using the LineItem.find method to do a search on the underlying table, uses a line_items object, e.g.

current_item = line_items.where(:product_id => product_id).first

Can someone please explain this, and ultimately I imagine, what the effect of the :has_many method call actually is? What is the line_items object, where does it come from? I guess the same question will apply to the effect of the other relational Rails methods.

Thanks.'


Consider my answer just as a very big comment to Chris Kimpton's answer.

First, you should read the API documentation, where the associations are explained pretty nicely.

In short, when you call the method has_many in the code of a class (remember that in Ruby every line is an executed code, so the has_many :something is just a call to some existing method) then that method defines another two methods with the same name as the argument you have passed.

In this case that would be the Symbol :line_items, so the has_many method makes something roughly equivalent to : def line_items(force_reload = false) and def line_items=(objects).

The newly created method line_items returns a collection object of all the LineItem objects filtered by WHERE cart_id = #{self.id} (this is a simplified example).

That collection object works like an Array, but it also responds to some more methods (like find or build) helping you to manage the relation between the Cart object and LineItem.

So, the line:

line_items.where(:product_id => some_id).first

is the equivalent of:

LineItem.where(:cart_id => self.id).where(:product_id => some_id).first

Using the first method (the line_items collection) you do not need to remember about adding that :cart_id => self.id to every statement.


If the code is exactly as you have written here, that line_items object must have been set up somehwere else in that code.

The has_many relationship will add a helper method to give the list of associated elements so it could be doing something like this:

cart = Cart.find(1)
line_items = cart.line_items

cart.line_items will return an array of line_items where line_item.cart_id = cart.id


I presume that sample line of code is in a method of the Cart class?

One of the "features" of ActiveRecord / has_many call is to add this pseudo method to your class.

So the Cart class gains a line_items method to access them.

The line_items.where call is searching within the related line_items - not all LineItems, which is what your call would do. It seems to be looking for a line_item related to a specific product - I wonder where the product_id var comes from - method parameter?

On the other side, the belongs_to call on LineItem adds a "cart" method to access the Cart it is in.

Hope this helps, Chris

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜