Как уже упоминалось, активные ассоциации записей создают метрическую прикладную загрузку удобных методов. Конечно, вы можете написать свои собственные методы, чтобы получить все. Но это не Rails Way.
Железнодорожный путь - кульминация двух девизов. СУХОЙ (не повторяйте себя) и «Соглашение о конфигурации». По сути, называя вещи так, чтобы это имело смысл, некоторые надежные методы, предоставляемые каркасом, могут абстрагировать весь общий код. Код, который вы помещаете в свой вопрос, является идеальным примером того, что можно заменить одним вызовом метода.
Где эти удобные методы действительно сияют, так это более сложные ситуации. Такие вещи, как модели соединений, условия, проверки и т. Д.
Чтобы ответить на ваш вопрос, когда вы делаете что-то вроде @user.articles.find(:all, :conditions => ["created_at > ? ", tuesday])
, Rails готовит два запроса SQL, а затем объединяет их в один. где как ваша версия просто возвращает список объектов. Именованные области действия делают то же самое, но обычно не пересекают границы модели.
Вы можете проверить это, проверив SQL-запросы в файле development.log, когда вы вызываете эти вещи в консоли.
Итак, давайте на минутку поговорим о Именованных областях , потому что они дают отличный пример того, как рельсы обрабатывают SQL, и я думаю, что они представляют собой более простой способ продемонстрировать, что происходит за кулисами, как им не нужны модельные ассоциации, чтобы хвастаться.
Именованные области могут использоваться для выполнения пользовательских поисков модели. Они могут быть связаны вместе или даже вызваны через ассоциации. Вы можете легко создать пользовательские средства поиска, которые возвращают идентичные списки, но затем вы столкнетесь с теми же проблемами, что и в Вопросе.
class Article < ActiveRecord::Base
belongs_to :user
has_many :comments
has_many :commentators, :through :comments, :class_name => "user"
named_scope :edited_scope, :conditions => {:edited => true}
named_scope :recent_scope, lambda do
{ :conditions => ["updated_at > ? ", DateTime.now - 7.days]}
def self.edited_method
self.find(:all, :conditions => {:edited => true})
end
def self.recent_method
self.find(:all, :conditions => ["updated_at > ?", DateTime.now - 7 days])
end
end
Article.edited_scope
=> # Array of articles that have been flagged as edited. 1 SQL query.
Article.edited_method
=> # Array of Articles that have been flagged as edited. 1 SQL query.
Array.edited_scope == Array.edited_method
=> true # return identical lists.
Article.recent_scope
=> # Array of articles that have been updated in the past 7 days.
1 SQL query.
Article.recent_method
=> # Array of Articles that have been updated in the past 7 days.
1 SQL query.
Array.recent_scope == Array.recent_method
=> true # return identical lists.
Здесь все меняется:
Article.edited_scope.recent_scope
=> # Array of articles that have both been edited and updated
in the past 7 days. 1 SQL query.
Article.edited_method.recent_method
=> # no method error recent_scope on Array
# Can't even mix and match.
Article.edited_scope.recent_method
=> # no method error
Article.recent_method.edited_scope
=> # no method error
# works even across associations.
@user.articles.edited.comments
=> # Array of comments belonging to Articles that are flagged as
edited and belong to @user. 1 SQL query.
По сути, каждая именованная область создает фрагмент SQL. Rails умело объединится с каждым другим фрагментом SQL в цепочке, чтобы произвести один запрос, возвращающий именно то, что вы хотите. Методы, добавленные методами ассоциации, работают одинаково. Вот почему они легко интегрируются с named_scopes.
Причина, по которой метод mix & match не работает, заключается в том, что метод of_sector, определенный в вопросе, не работает. edited_methods возвращает Array, где edited_scope (а также find и все другие удобные AR-методы, вызываемые как часть цепочки) передают свой фрагмент SQL вперед к следующей вещи в цепочке. Если он последний в цепочке, он выполняет запрос. Точно так же это не будет работать.
@edited = Article.edited_scope
@edited.recent_scope
Вы пытались использовать этот код. Вот правильный способ сделать это:
class User < ActiveRecord::Base
has_many :articles do
def of_sector(sector_id)
find(:all, :conditions => {:sector_id => sector_id})
end
end
end
Для достижения этой функциональности вы хотите сделать следующее:
class Articles < ActiveRecord::Base
belongs_to :user
named_scope :of_sector, lambda do |*sectors|
{ :conditions => {:sector_id => sectors} }
end
end
class User < ActiveRecord::Base
has_many :articles
end
Тогда вы можете делать такие вещи:
@user.articles.of_sector(4)
=> # articles belonging to @user and sector of 4
@user.articles.of_sector(5,6)
=> # articles belonging to @user and either sector 4 or 5
@user.articles.of_sector([1,2,3,])
=> # articles belonging to @user and either sector 1,2, or 3