Можно ли отменить область действия в Rails 3?
У меня есть следующий класс для моего класса с именем Collection
:
scope :with_missing_coins, joins(:coins).where("coins.is_missing = ?", true)
Я могу запустить Collection.with_missing_coins.count
и вернуть результат - он отлично работает!
В настоящее время, если я хочу получать коллекции без пропущенных монет, я добавляю еще одну область:
scope :without_missing_coins, joins(:coins).where("coins.is_missing = ?", false)
Я нахожу, что пишу много этих "противоположных" областей. Можно ли получить противоположность области без ущерба для удобочитаемости или прибегнуть к лямбда/методу (который принимает true
или false
как параметр)?
Что-то вроде этого:
Collection.!with_missing_coins
Ответы
Ответ 1
Я бы не использовал для этого одну область, но два:
scope :with_missing_coins, joins(:coins).where("coins.is_missing = ?", true)
scope :without_missing_coins, joins(:coins).where("coins.is_missing = ?", false)
Таким образом, когда эти области используются, тогда он четко показывает, что происходит. С некоторыми числами1311407, не сразу понятно, что делает аргумент false
для with_missing_coins
.
Мы должны попытаться написать код как можно яснее, и если это означает, что он менее ревнив о DRY один раз в то время, как и так.
Ответ 2
В Rails 4.2 вы можете:
scope :original, -> { ... original scope definition ... }
scope :not_original, -> { where.not(id: original) }
Он будет использовать подзапрос.
Ответ 3
Там нет "разворота" объема как такового, хотя я не думаю, что прибегать к методу лямбда - проблема.
scope :missing_coins, lambda {|status|
joins(:coins).where("coins.is_missing = ?", status)
}
# you could still implement your other scopes, but using the first
scope :with_missing_coins, lambda { missing_coins(true) }
scope :without_missing_coins, lambda { missing_coins(false) }
то
Collection.with_missing_coins
Collection.without_missing_coins
Ответ 4
это могло бы просто работать, не проверял это много. использует rails 5 Я думаю, что rails 3 имеет метод where_values вместо where_clause.
scope :not, ->(scope_name) { query = self
send(scope_name).joins_values.each do |join|
query = query.joins(join)
end
query.where((send(scope_name).where_clause.send(:predicates).reduce(:and).not))}
использование
Model.not(: SCOPE_NAME)
Ответ 5
Обновите. Теперь в Rails 6 добавлены удобные и изящные методы с отрицательным перечислением.
# All inactive devices
# Before
Device.where.not(status: :active)
#After
Device.not_active
сообщение в блоге
здесь