Adds attribute protection to properties
Public Facing * through either :protected or :accessible8 flags * prevents protected attributes from being set in mass assignment Developer Facing * refactors #initialize and #update_attribute_without_saving to use same private methods to set attributes on ExtendedDocument * adds new mixin to do protection Signed-off-by: Tapajós <tapajos@gmail.com>
This commit is contained in:
parent
58d621d399
commit
b5d09afef5
5 changed files with 191 additions and 12 deletions
74
lib/couchrest/mixins/attribute_protection.rb
Normal file
74
lib/couchrest/mixins/attribute_protection.rb
Normal file
|
@ -0,0 +1,74 @@
|
|||
module CouchRest
|
||||
module Mixins
|
||||
module AttributeProtection
|
||||
# Attribute protection from mass assignment to CouchRest properties
|
||||
#
|
||||
# Protected methods will be removed from
|
||||
# * new
|
||||
# * update_attributes
|
||||
# * upate_attributes_without_saving
|
||||
# * attributes=
|
||||
#
|
||||
# There are two modes of protection
|
||||
# 1) Declare accessible poperties, assume all the rest are protected
|
||||
# property :name, :accessible => true
|
||||
# property :admin # this will be automatically protected
|
||||
#
|
||||
# 2) Declare protected properties, assume all the rest are accessible
|
||||
# property :name # this will not be protected
|
||||
# property :admin, :protected => true
|
||||
#
|
||||
# Note: you cannot set both flags in a single class
|
||||
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def accessible_properties
|
||||
properties.select { |prop| prop.options[:accessible] }
|
||||
end
|
||||
|
||||
def protected_properties
|
||||
properties.select { |prop| prop.options[:protected] }
|
||||
end
|
||||
end
|
||||
|
||||
def accessible_properties
|
||||
self.class.accessible_properties
|
||||
end
|
||||
|
||||
def protected_properties
|
||||
self.class.protected_properties
|
||||
end
|
||||
|
||||
def remove_protected_attributes(attributes)
|
||||
protected_names = properties_to_remove_from_mass_assignment.map { |prop| prop.name }
|
||||
return attributes if protected_names.empty?
|
||||
|
||||
attributes.reject! do |key, value|
|
||||
protected_names.include?(key.to_s)
|
||||
end
|
||||
|
||||
attributes || {}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def properties_to_remove_from_mass_assignment
|
||||
has_protected = !protected_properties.empty?
|
||||
has_accessible = !accessible_properties.empty?
|
||||
|
||||
if !has_protected && !has_accessible
|
||||
[]
|
||||
elsif has_protected && !has_accessible
|
||||
protected_properties
|
||||
elsif has_accessible && !has_protected
|
||||
properties.reject { |prop| prop.options[:accessible] }
|
||||
else
|
||||
raise "Set either :accessible or :protected for #{self.class}, but not both"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,3 +6,4 @@ require File.join(File.dirname(__FILE__), 'validation')
|
|||
require File.join(File.dirname(__FILE__), 'extended_attachments')
|
||||
require File.join(File.dirname(__FILE__), 'class_proxy')
|
||||
require File.join(File.dirname(__FILE__), 'collection')
|
||||
require File.join(File.dirname(__FILE__), 'attribute_protection')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue