Можно ли отрицать область видимости в Rails 3? - PullRequest
29 голосов
/ 14 августа 2011

У меня есть следующий объем для моего класса под названием 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

Ответы [ 4 ]

52 голосов
/ 02 июня 2015

В Rails 4.2 вы можете сделать:

scope :original, -> { ... original scope definition ... }
scope :not_original, -> { where.not(id: original) }

Он будет использовать подзапрос.

12 голосов
/ 14 августа 2011

Я бы не использовал для этого одну область, а две:

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, то пусть будет так.

7 голосов
/ 14 августа 2011

Сами по себе области "обращения" нет, хотя я не думаю, что прибегать к лямбда-методу - это проблема.

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
0 голосов
/ 31 декабря 2018

это может просто сработать, особо не проверял. использует 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)

...