模型与可交换模块范围的关联

时间:2016-06-01 13:21:01

标签: ruby-on-rails

我有一个易受关注的问题,允许用户丢弃("删除")某些事情。

问题在于,即使该项目可以被删除,如果您查看较旧的内容,仍然需要引用该项目。如果您现在这样做,它就不会找到该对象,因为我已将default_scope更改为仅显示已删除错误的位置。

这是我的可销售模块:

module Trashable
  extend ActiveSupport::Concern

  included do
    default_scope   { where(trashed: false) }
    scope :trashed, -> { unscoped.where(trashed: true) }
    validates :trashed, inclusion: { in: [true, false] }
  end

  def trash
    update_attribute :trashed, true
  end
end

现在我有一个Order模型,您可以在其中查看订单。如果我们例如垃圾产品,我仍然希望用户能够查看他们的订单并查看产品。

现在我无法使用模型关联来访问它,例如:

has_many :products并使其包含trashed为false和true的位置。

有人知道如何实现这个目标吗?

2 个答案:

答案 0 :(得分:1)

你可以通过几种方式实现这一目标,这就是我所知道的

解决方案1 ​​像这样定义with_trashed

module Trashable
  extend ActiveSupport::Concern

  included do
    default_scope   { where(trashed: false) }
    scope :trashed, -> { unscoped.where(trashed: true) }

    # Define a new scope here
    scope :with_trashed, -> { unscope(where: :trashed) }
    validates :trashed, inclusion: { in: [true, false] }
  end

  def trash
    update_attribute :trashed, true
  end
end

然后你就可以使用它:

order.products.with_trashed

解决方案2 定义未范围的类

class UnscopedProduct < Product
  self.default_scopes = []
  belongs_to :order
end

class Order < ActiveRecord::Base
  has_many :products
  has_many :unscoped_products, foreign_key: :order_id, class_name: "UnscopedProduct"
end

然后你就可以使用它:

order.unscope_products

根据我的经验,我会使用解决方案1,但有一些奇怪的情况,这不再适用,例如,在复杂的查询中,所以请记住解决方案2,它将节省大量时间!

使用Default scope会导致以后复杂查询出现这么多问题。这取决于你!

答案 1 :(得分:0)

你可以做几件事:

  1. 正如评论中提到的那样,您应该使用Acts as Paranoid Gem,这正是出于此目的。使用它,您可以使用方法with_deletedonly_deleted,它们也会返回相关的已删除对象。

  2. 您不能像上面那样简单地使用unscoped。 Unscoped将删除所有条件,而不仅仅是trashed: false。您还可以尝试创建另一个范围,该范围返回已删除的对象,并将第二个范围中找到的对象与第一个范围合并。

  3. scope_1_results + scope_2_results

    如果您使用的是Rails 5,则还可以OR在Rails 4.x或更低版本中无法实现的范围。