Hash for ActiveRecord's select
Is it possible to pass a Hash
as a parameter for the ActiveRecord
's select
? I mean like this (here I have simple model: LineItem
has id
's of Product
and Order
):
Product.select(
:orders => [{:name => :buyer}, :email], # orders.name as buyer
:products => {:title => :product}). # products.title as product
joins(:line_items => :order)
To get the following SQL:
SELECT "orders"."name" as "buyer", "orders"."email", "products"."title" as "product"
FROM "products"
INNER JOIN "line_items" ON "line_items"."product_id" = "products"."id"
INNER JOIN "orders" ON "orders"."id" = "line_items"."order_id"
If it isn't possible, then I suggest some backward-compatible (can be used in old way, with 1 simple string as a peremeter) extension for the select
method, but I can't figure out how to make it as transparent (i.e. w/o _h
at the end as I did below) application-wide replacement:
class ActiveRecord::Base
def self.select_h(*fields) # TODO: rid of this ugly _h
hash_of_fields = fields.last.is_a?(Hash) ? fields.pop : {}
fields_in_hash = hash_of_fields.map do |table, field_or_fields|
(field_or_fields.is_a?(Array) ? field_or_fields : [field_开发者_运维技巧or_fields]).map do |field|
field = "#{field.first[0]}\" as \"#{field.first[1]}" if field.is_a? Hash
"\"#{table}\".\"#{field}\""
end
end
# calling original select
select (fields+fields_in_hash).join(', ')
end
end
I'll appreciate pointing me at some details about internals of ActiveRecord
's implementation regarding it's pattern that was used to make this very obscure-to-exam gem :)
The source of the select method--
# File activerecord/lib/active_record/relation/query_methods.rb, line 34
def select(value = Proc.new)
if block_given?
to_a.select {|*block_args| value.call(*block_args) }
else
relation = clone
relation.select_values += Array.wrap(value)
relation
end
end
-- suggests that it won't do what you're asking it to. However, as it can optionally take a block you might be able to coerce it into the behavior you're looking for...
Whenever I get confused about what I can and can't do with the Arel stuff, I just peruse the source at:
Arel API
I'm not sure this helps but at the very least it might send you in the right direction to explore...
For your final question of how to avoid the _h, see When monkey patching a method, can you call the overridden method from the new implementation?
class Foo
def bar
'Hello'
end
end
class Foo
old_bar = instance_method(:bar)
define_method(:bar) do
old_bar.bind(self).() + ' World'
end
end
Foo.new.bar # => 'Hello World'
精彩评论