[ Posted by kevin
Tue, 17 Apr 2007 22:57:52 GMT ]
For some reason most rails associations allow :select as a parameter to limit which rows are loaded, but belongs_to doesn't.
Here's my (only rudimentarily tested) monkey-patch to add it:
module ActiveRecord::Associations::ClassMethods
def create_belongs_to_reflection(association_id, options)
$stderr.puts "MAKING REFLECTION"
options.assert_valid_keys(
:select, #added
:class_name, :foreign_key, :foreign_type, :remote, :conditions, :order, :include, :dependent,
:counter_cache, :extend, :polymorphic
)
reflection = create_reflection(:belongs_to, association_id, options, self)
if options[:polymorphic]
reflection.options[:foreign_type] ||= reflection.class_name.underscore + "_type"
end
reflection
end
end
module ActiveRecord
module Associations
class BelongsToAssociation @reflection.options[:select] || '*', #added
:conditions => conditions,
:include => @reflection.options[:include]
)
end
end
end
end
Technorati Tags: monkey patching, ruby on rails
Posted in Coding | 9 comments
[ Posted by kevin
Fri, 13 Apr 2007 20:51:29 GMT ]
I've been avoiding blogging about things that were overly technical for awhile, but screw it, I need more things to write about anyways, so I'll start sharing nuggets of knowledge here as well.
Rails eager loading lets you load sub-elements on the database level, which can be a huge speed increase, though sometimes at a database cost. In my experience, the biggest problem is that items I'm joining together often have a big 'description' column, that can cause memory issues if loaded too indescriminatingly.
@logs = ItemLog.find(:all, :conditions => "target_id=#{@user.id}", :order => 'item_logs.created_at DESC', :limit => 40, :include => 'item')
What I wanted to do was add :select => 'only_rows_i_want'. But rails doesn't let you use :select with :include.
So what I did was do it without the :select, and take a look at the log file to see what the generated query would be. Then I removed the items I wanted and used it as a find_by_sql query:
rows = ItemLog.find_by_sql("SELECT item_logs.`id` AS t0_r0, item_logs.`user_id` AS t0_r1, item_logs.`item_id` AS t0_r2, item_logs.`created_at` AS t0_r3, item_logs.`referer` AS t0_r4, item_logs.`target_id` AS t0_r5, items.`id` AS t1_r0, items.`user_id` AS t1_r1, items.`title` AS t1_r4 FROM item_logs LEFT OUTER JOIN items ON items.id = item_logs.item_id WHERE (target_id=#{@user.id}) ORDER BY item_logs.created_at DESC LIMIT 50")
Then how do you get it to make the sub-elements into the actual objects?
join_dep = ActiveRecord::Associations::ClassMethods::JoinDependency.new(ItemLog, ['item'], nil)
@logs = join_dep.instantiate(rows)
I've put the name of the class I'm doing the find on as the first parameter, the include field I used as the 2nd. It works great with rails 1.2!
Technorati Tags: ruby, rails, ruby on rails
Posted in Coding | 5 comments