Как вернуть пустое отношение ActiveRecord?


Если у меня есть область с лямбда и она принимает аргумент, в зависимости от значения аргумента, я могу знать, что не будет никаких совпадений, но я все равно хочу вернуть отношение, а не пустой массив:

scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : [] }

то, что я действительно хочу,-это метод "none", противоположный "all", который возвращает отношение, которое все еще может быть связано, но приводит к короткому замыканию запроса.

9 206

9 ответов:

теперь есть" правильный " механизм в Rails 4:

>> Model.none 
=> #<ActiveRecord::Relation []>

более портативное решение, которое не требует столбца " id " и не предполагает, что не будет строки с идентификатором 0:

scope :none, where("1 = 0")

Я все еще ищу более "правильный" путь.

вы можете добавить область под названием "Нет":

scope :none, where(:id => nil).where("id IS NOT ?", nil)

это даст вам пустой ActiveRecord:: Relation

вы также можете добавить его в ActiveRecord::Base в инициализаторе (если хотите):

class ActiveRecord::Base
 def self.none
   where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil)))
 end
end

много способов получить что-то вроде этого, но, конечно, не лучшая вещь, чтобы держать в базе кода. Я использовал scope: none при рефакторинге и обнаружил, что мне нужно гарантировать пустое отношение ActiveRecord:: в течение короткого времени.

идешь в Rails 4

в рельсах 4, цепной ActiveRecord::NullRelation будет возвращен из вызовов, как Post.none.

ни он, ни цепные методы не будут генерировать запросы к базе данных.

в соответствии с комментариями:

возвращенная ActiveRecord:: NullRelation наследует от Связь и реализует шаблон нулевого объекта. Это объект с определенное поведение null и всегда возвращает пустой массив записей без quering база данных.

посмотреть исходный код.

scope :none, limit(0)

это опасное решение, потому что ваш объем может быть прикован.

пользователей.никто.первый

вернет первого пользователя. Это безопаснее использовать

scope :none, where('1 = 0')

Я думаю, что я предпочитаю, как это выглядит для других вариантов:

scope :none, limit(0)

приведет к чему-то вроде этого:

scope :users, lambda { |ids| ids.present? ? where("user_id IN (?)", ids) : limit(0) }

используйте scoped:

scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : scoped }

но, вы также можете упростить ваш код:

scope :for_users, lambda { |users| where(:user_id => users.map(&:id)) if users.any? }

Если вы хотите пустой результат, используйте эту (убрать условие if):

scope :for_users, lambda { |users| where(:user_id => users.map(&:id)) }

есть также варианты, но все они делают запрос к db

where('false')
where('null')

можно и так вот:

scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : User.none }

http://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/none

поправьте меня, если я ошибаюсь.