Область действия ActiveRecord Rails 3 и метод класса

Я новичок в новом интерфейсе запросов ActiveRecord, поэтому я все еще во всем разбираюсь.

Я надеялся, что кто-нибудь сможет объяснить разницу между использованием scope в модели ActiveRecord и просто использованием метода класса (т.е. self.some_method)

Из того, что я могу понять, ожидается, что область действия всегда будет возвращать отношение, тогда как метод класса не обязательно должен это делать. Это правда?

Например, я подумал, что имеет смысл сделать что-то вроде:

class Person
  scope :grouped_counts, group(:name).count
end

Но это не работает. Я получаю эту ошибку:

ArgumentError: Unknown key(s): communicating, failed, matched, unmatched
    from /Users/bradrobertson/.rvm/gems/ruby-1.9.2-p180@influitive/gems/activesupport-3.0.5/lib/active_support/core_ext/hash/keys.rb:43:in `assert_valid_keys'
    from /Users/bradrobertson/.rvm/gems/ruby-1.9.2-p180@influitive/gems/activerecord-3.0.5/lib/active_record/relation/spawn_methods.rb:110:in `apply_finder_options'
    from /Users/bradrobertson/.rvm/gems/ruby-1.9.2-p180@influitive/gems/activerecord-3.0.5/lib/active_record/named_scope.rb:110:in `block in scope'
    from (irb):48
    from /Users/bradrobertson/.rvm/gems/ruby-1.9.2-p180@influitive/gems/railties-3.0.5/lib/rails/commands/console.rb:44:in `start'
    from /Users/bradrobertson/.rvm/gems/ruby-1.9.2-p180@influitive/gems/railties-3.0.5/lib/rails/commands/console.rb:8:in `start'
    from /Users/bradrobertson/.rvm/gems/ruby-1.9.2-p180@influitive/gems/railties-3.0.5/lib/rails/commands.rb:23:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'
r

Однако он работает как метод класса

def self.grouped_counts
  group(:name).count
end

Мне интересно узнать мнение людей о том, когда использовать области действия и когда использовать методы класса. Правильно ли я предполагаю, что область видимости всегда должна возвращать отношение, а метод класса может возвращать все, что захочет?


person brad    schedule 05.05.2011    source источник


Ответы (2)


В Rails 2.x разница была больше, так как named_scopes не выполняли ваши запросы (чтобы вы могли связать их в цепочку), тогда как методы класса обычно выполняли запросы (так что вы не могли связать их в цепочку), если только вы не вручную обернули свой запрос в scoped(...) вызове.

В Rails 3 все возвращает ActiveRecord::Relation до тех пор, пока вам не потребуются фактические результаты, поэтому области действия могут быть связаны с методами класса и наоборот (при условии, что методы класса возвращают объекты ActiveRecord::Relation, а не какой-либо другой тип объекта (например, счетчик)).

Как правило, я использую scope записи для простых однострочников, чтобы отфильтровать мой набор результатов. Однако, если я делаю что-то сложное в «области действия», которая может потребовать подробной логики, лямбда-выражений, нескольких строк и т. д., я предпочитаю использовать метод класса. И, как вы поняли, если мне нужно вернуть счетчики или что-то в этом роде, я использую метод класса.

person Dylan Markow    schedule 05.05.2011
comment
Отличный ответ. См. также эту статью: Именованные области действия мертвы - person mjnissim; 09.02.2013

Как упомянул в своем ответе Дилан, одно различие между областью действия и методом класса заключается в том, что области оцениваются, когда класс загружен. Это может привести к неожиданному результату.

Например,

class Post < ActiveRecord::Base
    scope :published_earlier, where('published_at < ?', Date.today)
end

подвержен ошибкам. Правильный способ - использовать лямбда

class Post < ActiveRecord::Base
    scope :published_earlier, -> { where('published_at < ?', Date.today) }
end

Лямбда-блок оценивается лениво. Итак, Date.today запускается при вызове области, а не при оценке класса.

Если вы используете метод класса, вам не нужно использовать лямбда.

class Post < ActiveRecord::Base
    def self.published_earlier
        where('published_at < ?', Date.today)
    end
end

Потому что с методом класса код запускается во время вызова метода.

person Zack Xu    schedule 07.11.2013
comment
Следует отметить, что в Rails 4 лямбда-форма требуется для всех областей видимости. - person pdobb; 21.02.2014