Предотвратить преобразование отношения ActiveRecord в массив

ОБНОВИТЬ:

Как добавить в модель виртуальный атрибут и сохранить отношение активной записи.

Я пробовал следующее, но .each возвращает массив, а не активную запись. Какой еще метод я могу использовать?


Мой метод set_listable_for преобразует отношение activerecord в массив. Я хочу сохранить отношение ActiveRecord.

Во время выполнения я добавил attr_access к модели активной записи.

def add_listable_attribute_to(*relation)
  relation.each do |rel|
    rel[1].first.class.class_eval do
      attr_accessor :listable
    end
  end
end

Затем я использовал этот метод, чтобы установить значение атрибута на одно и то же значение для всех записей....

   def set_listable_for(relation, object)
      relation.each do |record|
        record.listable = object
      end
    end

Однако мое отношение ActiveRecord преобразуется в послесловие массива.

Как сохранить отношение Active Record, так как мне не нужен массив. Поскольку я продолжаю использовать его здесь и продолжаю анализировать и запрашивать его...

def union_scope(*relation)
  add_listable_attribute_to(*relation)

  listable = relation.first[0]
  combined = set_listable_for(relation.first[1], listable)
  relation.drop(1).each do |relation_set|
    listable = relation[0]
    set_listable_for(relation_set[1], listable)
    combined = combined.or(relation_set[1])
  end
  combined
end

Спасибо


person user2012677    schedule 26.07.2019    source источник
comment
Именно так должен вести себя ActiveRecord::Relation. Он представляет собой область или запрос, который можно выполнить для базы данных (пока нет записей). И как только вам понадобится одна или несколько фактических записей, он загрузит записи и вернет их в виде массива. Это происходит, если вы вызываете метод типа first, count или each для отношения. Поэтому ваш вопрос мне неясен, потому что вы просите отключить его основные функции.   -  person spickermann    schedule 26.07.2019
comment
@spickermann, я ищу альтернативное решение, которое заменит мой код, чтобы я мог вернуть отношение AR, а не массив.   -  person user2012677    schedule 26.07.2019


Ответы (2)


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

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

  1. Используйте декоратор, чтобы обернуть экземпляры вашего отношения после его загрузки в контроллер или представление. Это проще для понимания, но выводит функциональность из уровня модели.

  2. Установите listable в обратном вызове after_initialize. Это сохраняет функциональность на уровне модели, но добавляет много сложности.

  3. Убедитесь, что вы вызываете set_listable_for в контроллере только после определения области. Вариант №1.

person fylooi    schedule 26.07.2019
comment
Я бы хотел, но вижу добавленный код, после которого я все еще работаю с AR Relation, поэтому мне нужно другое решение. - person user2012677; 26.07.2019

Добавив оператор «AS» в Select, я смог вернуть модель ActiveRecord. Единственная проблема заключается в том, что когда я вызываю .count, мне нужно использовать .count(:all) или .count(:id), чтобы предотвратить ошибки.

def union_scope(*relation)
  listable = relation.first[0]
  scope = relation.first[1]
  combined = scope.select("#{scope.table_name}.*, \'#{listable.class.name}\' as listable")
  relation.drop(1).each do |relation_set|
    listable = relation_set[0]
    scope = relation_set[1].select("#{scope.table_name}.*, \'#{listable.class.name}\' as listable")
    combined = combined.or(scope)
  end
  combined
end
person user2012677    schedule 26.07.2019