Хеш для выбора ActiveRecord - PullRequest
       0

Хеш для выбора ActiveRecord

2 голосов
/ 26 июня 2011

Можно ли передать Hash в качестве параметра для ActiveRecord 'select?Я имею в виду, как это (здесь у меня есть простая модель: LineItem имеет id из Product и Order):

Product.select(
    :orders => [{:name => :buyer}, :email], # orders.name as buyer
    :products => {:title => :product}).     # products.title as product
  joins(:line_items => :order)

Чтобы получить следующий 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"

Если это невозможно, то я предлагаю несколько обратно совместимых (можно использовать по-старому, с 1 простой строкой в ​​качестве переметра) расширение для метода select, но яне могу понять, как сделать так, чтобы прозрачный (т.е. без _h в конце, как я делал ниже) замена в масштабе приложения:

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

Я буду признателен, если расскажу мне о некоторых деталях реализации ActiveRecord, касающихся его шаблона, который использовался для создания этого очень неясного для экзамена драгоценного камня:)

Ответы [ 2 ]

1 голос
/ 26 июня 2011

Источник выбранного метода -

# 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

- предполагает, что он не будет делать то, что вы просите. Тем не менее, поскольку он может по желанию взять блок, вы можете привести его в нужное вам поведение ...

Всякий раз, когда я путаюсь в том, что я могу и не могу делать с вещами Арела, я просто просматриваю источник по адресу:

Arel API

Я не уверен, что это помогает, но, по крайней мере, оно может направить вас в правильном направлении для исследования ...

0 голосов
/ 30 января 2014

Ваш последний вопрос о том, как избежать _h, см. . Когда вы исправляете метод, обезьяна, можете ли вы вызвать переопределенный метод из новой реализации?

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'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...