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.

Reply via email to