У меня есть массив объектов, назовем его Indicator
. Я хочу запустить def self.subjects
в этом массиве методы класса индикаторов (различных видов , областей действия и т. Д.). Единственный известный мне способ запустить методы класса для группы объектов - сделать их ActiveRecord :: Relation. Поэтому я прибегаю к добавлению to_indicators
метода в Array
.
def to_indicators
# TODO: Make this less terrible.
Indicator.where id: self.pluck(:id)
end
Иногда я объединяю несколько из этих областей, чтобы отфильтровать результаты в методах класса. Итак, хотя я вызываю метод для ActiveRecord :: Relation, я не знаю, как получить доступ к этому объекту. Я могу добраться до его содержания только через all
. Но all
это массив. Итак, мне нужно преобразовать этот массив в ActiveRecord :: Relation. Например, это часть одного из методов:
all.to_indicators.applicable_for_bank(id).each do |indicator|
total += indicator.residual_risk_for(id)
indicator_count += 1 if indicator.completed_by?(id)
end
Я думаю, это сводится к двум вопросам.
- Как я могу преобразовать массив объектов в ActiveRecord :: Relation? Желательно не делать
where
каждый раз. def self.subjects
Как мне получить доступ к самому объекту ActiveRecord :: Relation при запуске метода типа в ActiveRecord :: Relation?
Спасибо. Если мне нужно что-то уточнить, дайте мне знать.
.all
, просто используйте,.scoped
как указывает ответ Эндрю Маршалла (хотя в рельсах 4 он будет работать.all
). Если вам нужно превратить массив в отношение, вы где-то пошли не так ...Ответы:
Вы не можете преобразовать массив в ActiveRecord :: Relation, поскольку Relation - это просто построитель для SQL-запроса, а его методы не работают с фактическими данными.
Однако, если вы хотите отношения, тогда:
для ActiveRecord 3.x не вызывайте,
all
а вместо этого вызывайтеscoped
, что вернет Relation, которое представляет те же записи,all
что и в Array.для ActiveRecord 4.x просто вызовите
all
, который вернет Relation.Когда метод вызывается для объекта Relation,
self
это отношение (в отличие от класса модели, в котором оно определено).источник
class User; def self.somewhere; where(location: "somewhere"); end; end
, а затемUser.limit(5).somewhere
Вы можете преобразовать массив объектов
arr
в ActiveRecord :: Relation, как это (при условии, что вы знаете, к какому классу относятся объекты, что вы, вероятно, делаете)Вы должны использовать
where
его, это полезный инструмент, которым вы не должны отказываться. И теперь у вас есть однострочный преобразователь массива в отношение.map(&:id)
превратит ваш массив объектов в массив, содержащий только их идентификаторы. И передача массива в предложение where сгенерирует оператор SQL,IN
который выглядит примерно так:Имейте в виду, что порядок в массиве будет потерян - но поскольку ваша цель - запустить метод класса только для коллекции этих объектов, я предполагаю, что это не будет проблемой.
источник
where(id: arr.map(&:id))
? И, строго говоря, это не преобразует массив в отношение, а вместо этого получает новые экземпляры объектов (как только отношение реализовано) с теми идентификаторами, которые могут иметь другие значения атрибутов, чем уже существующие в памяти экземпляры в массиве.Что ж, в моем случае мне нужно преобразовать массив объектов в ActiveRecord :: Relation, а также отсортировать их по определенному столбцу (например, id). Поскольку я использую MySQL, функция поля может быть полезна.
SQL выглядит так:
Функция поля MySQL
источник
ActiveRecord::Relation
связывает запрос к базе данных, который извлекает данные из базы данных.Допустим, у нас есть массив с объектами одного класса, тогда с каким запросом мы предполагаем связать их?
Когда я бегу,
Здесь, выше,
users
возвращаетRelation
объект, но связывает запрос базы данных за ним, и вы можете его просмотреть,Таким образом, невозможно вернуться
ActiveRecord::Relation
из массива объектов, который не зависит от запроса sql.источник
Во-первых, это НЕ серебряная пуля. По своему опыту я обнаружил, что преобразование в отношения иногда проще, чем альтернативы. Я стараюсь использовать этот подход очень экономно и только в тех случаях, когда альтернатива будет более сложной.
Это, как говорится, мое решение, я расширил
Array
классПример использования будет
array.to_activerecord_relation.update_all(status: 'finished')
. Где мне это использовать?Иногда нужно отфильтровать,
ActiveRecord::Relation
например убрать незавершенные элементы. В таких случаях лучше всего использовать прицел,elements.not_finished
и вы все равно оставите егоActiveRecord::Relation
.Но иногда это состояние более сложное. Выньте все незавершенные элементы, которые были произведены за последние 4 недели и были проверены. Чтобы избежать создания новых областей, вы можете отфильтровать массив, а затем преобразовать обратно. Имейте в виду, что вы все еще делаете запрос к БД, быстро, поскольку он выполняет поиск,
id
но все еще является запросом.источник