Jodi Showers
2006-Jan-06 16:17 UTC
[Rails] How do I reference eagerly loaded Models in the View?
[I hope the repost isnt'' "minded". Following the advice of
another
thread I''ve changed the subject to a question. If I haven''t
included
important info, please ask. My database is being unduly killed. Jodi]
Cheers on-the-Rails-ers,
Before I start, I''ve read the ActiveRecord docs on eager loading, but
for the life of me, I can''t seem to get it working.
What I mean by this, is that the eager query itself looks good (I can
paste the
sql dump, but it looks good to me - and runs well independantly), but it
seems that I''m referencing the eagerly loaded data in a way that
activerecord doesn''t understand (my assumption) - thus I''m
getting a
tonne of additional queries.
[first, the domain:
WorkOrders has_many: WorkOrderItems
&&
WorkOrderItems belongs_to :WorkOrder
WorkOrderItems belongs_to :ProductsAndServices
secondly, the controller looks like:
@work_order = WorkOrder.find(params[:id])
@work_order_items = @work_order.WorkOrderItems.find(:all, :include
=> [:WorkOrder, :ProductsAndServices ] )
(you''ll note that I''m eagerly loading the work_order from the
work_order_item - that''s because the WorkOrderItem model references its
work_order for some processing - see "pst" below)
And in the view, I reference as such:
@work_order_items.each {|item| @work_order_items_table.data <<
Hash["Part #",
item.ProductsAndServices.part_number,"Description",
item.description, "Quantity",item.quantity, "Price",
number_to_currency(item.price), "Extended",
number_to_currency(item.sub_total)]}
The above generates @work_order_items.count queries to the
ProductsAndServices table. Why is that? Do I reference the eagerly
loaded data incorrectly?
With the same symptom, further down in the same view I make a call to a
WorkOrderItems method "pst" - this method references both eagerly
referenced models - WorkOrders and ProductsAndServices using the syntax:
#calculate the line item pst
def pst
if (self.WorkOrder.charge_pst? and
self.ProductsAndServices.charge_pst?)
sub_total * 0.07
else
0.0
end
end
Again, I see that database queries are made to retrieve both WorkOrder
and ProductsAndServices.
Probably the same problem on my part. Any ideas ninjas?
Thanx for any help.
Jodi
--
Posted via http://www.ruby-forum.com/.
Chris Hall
2006-Jan-06 17:44 UTC
[Rails] How do I reference eagerly loaded Models in the View?
your use of camelcase is confusing to read. the convention in ruby is to
not use camelcase for anything other than class names.. and it could
possible be the cause of your problem.
i''ve taken the liberty to rename/organize some things, hope you
don''t mind.
# table name : work_orders
class WorkOrder < AR::Base
has_many :work_order_items
end
# table name : work_order_items
class WorkOrderItem < AR::Base
belongs_to :work_order
belongs_to :product_or_service
end
# table name : product_or_services
class ProductOrService < AR::Base
has_many :work_order_items
end
---quote---
secondly, the controller looks like:
@work_order = WorkOrder.find(params[:id])
@work_order_items = @work_order.WorkOrderItems.find(:all, :include =>
[:WorkOrder, :ProductsAndServices ] )
---end quote---
instead, why not do:
@work_order_items = WorkOrderItem.find(:all, :conditions => [
"work_order_id
= ?", @params[:id] ], :include => [ :work_order, :product_or_service ])
---quote---
@work_order_items.each {|item| @work_order_items_table.data <<
Hash["Part #", item.ProductsAndServices.part_number,
"Description", item.description,
"Quantity",item.quantity,
"Price", number_to_currency(item.price),
"Extended", number_to_currency(item.sub_total)]}
---end quote---
not sure what the purpose of this is...i''m assuming this is html table
data? why not just use a partial?
fi that''s the case, then in list view:
<table>
<!--- column names -->
<%= render :partial => "item", :collection =>
@work_order_items %>
</table>
in _item.rhtml:
<tr>
<td><%= item.product_or_service.part_number %></td>
<td><%= item.description %></td>
<td><%= item.quantity %></td>
<td><%= number_to_currency(item.price) %></td>
<td><%= number_to_currency(item.sub_total) %></td>
</tr>
--quote---
#calculate the line item pst
def pst
if (self.WorkOrder.charge_pst? and
self.ProductsAndServices .charge_pst?)
sub_total * 0.07
else
0.0
end
end
---end quote---
again, using camelcase...try
def pst
(work_order.charge_pst? and product_or_service.charge_pst?) ? (sub_total *
0.07) : 0.0
end
hope this helps
On 1/6/06, Jodi Showers <jodi@nnovation.ca> wrote:>
> [I hope the repost isnt'' "minded". Following the advice
of another
> thread I''ve changed the subject to a question. If I
haven''t included
> important info, please ask. My database is being unduly killed. Jodi]
>
> Cheers on-the-Rails-ers,
>
> Before I start, I''ve read the ActiveRecord docs on eager loading,
but
> for the life of me, I can''t seem to get it working.
>
> What I mean by this, is that the eager query itself looks good (I can
> paste the
> sql dump, but it looks good to me - and runs well independantly), but it
> seems that I''m referencing the eagerly loaded data in a way that
> activerecord doesn''t understand (my assumption) - thus
I''m getting a
> tonne of additional queries.
>
> [first, the domain:
> WorkOrders has_many: WorkOrderItems
> &&
> WorkOrderItems belongs_to :WorkOrder
> WorkOrderItems belongs_to :ProductsAndServices
>
> secondly, the controller looks like:
> @work_order = WorkOrder.find(params[:id])
> @work_order_items = @work_order.WorkOrderItems.find(:all, :include
> => [:WorkOrder, :ProductsAndServices ] )
>
> (you''ll note that I''m eagerly loading the work_order from
the
> work_order_item - that''s because the WorkOrderItem model
references its
> work_order for some processing - see "pst" below)
>
> And in the view, I reference as such:
>
> @work_order_items.each {|item| @work_order_items_table.data <<
> Hash["Part #",
item.ProductsAndServices.part_number,"Description",
> item.description, "Quantity",item.quantity, "Price",
> number_to_currency(item.price), "Extended",
> number_to_currency(item.sub_total)]}
>
> The above generates @work_order_items.count queries to the
> ProductsAndServices table. Why is that? Do I reference the eagerly
> loaded data incorrectly?
>
> With the same symptom, further down in the same view I make a call to a
> WorkOrderItems method "pst" - this method references both eagerly
> referenced models - WorkOrders and ProductsAndServices using the syntax:
>
> #calculate the line item pst
> def pst
> if (self.WorkOrder.charge_pst? and
> self.ProductsAndServices.charge_pst?)
> sub_total * 0.07
> else
> 0.0
> end
> end
>
> Again, I see that database queries are made to retrieve both WorkOrder
> and ProductsAndServices.
>
>
> Probably the same problem on my part. Any ideas ninjas?
>
> Thanx for any help.
>
> Jodi
>
>
> --
> Posted via http://www.ruby-forum.com/.
> _______________________________________________
> Rails mailing list
> Rails@lists.rubyonrails.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
http://wrath.rubyonrails.org/pipermail/rails/attachments/20060106/33b9f836/attachment.html
Jodi Showers
2006-Jan-07 01:36 UTC
[Rails] Re: How do I reference eagerly loaded Models in the View?
Chris - I''ve just finally worked through your suggestions. While they didn''t directly lead to an answer, it did serve to help me re-examine the problem points (plus standardize my ruby syntax (cat java> /dev/null!).To your benefit chris, you didn''t have all the information needed to come up with the solution. I include the following, for those who can benefit. #1 is a watch-out (well for me anyhow), and #2 is a cool (documented)feature I discovered. I''ve since found out the following 2 things. 1. That recursive(?) model references maybe not be handled well by AR. @work_order.pst_total is a method, that looks something like: def pst_total work_order_items.inject(0) { |sum, item| sum + item.gst_charge } end and work_order_item.gst looks like #calculate the line item gst def gst if (work_order.charge_gst? and products_and_services.charge_gst?) sub_total * 0.08 else 0.0 end end As you can see that work_order.gst, calls work_order_item.gst, which then calls work_order.charge_gst? (oh what a tangled web we weave!) Anywho, the end result was work_order_items.count "select * from work_orders where id = ?". I moved the charge_gst logic, and low and behold, lots of work_order queries are toast. 2. from above, you can see if (work_order.charge_gst? and products_and_services.charge_gst?) products_and_services is a secondary relationship to work_orders [work_orders has_many :work_order_items. And :work_order_items belongs_to :products_and_services].>From the work_order class defn, I''m saving myself some queries on theproducts_and_services model using the following notation: class WorkOrder < ActiveRecord::Base has_many :work_order_items, :include => [:products_and_services] The :include option, from the docs ":include - specify second-order associations that should be eager loaded when the collection is loaded." Thus when I WorkOrder.find(), I not only get associated work_order_items, but their related products_and_services. sweet! Jodi Chris Hall wrote:> your use of camelcase is confusing to read. the convention in ruby is > to > not use camelcase for anything other than class names.. and it could > possible be the cause of your problem. > > i''ve taken the liberty to rename/organize some things, hope you don''t > mind. > > # table name : work_orders > class WorkOrder < AR::Base > has_many :work_order_items > end > > # table name : work_order_items > class WorkOrderItem < AR::Base > belongs_to :work_order > belongs_to :product_or_service > end > > # table name : product_or_services > class ProductOrService < AR::Base > has_many :work_order_items > end > > ---quote--- > secondly, the controller looks like: > @work_order = WorkOrder.find(params[:id]) > @work_order_items = @work_order.WorkOrderItems.find(:all, :include => > [:WorkOrder, :ProductsAndServices ] ) > ---end quote--- > > instead, why not do: > > @work_order_items = WorkOrderItem.find(:all, :conditions => [ > "work_order_id > = ?", @params[:id] ], :include => [ :work_order, :product_or_service ]) > > ---quote--- > @work_order_items.each {|item| @work_order_items_table.data << > Hash["Part #", item.ProductsAndServices.part_number, > "Description", item.description, > "Quantity",item.quantity, > "Price", number_to_currency(item.price), > "Extended", number_to_currency(item.sub_total)]} > ---end quote--- > > not sure what the purpose of this is...i''m assuming this is html table > data? why not just use a partial? > > fi that''s the case, then in list view: > > <table> > <!--- column names --> > <%= render :partial => "item", :collection => @work_order_items %> > </table> > > in _item.rhtml: > > <tr> > <td><%= item.product_or_service.part_number %></td> > <td><%= item.description %></td> > <td><%= item.quantity %></td> > <td><%= number_to_currency(item.price) %></td> > <td><%= number_to_currency(item.sub_total) %></td> > </tr> > > > --quote--- > #calculate the line item pst > def pst > if (self.WorkOrder.charge_pst? and > self.ProductsAndServices .charge_pst?) > sub_total * 0.07 > else > 0.0 > end > end > ---end quote--- > > again, using camelcase...try > > def pst > (work_order.charge_pst? and product_or_service.charge_pst?) ? > (sub_total * > 0.07) : 0.0 > end > > hope this helps-- Posted via http://www.ruby-forum.com/.