Как изменить результаты запроса Rails ActiveRecord перед возвратом? - PullRequest
2 голосов
/ 07 июня 2011

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

MyModel.some_custom_scope.some_other_scope.enhance_with_external_data.each do |object|
  puts object.some_attribute_from_external_data_source
end

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

def self.enhance_with_external_data
  external_data = get_external_data
  Enumerator.new do |yielder|
    # mimick some stuff I saw in ActiveRecord and don't quite understand:
    relation.to_a.each do |obj|
      update_obj_with_external_data(obj)
      yielder.yield(obj)
    end
  end
end

Это в основном работает, за исключением того, что оно не учитывает предыдущие примененные области, поэтому если я сделаю это:

MyModel.some_custom_scope.some_other_scope.enhance_with_external_data

Он возвращает ВСЕ МОДЕЛИ, а не только те, которые ограничены some_custom_scope и some_other_scope.

Надеюсь, то, что я пытаюсь сделать, имеет смысл. Кто-нибудь знает, как это сделать, или я пытаюсь поставить квадратный колышек в круглое отверстие?

Ответы [ 2 ]

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

Я нашел способ сделать это.Это довольно уродливо, но, кажется, работает:

def self.merge_with_extra_info
  the_scope = scoped
  class << the_scope
    alias :base_to_a :to_a
    def to_a
      MyModel.enhance(base_to_a)
    end
  end
  the_scope
end

def self.enhance(items)
  items.each do |item|
    item = add_extra_item_info(item)
  end
  items
end

Это добавляет метод класса к моей модели, который, по неизвестным мне причинам, делает его доступным для экземпляров ActiveRecord :: Relation.Он переопределяет, только для текущего объекта области видимости, метод to_a, который вызывается для получения записей.Это позволяет мне добавить дополнительную информацию к каждой записи перед возвратом.Так что теперь я получаю всю цепочечность и все такое:

MyModel.where(:some_attribute => some_value).merge_with_extra_info.limit(10).all

Мне бы хотелось иметь возможность получить его, поскольку он перечисляет, а не после того, как он помещен в массив, как здесь, но не смог понятьо том, как получить это глубоко в AR / Arel.

0 голосов
/ 22 сентября 2015

Я достиг чего-то похожего, расширив соотношение:

class EnhancedModel < DelegateClass(Model)
  def initialize(model, extra_data)
    super(model)
    @extra_data = extra_data
  end

  def use_extra_data
    @extra_data.whatever
  end
end

module EnhanceResults
  def to_a
    extra_data = get_data_from_external_source(...)
    super.to_a.map do |model_obj|
      EnhancedModel.new(model_obj, extra_data)
    end
  end
end

models = Model.where('condition')
models.extend(EnhanceResults)
models.each do |enhanced_model|
  enhanced_model.use_extra_data
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...