Permalink
Browse files

Added actions/events

  • Loading branch information...
1 parent 3d79df9 commit d32174373fd0f0deb4bac33157b45950a893663a Daniel Spangenberg committed Apr 10, 2012
Showing with 184 additions and 159 deletions.
  1. +0 −1 .rvmrc
  2. +2 −1 alfred.gemspec
  3. +1 −2 lib/alfred.rb
  4. +150 −0 lib/alfred/mass_assignment_security.rb
  5. +0 −153 lib/alfred/models.rb
  6. +30 −1 lib/alfred/orm/active_record.rb
  7. +1 −1 lib/alfred/version.rb
View
1 .rvmrc
@@ -1 +0,0 @@
-rvm 1.9.2@alfred --create
View
@@ -13,7 +13,8 @@ Gem::Specification.new do |s|
s.rubyforge_project = "alfred"
- s.add_dependency "rails", "~> 3.1.0.rc"
+ s.add_dependency "rails", ">= 3.1.0"
+ s.add_development_dependency "activemodel"
s.add_development_dependency "activerecord"
s.add_development_dependency "rr"
s.add_development_dependency "rspec"
View
@@ -1,8 +1,6 @@
require 'rails'
module Alfred
- autoload :Models, 'alfred/models'
-
# Automaticly add password_confirmation if password exists.
mattr_accessor :auto_password_confirmation
@@auto_password_confirmation = true
@@ -15,4 +13,5 @@ def self.setup
end
require 'alfred/engine'
+require 'alfred/mass_assignment_security'
require 'alfred/orm/active_record' if defined?(ActiveRecord)
@@ -0,0 +1,150 @@
+require 'active_model'
+
+module Alfred
+ module ActiveModel
+ module MassAssignmentSecurity
+ module ClassMethods
+ # Attributes named in this macro are protected from mass-assignment
+ # whenever attributes are sanitized before assignment. A role for the
+ # attributes is optional, if no role is provided then :default is used.
+ # A role can be defined by using the :as option.
+ #
+ # Mass-assignment to these attributes will simply be ignored, to assign
+ # to them you can use direct writer methods. This is meant to protect
+ # sensitive attributes from being overwritten by malicious users
+ # tampering with URLs or forms. Example:
+ #
+ # class Customer
+ # include ActiveModel::MassAssignmentSecurity
+ # extend Alfred::ActiveModel::MassAssignmentSecurity
+ #
+ # attr_accessor :name, :credit_rating
+ #
+ # alfred_protected :credit_rating
+ # alfred_protected :last_login, as: :trainee
+ #
+ # def assign_attributes(values, options = {})
+ # sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
+ # send("#{k}=", v)
+ # end
+ # end
+ # end
+ #
+ # When using the :default role :
+ #
+ # customer = Customer.new
+ # customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :default)
+ # customer.name # => "Daniel"
+ # customer.credit_rating # => nil
+ # customer.last_login # => nil
+ #
+ # customer.credit_rating = "Average"
+ # customer.credit_rating # => "Average"
+ #
+ # And using the :admin role :
+ #
+ # customer = Customer.new
+ # customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :trainee)
+ # customer.name # => "Daniel"
+ # customer.credit_rating # => "Excellent"
+ # customer.last_login # => nil
+ #
+ # To start from an all-closed default and enable attributes as needed,
+ # have a look at +alfred_accessible+.
+ #
+ # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +alfred_protected+
+ # to sanitize attributes won't provide sufficient protection.
+ def alfred_protected(*args)
+ alfred(:protected, *args)
+ end
+
+ # Specifies a white list of model attributes that can be set via
+ # mass-assignment.
+ #
+ # Like +alfred_protected+, a role for the attributes is optional,
+ # if no role is provided then :default is used. A role can be defined by
+ # using the :as option.
+ #
+ # This is the opposite of the +alfred_protected+ macro: Mass-assignment
+ # will only set attributes in this list, to assign to the rest of
+ # attributes you can use direct writer methods. This is meant to protect
+ # sensitive attributes from being overwritten by malicious users
+ # tampering with URLs or forms. If you'd rather start from an all-open
+ # default and restrict attributes as needed, have a look at
+ # +alfred_protected+.
+ #
+ # class Customer
+ # include ActiveModel::MassAssignmentSecurity
+ # extend Alfred::ActiveModel::MassAssignmentSecurity
+ #
+ # attr_accessor :name, :credit_rating
+ #
+ # alfred_accessible :name
+ # alfred_accessible :credit_rating, as: :admin
+ #
+ # def assign_attributes(values, options = {})
+ # sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
+ # send("#{k}=", v)
+ # end
+ # end
+ # end
+ #
+ # When using the :default role :
+ #
+ # customer = Customer.new
+ # customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :default)
+ # customer.name # => "Daniel"
+ # customer.credit_rating # => nil
+ #
+ # customer.credit_rating = "Average"
+ # customer.credit_rating # => "Average"
+ #
+ # And using the :admin role :
+ #
+ # customer = Customer.new
+ # customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :admin)
+ # customer.name # => "Daniel"
+ # customer.credit_rating # => "Excellent"
+ #
+ # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +alfred_accessible+
+ # to sanitize attributes won't provide sufficient protection.
+ def alfred_accessible(*args)
+ alfred(:accessible, *args)
+ end
+
+ private
+ def alfred(method, *args)
+ options = args.extract_options!
+
+ if args.include?(:password) && Alfred.auto_password_confirmation
+ args = args + [:password_confirmation]
+ end
+
+ [nil, :create, :update].each do |action|
+ if options[:on]
+ next unless options[:on] == action
+ end
+
+ action_args = args.dup
+
+ role = (options[:as] || :default).to_s
+ role << "_#{action}" if action
+ role = role.to_sym
+
+ action_args = action_args + [{ as: role }]
+
+ action_args = action_args + send("#{method}_attributes", role).to_a.compact.reject { |s| s.blank? }
+
+ send("attr_#{method}", *action_args)
+ end
+ end
+ end
+
+ include ClassMethods
+ end
+ end
+end
+
+module ActiveModel::MassAssignmentSecurity::ClassMethods
+ include Alfred::ActiveModel::MassAssignmentSecurity
+end
View
@@ -1,153 +0,0 @@
-module Alfred
- module Models
- # Attributes named in this macro are protected from mass-assignment
- # whenever attributes are sanitized before assignment. A role for the
- # attributes is optional, if no role is provided then :default is used.
- # A role can be defined by using the :as option.
- #
- # Mass-assignment to these attributes will simply be ignored, to assign
- # to them you can use direct writer methods. This is meant to protect
- # sensitive attributes from being overwritten by malicious users
- # tampering with URLs or forms. Example:
- #
- # class Customer
- # include ActiveModel::MassAssignmentSecurity
- # extend Alfred::Models
- #
- # attr_accessor :name, :credit_rating
- #
- # alfred_protected :credit_rating
- # alfred_protected :last_login, as: :trainee
- #
- # def assign_attributes(values, options = {})
- # sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
- # send("#{k}=", v)
- # end
- # end
- # end
- #
- # When using the :default role :
- #
- # customer = Customer.new
- # customer.assign_attributes({ name: "David", credit_rating: "Excellent", last_login: 1.day.ago }, as: :default)
- # customer.name # => "David"
- # customer.credit_rating # => nil
- # customer.last_login # => nil
- #
- # customer.credit_rating = "Average"
- # customer.credit_rating # => "Average"
- #
- # And using the :admin role :
- #
- # customer = Customer.new
- # customer.assign_attributes({ name: "David", credit_rating: "Excellent", last_login: 1.day.ago }, as: :trainee)
- # customer.name # => "David"
- # customer.credit_rating # => "Excellent"
- # customer.last_login # => nil
- #
- # To start from an all-closed default and enable attributes as needed,
- # have a look at +alfred_accessible+.
- #
- # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +alfred_protected+
- # to sanitize attributes won't provide sufficient protection.
- def alfred_protected(*args)
- alfred(:protected, *args)
- end
-
- # Specifies a white list of model attributes that can be set via
- # mass-assignment.
- #
- # Like +alfred_protected+, a role for the attributes is optional,
- # if no role is provided then :default is used. A role can be defined by
- # using the :as option.
- #
- # This is the opposite of the +alfred_protected+ macro: Mass-assignment
- # will only set attributes in this list, to assign to the rest of
- # attributes you can use direct writer methods. This is meant to protect
- # sensitive attributes from being overwritten by malicious users
- # tampering with URLs or forms. If you'd rather start from an all-open
- # default and restrict attributes as needed, have a look at
- # +alfred_protected+.
- #
- # class Customer
- # include ActiveModel::MassAssignmentSecurity
- # extend Alfred::Models
- #
- # attr_accessor :name, :credit_rating
- #
- # alfred_accessible :name
- # alfred_accessible :credit_rating, as: :admin
- #
- # def assign_attributes(values, options = {})
- # sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
- # send("#{k}=", v)
- # end
- # end
- # end
- #
- # When using the :default role :
- #
- # customer = Customer.new
- # customer.assign_attributes({ name: "David", credit_rating: "Excellent", last_login: 1.day.ago }, as: :default)
- # customer.name # => "David"
- # customer.credit_rating # => nil
- #
- # customer.credit_rating = "Average"
- # customer.credit_rating # => "Average"
- #
- # And using the :admin role :
- #
- # customer = Customer.new
- # customer.assign_attributes({ name: "David", credit_rating: "Excellent", last_login: 1.day.ago }, as: :admin)
- # customer.name # => "David"
- # customer.credit_rating # => "Excellent"
- #
- # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +alfred_accessible+
- # to sanitize attributes won't provide sufficient protection.
- def alfred_accessible(*args)
- alfred(:accessible, *args)
- end
-
- private
-
- def alfred(method, *args)
- options = args.extract_options!
-
- if options[:as]
- if method == :accessible
- args = args + accessible_attributes(options[:inherit] || :default).to_a
- else
- args = args + protected_attributes(options[:inherit] || :default).to_a
- end
- args = args + [{ as: options[:as] }]
- end
-
- if args.include?(:password) && Alfred.auto_password_confirmation
- args = args + [:password_confirmation]
- end
-
- if options[:on] && [:create, :update].include?(options[:on])
- if options[:on] == :create
- before = :before_create
- else
- before = :before_update
- end
- if method == :accessible
- self.class.send(:define_method, before) do
- attr_accessible(*args)
- end
- else
- self.class.send(:define_method, before) do
- attr_protected(*args)
- end
- end
- else
- if method == :accessible
- attr_accessible(*args)
- else
- attr_protected(*args)
- end
- end
- end
- end
-end
@@ -1,3 +1,32 @@
require 'active_record'
-ActiveRecord::Base.extend Alfred::Models
+module Alfred
+ module ActiveRecord
+ module Base
+ def assign_attributes(new_attributes, options = {})
+ role = (options[:as] || :default).to_s
+ role << "_#{options[:action]}" if options[:action]
+
+ options[:as] = role.to_sym
+
+ super
+ end
+
+ def initialize(attributes = nil, options = {})
+ options[:action] = :create
+
+ super
+ end
+
+ def update_attributes(attributes, options = {})
+ options[:action] = :update
+
+ super
+ end
+ end
+ end
+end
+
+class ActiveRecord::Base
+ include Alfred::ActiveRecord::Base
+end
View
@@ -1,3 +1,3 @@
module Alfred
- VERSION = "0.0.1"
+ VERSION = "0.0.2"
end

0 comments on commit d321743

Please sign in to comment.