Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

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

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

Множество способов получить что-то подобное, но, конечно, не самое лучшее, что нужно хранить в базе кода. Я использовал область действия: при рефакторинге не обнаружил, что мне нужно гарантировать короткое время пустой ActiveRecord:: Relation.

Ответ 4

Входящие в Rails 4

В Rails 4 цепочка ActiveRecord::NullRelation будет возвращена из таких вызовов, как Post.none.

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

Согласно комментариям:

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

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

Ответ 5

scope :none, limit(0)

Это опасное решение, потому что ваш прицел может быть привязан.

User.none.first

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

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

Ответ 6

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

scope :none, limit(0)

Переходя к чему-то вроде этого:

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

Ответ 7

Использовать область действия:

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)) }

Ответ 8

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

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