class Protector::DSL::Meta::Box
Single DSL
evaluation result
Attributes
Public Class Methods
@param model [Class] The class of protected entity @param fields [Array<String>] All the fields the model has @param subject [Object] Restriction subject @param entry [Object] An instance of the model @param blocks [Array<Proc>] An array of ‘protect` blocks
# File lib/protector/dsl.rb, line 15 def initialize(adapter, model, fields, subject, entry, blocks) @adapter = adapter @model = model @fields = fields @access = {} @scope_procs = [] @destroyable = false Protector.insecurely do blocks.each do |b| case b.arity when 2 instance_exec(subject, entry, &b) when 1 instance_exec(subject, &b) else instance_exec(&b) end end end end
Public Instance Methods
Enables action for given fields.
Built-in possible actions are: ‘:read`, `:update`, `:create`. You can pass any other actions you want to use with {#can?} afterwards.
**The method enables action for every field if ‘fields` splat is empty.** Use {#cannot} to exclude some of them afterwards.
The list of fields can be given as a Hash. In this form you can pass ‘Range` or `Proc` as a value. First will make Protector
check against value inclusion. The latter will make it evaluate given lambda (which is supposed to return true or false determining if the value should validate or not).
@param action [Symbol] Action to allow @param fields [String, Hash, Array] Splat of fields to allow action with
@see can?
@example
protect do can :read # Can read any field can :read, 'f1' # Can read `f1` field can :read, %w(f2 f3) # Can read `f2`, `f3` fields can :update, f1: 1..2 # Can update f1 field with values between 1 and 2 # Can create f1 field with value equal to 'olo' can :create, f1: lambda{|x| x == 'olo'} end
# File lib/protector/dsl.rb, line 105 def can(action, *fields) action = deprecate_actions(action) return @destroyable = true if action == :destroy @access[action] = {} unless @access[action] if fields.length == 0 @fields.each { |f| @access[action][f.to_s] = nil } else fields.each do |a| if a.is_a?(Array) a.each { |f| @access[action][f.to_s] = nil } elsif a.is_a?(Hash) @access[action].merge!(a.stringify_keys) else @access[action][a.to_s] = nil end end end end
Check whether you can perform custom action for given fields (or generally if no ‘field` given)
@param [Symbol] action Action to check against @param [String] field Field to check against
# File lib/protector/dsl.rb, line 192 def can?(action, field=false) return destroyable? if action == :destroy return false unless @access[action] return !@access[action].empty? unless field @access[action].key?(field.to_s) end
Disables action for given fields.
Works similar (but oppositely) to {#can}.
@param action [Symbol] Action to disallow @param fields [String, Hash, Array] Splat of fields to disallow action with
# File lib/protector/dsl.rb, line 136 def cannot(action, *fields) action = deprecate_actions(action) return @destroyable = false if action == :destroy return unless @access[action] if fields.length == 0 @access.delete(action) else fields.each do |a| if a.is_a?(Array) a.each { |f| @access[action].delete(f.to_s) } else @access[action].delete(a.to_s) end end @access.delete(action) if @access[action].empty? end end
# File lib/protector/dsl.rb, line 201 def cannot?(*args) !can?(*args) end
Checks whether you can create a model with given field in context of current subject
# File lib/protector/dsl.rb, line 166 def creatable?(fields=false) modifiable? :create, fields end
Checks whether you can destroy a model in context of current subject
# File lib/protector/dsl.rb, line 184 def destroyable? @destroyable end
# File lib/protector/dsl.rb, line 71 def eval_scope_procs(instance) scope_procs.reduce(instance) do |relation, scope_proc| relation.instance_eval(&scope_proc) end end
# File lib/protector/dsl.rb, line 170 def first_uncreatable_field(fields) first_unmodifiable_field :create, fields end
# File lib/protector/dsl.rb, line 179 def first_unupdatable_field(fields) first_unmodifiable_field :update, fields end
Checks whether given field of a model is readable in context of current subject
# File lib/protector/dsl.rb, line 161 def readable?(field) @access[:read] && @access[:read].key?(field.to_s) end
# File lib/protector/dsl.rb, line 65 def relation return false unless scoped? @relation ||= eval_scope_procs @model end
Activates the scope that selections will be filtered with
@yield Calls given model methods before the selection
@example
protect do # You can select nothing! scope { none } end
# File lib/protector/dsl.rb, line 55 def scope(&block) @scope_procs << block @relation = false end
# File lib/protector/dsl.rb, line 60 def scope_procs return [@adapter.null_proc] if @scope_procs.empty? && Protector.config.paranoid? @scope_procs end
Checks whether protection with given subject has the selection scope defined
# File lib/protector/dsl.rb, line 39 def scoped? Protector.config.paranoid? || @scope_procs.length > 0 end
Checks whether you can update a model with given field in context of current subject
# File lib/protector/dsl.rb, line 175 def updatable?(fields=false) modifiable? :update, fields end
Private Instance Methods
# File lib/protector/dsl.rb, line 233 def deprecate_actions(action) if action == :view ActiveSupport::Deprecation.warn ":view rule has been deprecated and replaced with :read! "+ "Starting from version 1.0 :view will be treated as a custom rule." :read else action end end
# File lib/protector/dsl.rb, line 207 def first_unmodifiable_field(part, fields) return (fields.keys.first || '-') unless @access[part] diff = fields.keys - @access[part].keys return diff.first if diff.length > 0 fields.each do |k, v| case x = @access[part][k] when Enumerable return k unless x.include?(v) when Proc return k unless Protector.insecurely{ x.call(v) } else return k if !x.nil? && x != v end end false end
# File lib/protector/dsl.rb, line 227 def modifiable?(part, fields=false) return false unless @access[part] return false if fields && first_unmodifiable_field(part, fields) true end