【问题标题】:Rails 3 default scope, scope with overrideRails 3默认范围,覆盖范围
【发布时间】:2011-08-02 22:09:41
【问题描述】:

我遇到一种情况,现有应用的行为正在发生变化,这让我很头疼。

我的应用有照片。照片有一个状态:"batch", "queue", or "complete"。应用中的所有现有照片都是“完整的”。

99% 的时间我只需要显示完整的照片,并且在所有现有代码库中,我需要将每次调用照片限制为仅显示完整的照片。

但是,在与上传和分类照片相关的屏幕中,我需要能够相当轻松地覆盖默认范围以显示批处理或排队的照片。

像许多其他人一样,我需要找到一种在某些情况下轻松覆盖默认范围的方法。我查看了这些问题(12),但它们似乎没有回答我正在寻找的内容。

我希望工作的代码是这样的:

class Photo < ActiveRecord::Base
  ...
  default_scope where(:status=>'complete')
  scope :batch, unscoped.where(:status=>'batch')
  scope :queue, unscoped.where(:status=>'queue')
  ...
end

但是,这不起作用。我尝试将作用域方法包装在 lambdas 中,但也没有用。

我意识到 default_scope 带有包袱,但如果我不能将它与覆盖一起使用,那么我正在考虑添加 scope :complete ... 并且必须梳理我现有应用程序中对照片的每次调用并添加 .complete过滤未处理的照片。

你会如何解决这个问题?

【问题讨论】:

  • 您的确切代码在 Rails 3.0.9 上对我来说可以正常工作。能否使用控制台运行Photo.scoped.to_sqlPhoto.batch.to_sql并发布输出?
  • @dylan - 我也在 3.0.9 中,批处理范围给出“where (status = 'complete') and (status = 'batch')
  • @klochner :( 是的,我想我意识到这是唯一的方法。****
  • @klochner 太奇怪了...我将他的代码复制并粘贴到一个新的应用程序中,并没有得到冲突的status = ... 部分...
  • @dylan - 仔细检查,我是 3.0.7,也许他们改变了行为?

标签: ruby-on-rails ruby-on-rails-3 activerecord named-scope default-scope


【解决方案1】:

def self.batch
  Photo.unscoped.where(:status=>"batch")
end
本帖比较权威:Overriding a Rails default_scope

【讨论】:

  • 我想到了这个,我也试过了,但后来我遇到了这个问题:user.photos.batch 返回所有照片(因为模型上的 unscoped 调用破坏了关联)。
  • 你在这里搞砸了。您可以添加一个 User::photos 方法,该方法为用户返回未限定范围的照片,否则 default_scope 有点讨厌。
  • 出于好奇,你知道重写 default_scope 方法来改变行为需要什么吗?我有兴趣尝试一下,但不知道从哪里开始。
  • 这里是 rdoc,点击“显示源代码”查看 default_scope 的工作原理:api.rubyonrails.org/classes/ActiveRecord/…
  • 太好了,谢谢!如果其他人有任何想法,我将把这个问题留得更久一点,但如果没有人有任何想法,我会接受你的回答,因为它确实有效。
【解决方案2】:

我试一试。假设您想从默认范围中删除 where 子句(而不仅仅是用另一个值覆盖它)并保持关联,您可以试试这个:

class Photo < ActiveRecord::Base
  default_scope where(:status => 'complete').where(:deleted_at => '').order('id desc')

  def self.without_default_status
    # Get the ActiveRecord::Relation with the default_scope applied.
    photos = scoped.with_default_scope
    # Find the where clause that matches the where clause we want to remove 
    # from the default scope and delete it.
    photos.where_values.delete_if { |query| query.to_sql == "\"photos\".\"status\" = 'complete'" }
    photos
  end

end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    • 1970-01-01
    • 2012-05-01
    • 2014-01-30
    • 1970-01-01
    相关资源
    最近更新 更多