Есть ли способ выйти за пределы default_scope при использовании has_many?

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

class Licence < ActiveRecord::Base
  default_scope :conditions => { :parent_licence_id, nil }

  belongs_to :parent_licence, :class_name => 'Licence'
  has_many :nested_licences, :class_name => 'Licence',
           :foreign_key => 'parent_licence_id', :dependent => :destroy
end

class User < ActiveRecord::Base
  has_many :licences
end

Использование default_scope показалось отличной идеей, потому что различные модели, которые связаны с License (их около 4), а также любой код, использующий find (), не должны делать ничего особенного. Причина, по которой это не прекрасная идея, заключается в том, что область действия по умолчанию также применяется к has_many, что приводит к тому, что дочерние элементы никогда не обнаруживаются. Но has_many - это единственное место, которое нужно вырвать из области видимости, поэтому, что касается поведения "по умолчанию", я думаю, что это default_scope вполне разумно.

Так есть ли хороший способ обойти эту конкретную проблему?

Вот тот, который мне не очень нравится, потому что он использует SQL для почти тривиального запроса:

has_many :nested_licences, :class_name => 'Licence', :dependent => :destroy,
  :finder_sql => 'SELECT l.* FROM licences l WHERE l.parent_licence_id = #{id}',
  :counter_sql => 'SELECT COUNT(l.*) FROM licences l WHERE l.parent_licence_id = #{id}'

В качестве альтернативы, есть ли способ применить именованную область видимости к ассоциации из модели? например что-то вроде этого бессмысленного кода:

class Licence < ActiveRecord::Base
  named_scope :roots, :conditions => { :parent_licence_id, nil }

  belongs_to :parent_licence, :class_name => 'Licence'
  has_many :nested_licences, :class_name => 'Licence',
           :foreign_key => 'parent_licence_id', :dependent => :destroy
end

class User < ActiveRecord::Base
  has_many :licences, :scope => :roots   # a :scope option doesn't really exist
end

Я знаю, что тоже могу это сделать:

class Licence < ActiveRecord::Base
  named_scope :roots, :conditions => { :parent_licence_id, nil }

  belongs_to :parent_licence, :class_name => 'Licence'
  has_many :nested_licences, :class_name => 'Licence',
           :foreign_key => 'parent_licence_id', :dependent => :destroy
end

class User < ActiveRecord::Base
  has_many :licences, :conditions => { :parent_licence_id, nil }
end

Но это действительно не очень СУХОЕ. На самом деле необходимость выполнять каждый запрос через Licence.roots.find() вместо Licence.find() тоже не очень СУХОЙ, если честно. Он просто просит об ошибке, когда область не используется.


person Trejkaz    schedule 07.07.2010    source источник


Ответы (2)


Попробуйте использовать Licence.unscoped.find()

btw - В документации для ActiveRecord::Base.unscoped говорится, что объединение unscoped с именованным методом scope не имеет никакого эффекта.
Рекомендуется использовать блочную форму unscoped, потому что объединение unscoped с именованным scope не работает. Если «отправлено» (ниже) является named_scope, следующие два оператора идентичны.

Message.unscoped.sent
Message.sent  

fyi rails 2 также имеет with_exclusive_scope, что может быть полезно.

person Michael Durrant    schedule 19.10.2011
comment
Я также рекомендую не использовать условия с областью действия по умолчанию. Просто используйте default_scope для заказа. Когда есть условия, используйте именованную область видимости. - person Michael Durrant; 19.02.2012

Разве вы не можете использовать опцию :conditions в ассоциации? Что-то вроде этого:

has_many :nested_licences, :class_name => 'Licence',
         :dependent => :destroy, :conditions => "parent_licence_id = #{id}" 
person John Topley    schedule 07.07.2010
comment
Я тоже пробовал это, потому что rdoc подразумевал, что область видимости не будет (в нем говорилось, что она будет охватывать ее, если это будет хэш, я предположил, что это означает обратное, но это не так). Однако, в конце концов, область видимости была ограничена. :-( - person Trejkaz; 09.07.2010