我应该使用控制器中的过滤器还是模型中的回调来阻止记录编辑?

时间:2011-02-11 03:57:22

标签: ruby-on-rails model-view-controller ruby-on-rails-3

为了保持数据完整性,我需要防止某些模型在某些事件后被修改。例如,产品售出后不应该被注销。

我总是在控制器中实现它,就像这样(伪代码):

def ProductsController < ApplicationController
  before_filter require_product_not_sold, :only => [ :write_off ]

private
  def require_product_not_sold
    if @product.sold?
      redirect_to @product, :error => "You can't write off a product that has been sold"
    end
  end
end

让我感到震惊的是,我也可以在模型中做到这一点。像这样:

def Product < ActiveRecord::Base
  before_update :require_product_not_sold

private
  def require_product_not_sold
    if self.written_off_changed?
      # Add an error, fail validation etc. Prevent the model from saving
    end
  end
end

还要考虑可能有几个不同的事件需要产品尚未售出。

我喜欢控制器方法 - 您可以设置有意义的Flash消息,而不是添加验证错误。但感觉这个代码应该在模型中(例如,如果我想在我的Rails应用程序之外使用该模型)。

  1. 我做错了吗?
  2. 在我的模型中处理这个有什么好处?
  3. 在我的模型中处理此问题有哪些缺点?
  4. 如果我在模型中处理它,我真的应该使用validates而不是回调吗?什么是最干净的处理方式?
  5. 感谢您的想法:)

1 个答案:

答案 0 :(得分:2)

根据您的问题,您似乎已经覆盖了这个。理想情况下,模型应该知道如何保护其状态,因为数据对象通常在设计时考虑了可移植性(即使它们永远不会以这种方式使用)。

但在这种情况下,您希望在用户访问模型之前阻止操作。在这种情况下使用模型验证意味着你已经太晚了,用户已经进入并试图注销根据其销售状态永远无法访问的产品,因此已经超出了应有的范围。

所以我觉得理想的答案是“两者兼而有之”。该模型“应该”知道如何保护自己,作为备份,以防它在外部使用。

然而,在现实世界中,我们有不同的优先级和约束,因此我建议在可行的情况下实施您列出的更改,否则将其保存到下一个项目中。

就使用模型回调与验证而言,我认为这是一个棘手的问题,但我会进行验证,因为您可能希望向用户显示一条消息,并且正是为了这个用途而构建验证(我认为这更像是一个友好的和预期的用户错误,而不是与你可能处理不同的敌对或安全相关的错误。

这是否与你一直在考虑的一致?