use I18n for unauthorization messages - closes #103
This commit is contained in:
parent
66314a89f8
commit
a5f838a964
|
@ -49,7 +49,6 @@ module CanCan
|
||||||
#
|
#
|
||||||
# Also see the RSpec Matchers to aid in testing.
|
# Also see the RSpec Matchers to aid in testing.
|
||||||
def can?(action, subject, *extra_args)
|
def can?(action, subject, *extra_args)
|
||||||
raise Error, "Nom nom nom. I eated it." if action == :has && subject == :cheezburger
|
|
||||||
match = relevant_can_definitions(action, subject).detect do |can_definition|
|
match = relevant_can_definitions(action, subject).detect do |can_definition|
|
||||||
can_definition.matches_conditions?(action, subject, extra_args)
|
can_definition.matches_conditions?(action, subject, extra_args)
|
||||||
end
|
end
|
||||||
|
@ -189,9 +188,36 @@ module CanCan
|
||||||
Query.new(subject, relevant_can_definitions_for_query(action, subject))
|
Query.new(subject, relevant_can_definitions_for_query(action, subject))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# See ControllerAdditions#authorize! for documentation.
|
||||||
|
def authorize!(action, subject, *args)
|
||||||
|
message = nil
|
||||||
|
if args.last.kind_of?(Hash) && args.last.has_key?(:message)
|
||||||
|
message = args.pop[:message]
|
||||||
|
end
|
||||||
|
if cannot?(action, subject, *args)
|
||||||
|
message ||= unauthorized_message(action, subject)
|
||||||
|
raise AccessDenied.new(message, action, subject)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def unauthorized_message(action, subject)
|
||||||
|
keys = unauthorized_message_keys(action, subject)
|
||||||
|
message = I18n.translate(nil, :scope => :unauthorized, :default => keys + [""])
|
||||||
|
message.blank? ? nil : message
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Accepts a hash of aliased actions and returns an array of actions which match.
|
def unauthorized_message_keys(action, subject)
|
||||||
|
subject = (subject.class == Class ? subject : subject.class).name.underscore unless subject.kind_of? Symbol
|
||||||
|
[subject, :all].map do |try_subject|
|
||||||
|
[aliases_for_action(action), :manage].flatten.map do |try_action|
|
||||||
|
:"#{try_action}.#{try_subject}"
|
||||||
|
end
|
||||||
|
end.flatten
|
||||||
|
end
|
||||||
|
|
||||||
|
# Accepts an array of actions and returns an array of actions which match.
|
||||||
# This should be called before "matches?" and other checking methods since they
|
# This should be called before "matches?" and other checking methods since they
|
||||||
# rely on the actions to be expanded.
|
# rely on the actions to be expanded.
|
||||||
def expand_actions(actions)
|
def expand_actions(actions)
|
||||||
|
@ -200,6 +226,16 @@ module CanCan
|
||||||
end.flatten
|
end.flatten
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Given an action, it will try to find all of the actions which are aliased to it.
|
||||||
|
# This does the opposite kind of lookup as expand_actions.
|
||||||
|
def aliases_for_action(action)
|
||||||
|
results = [action]
|
||||||
|
aliased_actions.each do |aliased_action, actions|
|
||||||
|
results += aliases_for_action(aliased_action) if actions.include? action
|
||||||
|
end
|
||||||
|
results
|
||||||
|
end
|
||||||
|
|
||||||
def can_definitions
|
def can_definitions
|
||||||
@can_definitions ||= []
|
@can_definitions ||= []
|
||||||
end
|
end
|
||||||
|
|
|
@ -185,12 +185,8 @@ module CanCan
|
||||||
#
|
#
|
||||||
# See the load_and_authorize_resource method to automatically add the authorize! behavior
|
# See the load_and_authorize_resource method to automatically add the authorize! behavior
|
||||||
# to the default RESTful actions.
|
# to the default RESTful actions.
|
||||||
def authorize!(action, subject, *args)
|
def authorize!(*args)
|
||||||
message = nil
|
current_ability.authorize!(*args)
|
||||||
if args.last.kind_of?(Hash) && args.last.has_key?(:message)
|
|
||||||
message = args.pop[:message]
|
|
||||||
end
|
|
||||||
raise AccessDenied.new(message, action, subject) if cannot?(action, subject, *args)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def unauthorized!(message = nil)
|
def unauthorized!(message = nil)
|
||||||
|
|
|
@ -157,18 +157,7 @@ describe CanCan::Ability do
|
||||||
@ability.can?(:read, 123).should be_false
|
@ability.can?(:read, 123).should be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should support block on 'cannot' method" do
|
|
||||||
@ability.can :read, :all
|
|
||||||
@ability.cannot :read, Integer do |int|
|
|
||||||
int > 5
|
|
||||||
end
|
|
||||||
@ability.can?(:read, "foo").should be_true
|
|
||||||
@ability.can?(:read, 3).should be_true
|
|
||||||
@ability.can?(:read, 123).should be_false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should pass to previous can definition, if block returns false or nil" do
|
it "should pass to previous can definition, if block returns false or nil" do
|
||||||
#same as previous
|
|
||||||
@ability.can :read, :all
|
@ability.can :read, :all
|
||||||
@ability.cannot :read, Integer do |int|
|
@ability.cannot :read, Integer do |int|
|
||||||
int > 10 ? nil : ( int > 5 )
|
int > 10 ? nil : ( int > 5 )
|
||||||
|
@ -177,7 +166,6 @@ describe CanCan::Ability do
|
||||||
@ability.can?(:read, 3).should be_true
|
@ability.can?(:read, 3).should be_true
|
||||||
@ability.can?(:read, 8).should be_false
|
@ability.can?(:read, 8).should be_false
|
||||||
@ability.can?(:read, 123).should be_true
|
@ability.can?(:read, 123).should be_true
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should always return `false` for single cannot definition" do
|
it "should always return `false` for single cannot definition" do
|
||||||
|
@ -262,9 +250,39 @@ describe CanCan::Ability do
|
||||||
@ability.can?(:read, Array).should be_true
|
@ability.can?(:read, Array).should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should has eated cheezburger" do
|
describe "unauthorized message" do
|
||||||
lambda {
|
after(:each) do
|
||||||
@ability.can? :has, :cheezburger
|
I18n.backend = nil
|
||||||
}.should raise_error(CanCan::Error, "Nom nom nom. I eated it.")
|
end
|
||||||
|
|
||||||
|
it "should use action/subject in i18n" do
|
||||||
|
I18n.backend.store_translations :en, :unauthorized => {:update => {:array => "foo"}}
|
||||||
|
@ability.unauthorized_message(:update, Array).should == "foo"
|
||||||
|
@ability.unauthorized_message(:update, [1, 2, 3]).should == "foo"
|
||||||
|
@ability.unauthorized_message(:update, :missing).should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should use symbol as subject directly" do
|
||||||
|
I18n.backend.store_translations :en, :unauthorized => {:has => {:cheezburger => "Nom nom nom. I eated it."}}
|
||||||
|
@ability.unauthorized_message(:has, :cheezburger).should == "Nom nom nom. I eated it."
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should fall back to 'manage' and 'all'" do
|
||||||
|
I18n.backend.store_translations :en, :unauthorized => {
|
||||||
|
:manage => {:all => "manage all", :array => "manage array"},
|
||||||
|
:update => {:all => "update all", :array => "update array"}
|
||||||
|
}
|
||||||
|
@ability.unauthorized_message(:update, Array).should == "update array"
|
||||||
|
@ability.unauthorized_message(:update, Hash).should == "update all"
|
||||||
|
@ability.unauthorized_message(:foo, Array).should == "manage array"
|
||||||
|
@ability.unauthorized_message(:foo, Hash).should == "manage all"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should follow aliased actions" do
|
||||||
|
I18n.backend.store_translations :en, :unauthorized => {:modify => {:array => "modify array"}}
|
||||||
|
@ability.alias_action :update, :to => :modify
|
||||||
|
@ability.unauthorized_message(:update, Array).should == "modify array"
|
||||||
|
@ability.unauthorized_message(:edit, Array).should == "modify array"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,7 @@ describe CanCan::ControllerAdditions do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should raise access denied exception if ability us unauthorized to perform a certain action" do
|
it "should raise access denied exception if ability us unauthorized to perform a certain action" do
|
||||||
|
# TODO this should probably be moved into Ability spec
|
||||||
begin
|
begin
|
||||||
@controller.authorize! :read, :foo, 1, 2, 3, :message => "Access denied!"
|
@controller.authorize! :read, :foo, 1, 2, 3, :message => "Access denied!"
|
||||||
rescue CanCan::AccessDenied => e
|
rescue CanCan::AccessDenied => e
|
||||||
|
|
Loading…
Reference in New Issue
Block a user