From ec616ae75b69996d1cbe0163be124274dcfb0eb0 Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Thu, 30 Dec 2010 15:40:53 -0800 Subject: [PATCH] moving accessible_by out into ModelAdditions module --- lib/cancan.rb | 1 + lib/cancan/exceptions.rb | 3 ++ lib/cancan/model_adapters/abstract_adapter.rb | 5 +++ .../model_adapters/active_record_adapter.rb | 42 ++----------------- .../model_adapters/data_mapper_adapter.rb | 33 +-------------- lib/cancan/model_adapters/mongoid_adapter.rb | 33 +-------------- lib/cancan/model_additions.rb | 31 ++++++++++++++ lib/cancan/query.rb | 4 +- .../model_adapters/mongoid_adapter_spec.rb | 4 +- 9 files changed, 52 insertions(+), 104 deletions(-) create mode 100644 lib/cancan/model_additions.rb diff --git a/lib/cancan.rb b/lib/cancan.rb index a947157..f464e02 100644 --- a/lib/cancan.rb +++ b/lib/cancan.rb @@ -2,6 +2,7 @@ require 'cancan/ability' require 'cancan/rule' require 'cancan/controller_resource' require 'cancan/controller_additions' +require 'cancan/model_additions' require 'cancan/exceptions' require 'cancan/query' require 'cancan/inherited_resource' diff --git a/lib/cancan/exceptions.rb b/lib/cancan/exceptions.rb index 073e3ac..fa676fc 100644 --- a/lib/cancan/exceptions.rb +++ b/lib/cancan/exceptions.rb @@ -2,6 +2,9 @@ module CanCan # A general CanCan exception class Error < StandardError; end + # Raised when behavior is not implemented, usually used in an abstract class. + class NotImplemented < Error; end + # Raised when removed code is called, an alternative solution is provided in message. class ImplementationRemoved < Error; end diff --git a/lib/cancan/model_adapters/abstract_adapter.rb b/lib/cancan/model_adapters/abstract_adapter.rb index d350a4a..4d99233 100644 --- a/lib/cancan/model_adapters/abstract_adapter.rb +++ b/lib/cancan/model_adapters/abstract_adapter.rb @@ -19,6 +19,11 @@ module CanCan @model_class = model_class @rules = rules end + + def database_records + # This should be overridden in a subclass to return records which match @rules + raise NotImplemented, "This model adapter does not support fetching records from the database." + end end end end diff --git a/lib/cancan/model_adapters/active_record_adapter.rb b/lib/cancan/model_adapters/active_record_adapter.rb index a444e2e..a467722 100644 --- a/lib/cancan/model_adapters/active_record_adapter.rb +++ b/lib/cancan/model_adapters/active_record_adapter.rb @@ -6,7 +6,7 @@ module CanCan end # Returns conditions intended to be used inside a database query. Normally you will not call this - # method directly, but instead go through ActiveRecordAdditions#accessible_by. + # method directly, but instead go through ModelAdditions#accessible_by. # # If there is only one "can" definition, a hash of conditions will be returned matching the one defined. # @@ -44,7 +44,7 @@ module CanCan end # Returns the associations used in conditions for the :joins option of a search. - # See ActiveRecordAdditions#accessible_by for use in Active Record. + # See ModelAdditions#accessible_by def joins joins_hash = {} @rules.each do |rule| @@ -114,40 +114,6 @@ module CanCan end end -module CanCan - # This module is automatically included into all Active Record models. - module ActiveRecordAdditions - module ClassMethods - # Returns a scope which fetches only the records that the passed ability - # can perform a given action on. The action defaults to :read. This - # is usually called from a controller and passed the +current_ability+. - # - # @articles = Article.accessible_by(current_ability) - # - # Here only the articles which the user is able to read will be returned. - # If the user does not have permission to read any articles then an empty - # result is returned. Since this is a scope it can be combined with any - # other scopes or pagination. - # - # An alternative action can optionally be passed as a second argument. - # - # @articles = Article.accessible_by(current_ability, :update) - # - # Here only the articles which the user can update are returned. This - # internally uses Ability#conditions method, see that for more information. - def accessible_by(ability, action = :read) - ability.model_adapter(self, action).database_records - end - end - - def self.included(base) - base.extend ClassMethods - end - end -end - -if defined? ActiveRecord - ActiveRecord::Base.class_eval do - include CanCan::ActiveRecordAdditions - end +ActiveRecord::Base.class_eval do + include CanCan::ModelAdditions end diff --git a/lib/cancan/model_adapters/data_mapper_adapter.rb b/lib/cancan/model_adapters/data_mapper_adapter.rb index dd405c9..417bedc 100644 --- a/lib/cancan/model_adapters/data_mapper_adapter.rb +++ b/lib/cancan/model_adapters/data_mapper_adapter.rb @@ -20,35 +20,6 @@ module CanCan end end -module CanCan - module DataMapperAdditions - module ClassMethods - # Returns a scope which fetches only the records that the passed ability - # can perform a given action on. The action defaults to :read. This - # is usually called from a controller and passed the +current_ability+. - # - # @articles = Article.accessible_by(current_ability) - # - # Here only the articles which the user is able to read will be returned. - # If the user does not have permission to read any articles then an empty - # result is returned. Since this is a scope it can be combined with any - # other scopes or pagination. - # - # An alternative action can optionally be passed as a second argument. - # - # @articles = Article.accessible_by(current_ability, :update) - # - # Here only the articles which the user can update are returned. This - # internally uses Ability#conditions method, see that for more information. - def accessible_by(ability, action = :read) - ability.model_adapter(self, action).database_records - end - end - end -end - -if Object.const_defined?('DataMapper') - DataMapper::Model.class_eval do - include CanCan::DataMapperAdditions::ClassMethods - end +DataMapper::Model.class_eval do + include CanCan::ModelAdditions::ClassMethods end diff --git a/lib/cancan/model_adapters/mongoid_adapter.rb b/lib/cancan/model_adapters/mongoid_adapter.rb index 30ca98c..a6f0df4 100644 --- a/lib/cancan/model_adapters/mongoid_adapter.rb +++ b/lib/cancan/model_adapters/mongoid_adapter.rb @@ -2,7 +2,7 @@ module CanCan module ModelAdapters class MongoidAdapter < AbstractAdapter def self.for_class?(model_class) - model_class <= CanCan::MongoidAdditions # there should be a better class to detect with this + model_class <= Mongoid::Document end def database_records @@ -50,35 +50,6 @@ module CanCan alias_method :matches_conditions_hash_without_mongoid_subject?, :matches_conditions_hash? alias_method :matches_conditions_hash?, :matches_conditions_hash_with_mongoid_subject? end - - module MongoidAdditions - module ClassMethods - # Returns a scope which fetches only the records that the passed ability - # can perform a given action on. The action defaults to :read. This - # is usually called from a controller and passed the +current_ability+. - # - # @articles = Article.accessible_by(current_ability) - # - # Here only the articles which the user is able to read will be returned. - # If the user does not have permission to read any articles then an empty - # result is returned. Since this is a scope it can be combined with any - # other scopes or pagination. - # - # An alternative action can optionally be passed as a second argument. - # - # @articles = Article.accessible_by(current_ability, :update) - # - # Here only the articles which the user can update are returned. This - # internally uses Ability#conditions method, see that for more information. - def accessible_by(ability, action = :read) - ability.model_adapter(self, action).database_records - end - end - - def self.included(base) - base.extend ClassMethods - end - end end # Info on monkeypatching Mongoid : @@ -90,7 +61,7 @@ if defined?(::Mongoid) old_block = @_included_block @_included_block = Proc.new do class_eval(&old_block) if old_block - include CanCan::MongoidAdditions + include CanCan::ModelAdditions end end end diff --git a/lib/cancan/model_additions.rb b/lib/cancan/model_additions.rb new file mode 100644 index 0000000..962c2cd --- /dev/null +++ b/lib/cancan/model_additions.rb @@ -0,0 +1,31 @@ +module CanCan + + # This module adds the accessible_by class method to a model. It is included in the model adapters. + module ModelAdditions + module ClassMethods + # Returns a scope which fetches only the records that the passed ability + # can perform a given action on. The action defaults to :read. This + # is usually called from a controller and passed the +current_ability+. + # + # @articles = Article.accessible_by(current_ability) + # + # Here only the articles which the user is able to read will be returned. + # If the user does not have permission to read any articles then an empty + # result is returned. Since this is a scope it can be combined with any + # other scopes or pagination. + # + # An alternative action can optionally be passed as a second argument. + # + # @articles = Article.accessible_by(current_ability, :update) + # + # Here only the articles which the user can update are returned. + def accessible_by(ability, action = :read) + ability.model_adapter(self, action).database_records + end + end + + def self.included(base) + base.extend ClassMethods + end + end +end diff --git a/lib/cancan/query.rb b/lib/cancan/query.rb index 595abff..7ef66fa 100644 --- a/lib/cancan/query.rb +++ b/lib/cancan/query.rb @@ -1,7 +1,7 @@ module CanCan # Generates the sql conditions and association joins for use in ActiveRecord queries. - # Normally you will not use this class directly, but instead through ActiveRecordAdditions#accessible_by. + # Normally you will not use this class directly, but instead through ModelAdditions#accessible_by. class Query def initialize(sanitizer, rules) @sanitizer = sanitizer @@ -9,7 +9,7 @@ module CanCan end # Returns conditions intended to be used inside a database query. Normally you will not call this - # method directly, but instead go through ActiveRecordAdditions#accessible_by. + # method directly, but instead go through ModelAdditions#accessible_by. # # If there is only one "can" definition, a hash of conditions will be returned matching the one defined. # diff --git a/spec/cancan/model_adapters/mongoid_adapter_spec.rb b/spec/cancan/model_adapters/mongoid_adapter_spec.rb index bbf1718..b6d5be2 100644 --- a/spec/cancan/model_adapters/mongoid_adapter_spec.rb +++ b/spec/cancan/model_adapters/mongoid_adapter_spec.rb @@ -3,14 +3,14 @@ if ENV["MODEL_ADAPTER"] == "mongoid" class MongoidCategory include Mongoid::Document - include CanCan::MongoidAdditions + include CanCan::ModelAdditions references_many :mongoid_projects end class MongoidProject include Mongoid::Document - include CanCan::MongoidAdditions + include CanCan::ModelAdditions referenced_in :mongoid_category