Module Access::RequirePrivilege::InstanceMethods
In: lib/access_require_privilege.rb

Methods

Public Instance methods

Returns true if the user has permission to cause the specific action, in the sense of +require_privilege :for_action+ e.g., blog.permits_action?( :update ).

If the action is :destroy, we also check whether some associated object (via :belongs_to) has a :to_dissociate_as requirement that would prevent destruction.

See also permits_create? at the class level.

[Source]

     # File lib/access_require_privilege.rb, line 709
709:       def permits_action?( event_name, user = User.current )
710: 
711:         callback_name = EVENT_CALLBACK_KEYS[ event_name ]
712:         priv = self.class.callback_privilege( callback_name )
713:         self_permits = priv.nil? || self.permits?( priv, user )
714: 
715:         return false if !self_permits
716:         return self_permits unless event_name == :destroy
717: 
718:         self.class.reflect_on_all_associations( :belongs_to ).each do |assoc|
719:           klass = self.class.class_for_associate( assoc.name )
720:           dissoc_priv = klass.dissociate_privilege(self.class.name, assoc.name)
721:           if !dissoc_priv.nil?
722:             associate = self.send assoc.name
723:             if !associate.nil?
724:               return false unless associate.permits?( dissoc_priv, user )
725:             end
726:           end
727:         end
728: 
729:         return true
730:         
731:       end

Returns true if the user has permission to run a callback, e.g., blog.permits_at_callback?( :before_create )

[Source]

     # File lib/access_require_privilege.rb, line 694
694:       def permits_at_callback?( callback_name, user = User.current )
695:         priv = self.class.callback_privilege( callback_name )
696:         return priv.nil? || self.permits?( priv, user )
697:       end

Returns true if the user has permission to update attribute attr, named by a symbol, e.g. blog.permits_update_attr?( :name )

[Source]

     # File lib/access_require_privilege.rb, line 686
686:       def permits_update_attr?( attr, user = User.current )
687:         priv = update_attr_privilege( attr )
688:         return priv.nil? || self.permits?( priv, user )
689:       end

If, say, we have:

  class Blog; belongs_to :owner_firm; end

then +some_blog.permitted_associates :owner_firm+ will return all firms that would allow us to do:

  blog.owner_firm = the_firm
  blog.save!

without a PermissionFailure.

Additional keyword arguments may be supplied.

If :conditions are supplied, they augment the permitted_associates conditions, so the ‘name like ?’ example above will return only permitted firms whose name matches the pattern.

Other keyword arguments are passed unaltered to the underlying find operation.

As a matter of implementation detail, there are three requirements that a permitted associate must meet:

  • If the association‘s foreign key (e.g. ‘owner_firm_id’) is also an access control key, and the object‘s class (e.g. ‘Blog’ above) requires permission for_action +:create+, or +:update+, we look at the values given for owner_firm_id in User.current‘s +:create+ or +:update+ permissions on the Blog class.
  • Alternatively Firm may require_privilege +:to_associate_as+ +’Blog#owner_firm_id’+ — in which case, we look for firms on which User.current has the relevant privilege.

If both the above checks apply, we only return firms that pass both tests. Finally:

  • Firm may require_privilege +:to_dissociate_as+ +’Blog#owner_firm_id’+ — which can keep us from changing the association, once it is already set. If such a condition applies, then the current value for the associate is the only permitted value.

[Source]

     # File lib/access_require_privilege.rb, line 784
784:       def permitted_associates( assoc_name, opts = {} )
785: 
786:         # Start with SQL condtions supplied by the user, if any
787: 
788:         sql_conds = []
789:         opts = opts.dup
790:         if opts.has_key?( :conditions )
791:           sql_conds << sanitize_sql( opts.delete( :conditions ))
792:         end
793:         user = opts.delete( :for_user ) || User.current
794: 
795:         # Next, add check for the current-associate special case,
796:         # if it applies...
797: 
798:         klass = self.class.class_for_associate( assoc_name )
799:         if klass.nil?
800:           raise ArgumentError, "No belongs_to #{assoc_name} for this class"
801:         end
802:         
803:         dissoc_priv = klass.dissociate_privilege( self.class.name, assoc_name )
804: 
805:         unless dissoc_priv.nil?
806:           current_associate = self.send assoc_name
807:           unless current_associate.permits?( dissoc_priv, user )
808: 
809:             # Don't just return [current_associate] here out of fanatical
810:             # devotion to correctness --- it may not meet additional
811:             # conditions supplied by the user, in which case the correct
812:             # return value is [].
813: 
814:             sql_conds << sanitize_sql( [ 'id = ?', current_associate.id ] )
815:           end
816:         end
817: 
818:         # Next, add check for :to_associate privilege, if any
819: 
820:         assoc_priv = klass.associate_privilege( self.class.name, assoc_name )
821:         
822:         unless assoc_priv.nil?
823:           sql_conds << klass.where_permits( assoc_priv, user )
824:         end
825: 
826:         # Lastly, if foreign key is an access control key, and we don't
827:         # have wildcard permissions, then only certain values will allow
828:         # a save...
829: 
830:         reflection = self.class.reflect_on_association( assoc_name )
831:         foreign_key = reflection.primary_key_name.to_s
832: 
833:         if self.class.access_control_keys.include?( foreign_key )
834: 
835:           save_event_type = new_record? ? :create : :update
836: 
837:           callback_name = EVENT_CALLBACK_KEYS[ save_event_type ]
838:           privilege = self.class.callback_privilege( callback_name )
839: 
840:           perm_access_key = 'target_' + foreign_key
841: 
842:           unless privilege.nil?
843: 
844:             all_perms = user.all_permissions( privilege, self.class )
845:             all_ids = all_perms.collect{ |perm| perm[perm_access_key] }
846: 
847:             if all_ids == []
848:               sql_conds << '2 + 2 = 5'
849:             elsif !all_ids.any?{ |id| id.nil? }
850:               sql_conds << sanitize_sql([ "#{klass.table_name}.id in (?)",
851:                                           all_ids ])
852:             end
853:             
854:           end
855:           
856:         end
857: 
858:         # Now have a bunch of conditions, and 'em together and do it...
859: 
860:         real_conds = sql_conds.join( ' and ' )
861: 
862:         return klass.find( :all, opts.merge!( :conditions => real_conds ) )
863:         
864:       end

[Validate]