70

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

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可能已经为零。

4

7 回答 7

71

哦。我欺骗了自己。认为以下方法行不通......但它确实:

Product.unscoped do
  my_photo.product
end

请注意,您必须在模型上调用 unscoped ,default_scope并且应该绕过 。

此外,必须尊重继承。如果您有class InsuranceProduct < Productandclass FinancialProduct < Product和 a default_scopein 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 的另一个怪癖。

于 2011-01-21T13:08:21.190 回答
54

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

class Photo < ActiveRecord::Base
  belongs_to :product

  def product
    Product.unscoped{ super }
  end
end

我遇到了同样的情况,我有一个需要取消作用域的关联模型,但在几乎所有其他情况下,它都需要默认作用域。如果您在多个地方使用关联 getter,这应该可以节省对 unscoped 的额外调用。

于 2012-06-13T15:43:24.307 回答
28

我参加聚会可能有点晚了,但前段时间我发现自己处于同样的境地,我写了一个 gem 来轻松做到这一点:unscoped_associations

用法:

belongs_to :user, unscoped: true

支持:

  • 属于
  • has_one
  • 有很多

还支持多态关联。

于 2013-11-25T19:17:27.210 回答
17

如果您需要始终取消特定关联的范围,则可以在定义关联时取消范围:

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

出于某种原因,特定where键没有为我正确加载,所以我只是取消了整个 的范围where,这是在我的情况下碰巧解决的另一个选项:

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

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

于 2016-10-29T17:32:51.553 回答
4

在 Rails 4 中,您可以将关联与不受欢迎的过滤器的显式 unscope 一起使用,即my_photo.product.unscope(where: :visible)

于 2016-05-05T14:08:01.423 回答
1

这不是主题,而是关于 ActiveRecord#becomes 的问题:我们(希望)用初始化程序修复了它

类 ActiveRecord::Base

   def become_with_association_cache(klass)
     成为 = become_without_association_cache(klass)
     成为.instance_variable_set("@association_cache", @association_cache)
     变成了
   结尾
   alias_method_chain : 成为, :association_cache

 结尾

https://gist.github.com/2478161

于 2012-04-24T09:21:46.397 回答
0

新答案

这个问题应该可以帮助您弄清楚如何绕过关联的默认 where 子句。

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

于 2011-01-21T11:56:33.023 回答