我目前正在处理的应用程序的逻辑要求Payment
如果status
为open
,则必须是不可编辑的。我看到了两种实现方法:
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
,如何仅为编辑路线添加约束?
答案 0 :(得分:1)
关于Rails解决这个问题的方法,实际上并不是你的建议。
路由 - 您的路由应该只是声明性地声明应用程序的RESTful接口。除非绝对必要,否则他们不应该知道当前的请求。
控制器 - 在控制器中添加业务逻辑会使控制器膨胀并违反DRY。
在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_validation
或before_update
callbacks。此外,请勿向edit
(链接,按钮等)显示状态为Payment
的{{1}}的任何方式。如果用户以某种方式访问您的表单,则显示它,但随后模型中的验证将不允许他们保存它。我认为,在这种情况下,每个人都要对自己的责任负责。
但是,如果您必须从您提供的2个选项中进行选择,我会选择第二个选项。你的第一个选择,在路线中有业务逻辑,似乎不对。它不属于那里,IMO。第二个选项更好,但缺点是您和您的团队成员仍然必须记住他们必须检查open
对象的Payment
属性在触摸之前没有一些价值它。显然,有人会忘记在某些时候这样做。因此,从长远来看,您的系统(系统中的模型)将具有损坏的状态。