1

I have a model with a statemachine and i want to limit different states/events/transitions to different users.

How can i access current user and ability in this model?

tonymarschall
  • 3,862
  • 3
  • 29
  • 52
  • I have red http://stackoverflow.com/questions/3293400/access-cancans-can-method-from-a-model but do not understand howto get user (to call user.can?(:update,@article)) into model – tonymarschall Mar 08 '12 at 08:09
  • 1
    See http://stackoverflow.com/questions/1568218/access-to-current-user-from-within-a-model-in-ruby-on-rails ? Passing a user to a model is reasonable, accessing the current specifically is probably an anti-pattern. – Jonah Mar 08 '12 at 08:19

1 Answers1

2

You can define abilities in cancan against any methods provided by the model. State machine transitions are themselves methods provided by the model, so just set up your abilities as you would for any other methods.

For example, given a simple model:

class Order < ActiveRecord::Base

  state_machine :initial => :new do

    event :start_processing do
      transition :new => :processing
    end

    event :complete_order do
      transition :processing => :complete
    end

    event :escalate_order do
      transition :processing => :escalated
    end

    event :complete_escalated_order
      transition :escalated => :complete
    end

    state :new
    state :processing
    state :escalated
    state :complete
  end

end

You might define abilities like this:

class Ability

  if user.role? :orderer
    can [:start_processing, :escalate_order, :complete_order], :orders
  end
  if user.role? :manager
    can :complete_escalated_order, :orders
  end

end

EDIT - I should have added, that you would then use these abilities in your controllers handling the user requests:

class OrdersController < ApplicationController

  def complete
    @order = Order.find_by_ref(params[:id])

    if @order.can_complete_order?
      authorize! :complete_order, @order
      @order.complete_order
    elsif @order.can_complete_escalated_order?
      authorize! :complete_escalated_order, @order
      @order.complete_escalated_order
    else
      redirect_to root_url, :notice => "Order cannot be completed"
    end

    redirect_to my_queue_path, :notice => "Order #{@order.ref} has been marked as complete."

end

Jon
  • 10,678
  • 2
  • 36
  • 48
  • Great! Will test this afternoon. Can you give a hint on howto limit events in a select a user is able to choose from? Currently i am using @item.state_transitions to fetch all possible events. – tonymarschall Mar 08 '12 at 12:52
  • I would probably define what transitions a role is capable of, and then find them through the user's assigned roles. – Jon Mar 08 '12 at 13:08