如何在Rails3中使用unscoped关联关系?

时间:2011-01-21 11:16:14

标签: ruby-on-rails ruby-on-rails-3 scope arel

由于信息安全限制,我在产品上有默认范围。

class Product < ActiveRecord::Base
  has_many :photos

  default_scope where('visible = 1')
end

然而,在我的相关照片模型中,我还必须找到不应该看到的产品。

class Photo < ActiveRecord::Base
  belongs_to :product
end

my_photo.product

在其他情况下,我可以使用unscoped来绕过default_scope,例如在Product.unscoped.find_by_title('abc')。但是:

如何在使用记录关联时删除范围?

my_photo.unscoped.product没有意义,因为my_photo没有名为unscoped的方法。 my_photo.product.unscoped也没有意义,因为my_photo.product可能已经是零。

7 个答案:

答案 0 :(得分:61)

喔。我骗了自己。以为以下方法不起作用......但确实如此:

Product.unscoped do
  my_photo.product
end

请注意,您必须使用应绕过的default_scope在模型上调用unscoped。

此外,必须尊重继承。如果class InsuranceProduct < Product中有class FinancialProduct < Productdefault_scope以及Product,则以下两种组合都可以使用:

InsuranceProduct.unscoped do
  my_record.insurance_products
end

FinancialProduct.unscoped do
  my_record.financial_products
end

Product.unscoped do
  my_record.products
end

但是,以下无效,但范围在Product中定义:

Product.unscoped do
  my_record.financial_products
end

我猜这是Ruby / Rails中STI的另一个怪癖。

答案 1 :(得分:50)

另一个选择是覆盖getter方法和unscope super:

class Photo < ActiveRecord::Base
  belongs_to :product

  def product
    Product.unscoped{ super }
  end
end

我遇到了一个相同的情况,我有一个相关的模型需要无范围,但在几乎所有其他情况下,它需要默认范围。如果您在多个地方使用关联吸气器,这应该可以节省额外的无范围调用。

答案 2 :(得分:24)

我可能有点迟到了,但不久前我发现自己处于相同的状况,我写了一个宝石来轻松做到这一点:unscoped_associations

用法:

belongs_to :user, unscoped: true

支持:

  • belongs_to的
  • HAS_ONE
  • 的has_many

也支持多态关联。

答案 3 :(得分:7)

如果您需要一个特定的关联以始终未展开,您可以在定义关联时取消它:

belongs_to :product, -> { unscope(where: :visible) }

由于某些原因,我没有正确加载特定的where密钥,所以我只是解开了整个where,这是我的情况下碰巧遇到的另一种选择:

belongs_to :product, -> { unscope(:where) }

其他答案也值得一看,但这是Rails 4.1 +的另一个选择。

答案 4 :(得分:5)

在Rails 4中,您可以使用与不受欢迎的过滤器的明确不合作关联,即my_photo.product.unscope(where: :visible)

答案 5 :(得分:1)

这不是关于主题,而是关于ActiveRecord#的问题变成:我们(希望)用初始化器修复它

 class ActiveRecord::Base

   def becomes_with_association_cache(klass)
     became = becomes_without_association_cache(klass)
     became.instance_variable_set("@association_cache", @association_cache)
     became
   end
   alias_method_chain :becomes, :association_cache

 end

https://gist.github.com/2478161

答案 6 :(得分:0)

新答案

This question应该帮助您弄清楚如何绕过关联的默认where子句。

值得重复的是,如果你经常不得不避开范围那么它可能应该是默认值。创建一个visible非默认范围,并在您的关联中明确使用它。