限制编辑基于资源的资源属性

时间:2016-04-28 13:13:23

标签: ruby-on-rails routes

我目前正在处理的应用程序的逻辑要求Payment如果statusopen,则必须是不可编辑的。我看到了两种实现方法:

1路由约束,如:

constraint: lambda { |req| Payment.find(req.id).status != 'open' }

2 PaymentsController#edit中的一个简单条件:

if @payment.status == 'open'
  redirect_to payments_path
end

我应该选择哪种方式? Rails-ish哪个更合适干净?还有其他选择吗?如果我使用第一个选项并使用resources :payments,如何仅为编辑路线添加约束?

2 个答案:

答案 0 :(得分:1)

关于Rails解决这个问题的方法,实际上并不是你的建议。

  1. 路由 - 您的路由应该只是声明性地声明应用程序的RESTful接口。除非绝对必要,否则他们不应该知道当前的请求。

  2. 控制器 - 在控制器中添加业务逻辑会使控制器膨胀并违反DRY。

  3. 在MVC中,模型负责执行业务逻辑。您可以通过自定义验证来处理此问题,例如:

    class Payment
      validates :cannot_be_edited_when_open, on: :update
      def cannot_be_edited_when_open
        errors.add(:status, 'is open. Cannot edit this record.') if self.open?
      end
    end
    

    这将导致对.update的任何调用失败 - 这意味着您可能不需要更改控制器中的任何内容。

    被修改

    处理此问题的另一个地方是授权层 - 这里的关键区别在于如何处理反馈。

    验证失败只会重新呈现表单(API的422 Unprocessable Entity),而授权错误应该清楚地告诉用户“没有你没有权限这样做 - 并且更改输入不会改变“(403 Forbidden)。

    要在CanCan中设置规则,您可以:

    can [:edit, :update], Payment do |payment|
      payment.status !== 'open'
    end  
    

    如果您的业务逻辑允许,您还可以使用哈希条件而不是块来设置它:

    can [:edit, :update], Payment, status: 'not-open'
    

答案 1 :(得分:1)

如果您指定的规则是业务逻辑,即不应使用状态Payment更新open对象,那么正确的方法是添加模型的逻辑。您可以使用before_validationbefore_update callbacks。此外,请勿向edit(链接,按钮等)显示状态为Payment的{​​{1}}的任何方式。如果用户以某种方式访问​​您的表单,则显示它,但随后模型中的验证将不允许他们保存它。我认为,在这种情况下,每个人都要对自己的责任负责。

但是,如果您必须从您提供的2个选项中进行选择,我会选择第二个选项。你的第一个选择,在路线中有业务逻辑,似乎不对。它不属于那里,IMO。第二个选项更好,但缺点是您和您的团队成员仍然必须记住他们必须检查open对象的Payment属性在触摸之前没有一些价值它。显然,有人会忘记在某些时候这样做。因此,从长远来看,您的系统(系统中的模型)将具有损坏的状态。