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

cri*_*spy 62 scope ruby-on-rails arel ruby-on-rails-3

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

class Product < ActiveRecord::Base
  has_many :photos

  default_scope where('visible = 1')
end
Run Code Online (Sandbox Code Playgroud)

但是,在我的相关照片模型中,我还必须找到不可见的产品.

class Photo < ActiveRecord::Base
  belongs_to :product
end

my_photo.product
Run Code Online (Sandbox Code Playgroud)

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

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

my_photo.unscoped.product因为my_photo没有调用方法,所以没有意义unscoped.也没有my_photo.product.unscoped任何意义,因为my_photo.product可能已经是零.

cri*_*spy 62

哦.我骗了自己.认为以下不起作用......但确实如此:

Product.unscoped do
  my_photo.product
end
Run Code Online (Sandbox Code Playgroud)

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

此外,必须尊重继承.如果你有class InsuranceProduct < Productclass FinancialProduct < Product一个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
Run Code Online (Sandbox Code Playgroud)

但是,尽管范围定义如下,但以下内容不起作用Product:

Product.unscoped do
  my_record.financial_products
end
Run Code Online (Sandbox Code Playgroud)

我想这是Ruby/Rails中STI的另一个怪癖.

  • 但是这个解决方案有一个问题:查询必须在块内部执行,因此必须确保在`has_many`关系上调用`#all`或`#to_a`.详情请见:https://github.com/rails/rails/issues/5591 (5认同)

joh*_*ley 50

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

class Photo < ActiveRecord::Base
  belongs_to :product

  def product
    Product.unscoped{ super }
  end
end
Run Code Online (Sandbox Code Playgroud)

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

  • 谢谢!虽然感觉非常hacky ...希望有一种方法可以编写`belongs_to:product,:unscoped => true`,这会阻止我们在每个模型中覆盖该方法. (4认同)

mar*_*ets 24

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

用法:

belongs_to :user, unscoped: true
Run Code Online (Sandbox Code Playgroud)

支持:

  • 属于
  • HAS_ONE
  • 有很多

还支持多态关联.

  • 我很惊讶这需要宝石!这应该是一个rails默认功能! (7认同)

Chr*_*ers 6

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

belongs_to :product, -> { unscope(where: :visible) }
Run Code Online (Sandbox Code Playgroud)

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

belongs_to :product, -> { unscope(:where) }
Run Code Online (Sandbox Code Playgroud)

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

  • 使用belongs_to :product, -&gt; { unscope(:where) } 时要非常小心,它会删除整个范围,所以如果你有 something.product 它只会返回数据库中的第一个产品。杀死 where id =... (4认同)

Kam*_*ran 5

在Rails 4中,您可以将关联与不合需要的过滤器的显式取消作用域结合使用,即 my_photo.product.unscope(where: :visible)