Есть ли способ выйти из default_scope при использовании has_many? - PullRequest
2 голосов
/ 07 июля 2010

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

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 - это место only , которое необходимо вырвать из области видимости, поэтому, если говорить о поведении по умолчанию, я думаю, что 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() тоже не очень СУХАЯ, если честно.Он просто просит, чтобы произошла ошибка, когда область не используется.

Ответы [ 2 ]

2 голосов
/ 20 октября 2011

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

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

Message.unscoped.sent
Message.sent  

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

0 голосов
/ 07 июля 2010

Не можете ли вы использовать опцию :conditions в ассоциации?Как то так:

has_many :nested_licences, :class_name => 'Licence',
         :dependent => :destroy, :conditions => "parent_licence_id = #{id}" 
...