John H. wrote in post #1063205: > I'm a bit unclear what's going on with relations. I'm hoping someone can > help explain it to me. > > Lets say we have a model with orders and line_items such that an order > has > many line_items. Thus: > > class Order > has_may :line_items > end > class LineItem > belongs_to :order > end > > When I have an order and call line_items what's going on? e.g. > > Order order = Order.first > order.line_items.each {|li| puts li } > > I thought that was basically an alias for: > > Order order = Order.first > LineItem.where(:order_id => order.id).each {|li| puts li }
This is an over-simplification. Let me illustrate by example: 1.9.3p194 :010 > order = Order.first Order Load (0.3ms) SELECT "orders".* FROM "orders" LIMIT 1 => #<Order id: 1, name: "First item", description: "First one", price: nil, created_at: "2012-06-06 01:20:03", updated_at: "2012-06-06 01:20:03"> Notice first that selecting the order does not touch the line_items table at all. At this point the order.line_items method is represented by an ActiveRecord::Relation object. Accessing this relation object will load (fire) the relation and populate the array. Now let's take look at the line_items: 1.9.3p194 :002 > order.line_items LineItem Load (0.2ms) SELECT "line_items".* FROM "line_items" WHERE "line_items"."order_id" = 1 => [#<LineItem id: 1, order_id: 1, name: "Line 1", quantity: 5, created_at: "2012-06-06 01:21:24", updated_at: "2012-06-06 01:21:24">] 1.9.3p194 :003 > order.line_items => [#<LineItem id: 1, order_id: 1, name: "Line 1", quantity: 5, created_at: "2012-06-06 01:21:24", updated_at: "2012-06-06 01:21:24">] Notice the first time we access line_items ActiveRecord will load the association by running a generated SQL statement. Subsequent calls do not reissue the SQL statement. Let's take a look at what is reported as the class for order.line_items: 1.9.3p194 :003 > puts order.line_items.class Array This appears to be a typical Array object, but it's really more complicated than that. What you're seeing is not a simple Array object, but rather an Array that has been extended with some Rails magic. Let's take a look that the ancestry of that resulting "Array" object: 1.9.3p194 :004 > puts order.line_items.class.ancestors Array JSON::Ext::Generator::GeneratorMethods::Array Enumerable Object PP::ObjectMixin JSON::Ext::Generator::GeneratorMethods::Object ActiveSupport::Dependencies::Loadable Kernel BasicObject Here's the ancestry of a plain old Ruby Array: # Ruby (No Rails) $ irb 1.9.3p194 :001 > Array.ancestors => [Array, Enumerable, Object, Kernel, BasicObject] In fact all Array objects in rails have the additional magic added to them: # Ruby on Rails $ rails console Loading development environment (Rails 3.2.3) 1.9.3p194 :001 > puts Array.ancestors Array JSON::Ext::Generator::GeneratorMethods::Array Enumerable Object PP::ObjectMixin JSON::Ext::Generator::GeneratorMethods::Object ActiveSupport::Dependencies::Loadable Kernel BasicObject > but, this isn't consistent with batching. > > So if we do > > Order order = Order.first > > # this doesn't appear to work, it's not batching, just finding all of > the > line items and iterating > order.line_items.find_each {|li| puts li } Hopefully what I explained above will clear up what's happening here. That very first access of order.line_items is causing that relation object to fire and load the objects. What you probably want is the find_in_batches method provided by ActiveRecord: http://api.rubyonrails.org/classes/ActiveRecord/Batches.html#method-i-find_in_batches -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-talk+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.