views:

13

answers:

2

I'm currently using Declarative Authorization on my application, and trying to catch Exceptions from type Authorization::NotAuthorized.

I have an Entity that has a category. Depending on the role a user can create a new category when creating this entity. At my :before_validation callback I assign the category and want to be able to catch the authorization exception in case he doesn't have permission.

I could check it's role and make a conditional instruction, but then would have to write all the roles.

Exception is being thrown, but I'm not able to catch it, at the "new" instruction.

Code follows:

# Model
before_validation :set_category

def category_name
    @category_name ||= category.name unless category.nil?
    @category_name
end

def category_name=(name)
    name.strip!
    name.downcase!
    @category_name = name
end

def set_category
    if @category_name and not company.blank?
        lookup_category = company.categories.not_deleted.find_by_name(@category_name)
        begin 
            category = lookup_category.blank? ? company.categories.new(:name => @category_name) : lookup_category
        rescue Authorization::NotAuthorized
           errors.add(:category, I18n.t('activerecord.errors.messages.exclusion'))
        end
    end
end

# Controller
def create
    @ticket = current_user.created_tickets.new(params[:ticket])
    if @ticket.save  # Line 88
    ...

Exception stack trace:

Authorization::NotAuthorized (No matching rules found for create for #<User id: 36,..."> (roles [:Requester], privileges [:create], context :categories).):
  /Library/Ruby/Gems/1.8/gems/declarative_authorization-0.4.1/lib/declarative_authorization/authorization.rb:168:in `permit!'
  /Library/Ruby/Gems/1.8/gems/declarative_authorization-0.4.1/lib/declarative_authorization/in_model.rb:131:in `using_access_control'
  /Library/Ruby/Gems/1.8/gems/after_commit-1.0.7/lib/after_commit/connection_adapters.rb:12:in `transaction'
  /Library/Ruby/Gems/1.8/gems/after_commit-1.0.7/lib/after_commit/connection_adapters.rb:12:in `transaction'
  app/controllers/tickets_controller.rb:88:in `create'

Debugger goes inside the block:

# Debugger
lookup_category = company.categories.not_deleted.find_by_name(@category_name)
(rdb:3) list
[275, 284] in /Users/Pedro/projects/trunk/app/models/ticket.rb
   275    
   276    def set_category
   277      if @category_name and not self.company.blank?
   278        begin
   279          debugger
=> 280          lookup_category = company.categories.not_deleted.find_by_name(@category_name)
   281          self.category = lookup_category.blank? ? company.categories.new(:name => @category_name) : lookup_category
   282        rescue Authorization::NotAuthorized
   283          self.errors.add(:category, I18n.t('activerecord.errors.messages.exclusion'))
   284        end
(rdb:3) n
/Users/Pedro/projects/trunk/app/models/ticket.rb:281
self.category = lookup_category.blank? ? company.categories.new(:name => @category_name) : lookup_category
(rdb:3) list
[276, 285] in /Users/Pedro/projects/trunk/app/models/ticket.rb
   276    def set_category
   277      if @category_name and not self.company.blank?
   278        begin
   279          debugger
   280          lookup_category = company.categories.not_deleted.find_by_name(@category_name)
=> 281          self.category = lookup_category.blank? ? company.categories.new(:name => @category_name) : lookup_category
   282        rescue Authorization::NotAuthorized
   283          self.errors.add(:category, I18n.t('activerecord.errors.messages.exclusion'))
   284        end
   285      end
(rdb:3) n
/Users/Pedro/.gem/ruby/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb:94
break result if terminator.call(result, object)
(rdb:3) list
[89, 98] in /Users/Pedro/.gem/ruby/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb
   89          unless block_given?
   90            send(enumerator) { |callback| callback.call(object) }
   91          else
   92            send(enumerator) do |callback|
   93              result = callback.call(object)
=> 94              break result if terminator.call(result, object)
   95            end
   96          end
   97        end
   98  
(rdb:3)
A: 

I'd say that it's breaking outside the begin ... rescue block and therefore not caught by the rescue. Try to do the same rescue on line 88 of your controller.

If you want to handle this in the validation process, maybe try to do a test on the roles or permissions of the user before creating your object instead of catching the exception that will only be thrown on creation.

marcgg
Exception is raised inside the begin...rescue block. I've ran debugger
Yise
@yise: are you sure? there's nothing related to controller actions in there, and if you don't have rights on :create, you wouldn't even go into the action calling this block
marcgg
@marcgg: Added debugger log
Yise
@yise: Maybe it's because I lack cafeine right now, but I don't see any sign of the error being raised in the block
marcgg
@marcgg: Exactly.. there is no sign. But an exception is raised. And it's on that line of code for sure because if I comment it everything goes ok...
Yise
@yise: My call would be that you're not looking at the line causing the problem. Maybe removing this line cause the validations to fail and therefore skip the saving process? Maybe this line has some other effects? I don't know since I would need to step through all your code to figure that one out ^^
marcgg
A: 

It's not possible to catch the exception on a before callback. The best way I found to do this kind of validation is:

# Model code
begin 
    User.with_permissions_to :create, :categories  # Raises exception if not permitted
    ... do whatever you want
rescue
    ... do whatever you want
end

Thanks for all the help

Yise