Rails cancan和State Machine - 授权状态

时间:2012-12-19 02:30:09

标签: ruby-on-rails ruby authorization cancan state-machine

我最近在我的rails应用程序中使用了两个很棒的gem,state_machine和cancan,但我很好奇将它们干净地集成在一起的最好方法。 目前,我已将状态转换置于按钮上,这些按钮将继续执行控制器授权的操作。这很有效,我可以限制谁可以执行该操作。

我想让用户也能够在编辑表单中更改对象状态。我注意到state_machine将获取散列中的state_event键,以及要执行的操作的值(因此它将遍历所有state_machines回调)。 这可以使用update_attributes中的params哈希传递。奇妙。

但是,只有某些用户应该能够将对象更改为某些状态。我该如何实现呢?这个想法是

params['state_event']=='move_to_x'

应该为某些用户纾困,但允许其他用户。它也让我担心,直到我实现这个是授权部分,一个聪明的用户可以在状态事件中发布任何内容,即使它们也不应该被允许!。

2 个答案:

答案 0 :(得分:1)

你可以用两种方式做到这一点。通过在过渡上设置条件。像这样:

 transition :from => :parked, :to => :idling, :if => :valid_user

在模型中创建valid_user方法。

def valid_user
  if User.current_user.has_role?(xyz)
    do baa
  end
end

(User.current_user.has_role?(xyz))不是有效的测试 - 您需要自己的测试。

或者您可以使用自定义状态机验证:

 state :first_gear, :second_gear do
   validate :speed_is_legal

在文档中发现了一个警告:

http://rdoc.info/github/pluginaweek/state_machine/master/StateMachine/Integrations/ActiveModel

这里有另一篇有趣的帖子:

State Machine, Model Validations and RSpec

我们在应用程序中成功使用这两种方法。

- 为大众编辑 -

考虑关于在模型中使用current_user的评论。我们认为这是重新阅读我们的代码。在我们使用这个的一两个例子中,我们意识到我们可以完全删除current_user方法,从而消除任何安全风险。

我们没有调用User.current_user,而是交换到:

 self.users.first 

这显然假设模型has_many用户。然后,您可以调用此用户的能力

答案 1 :(得分:0)

这实际上并不像我想象的那么糟糕,而且我已经完成了一个让代码相当短的方式,并且将current_user排除在我的模型之外(这么大的优点)。

诀窍是在控制器中再次调用authorize。

基本上

def update
  authorize! params[:object][:state_event].to_sym, @object unless params[:object][:state_event].empty?
  .... etc
end

这样我就可以在Ability.rb中使用别名。因此,可以执行操作的用户将被授权,而无法获得异常的用户将被授权。这也很棒,因为它与我基于按钮的动作使用的能力相同。

唯一需要注意的是,你不能使用@ object.state_transistions来获取用户可以转换到的可用状态列表,但应该可以通过某种辅助方法来实现。

更新:虽然在像图层这样的视图中获取这些状态很容易

我使用简单的表单,所以我只是一个集合输入

 ..... collection: @object.status_transistions.select{|t| can? t.event, @object}

这使得select具有对象可以经历的所有转换,并且用户也被授权执行:)。