Permalink
Browse files

backport attr_protected/attr_accessible support, cleaned up warnings,…

… fixed a test for new version of Expectation gem
  • Loading branch information...
1 parent ebbd107 commit 5039f884b4fdcf5e15977e3c3d515cf4378692e5 Josh Martin committed Jun 29, 2010
Showing with 92 additions and 7 deletions.
  1. +1 −1 lib/active_presenter.rb
  2. +47 −2 lib/active_presenter/base.rb
  3. +2 −2 lib/active_presenter/version.rb
  4. +25 −1 test/base_test.rb
  5. +17 −1 test/test_helper.rb
View
@@ -1,5 +1,5 @@
require 'rubygems'
-require 'activerecord'
+require 'active_record'
Dir.glob(File.dirname(__FILE__)+'/active_presenter/**/*.rb').each { |l| require l }
module ActivePresenter
@@ -6,6 +6,7 @@ class Base
define_callbacks :before_validation, :before_save, :after_save
class_inheritable_accessor :presented
+ class_inheritable_accessor :attr_protected, :attr_accessible
self.presented = {}
# Indicates which models are to be presented by this presenter.
@@ -67,6 +68,30 @@ def self.human_name(options = {}) # :nodoc:
I18n.translate(defaults.shift, {:scope => [:activerecord, :models], :count => 1, :default => defaults}.merge(options))
end
+ # Note that +attr_protected+ is still applied to the received hash. Thus,
+ # with this technique you can at most _extend_ the list of protected
+ # attributes for a particular mass-assignment call.
+ def self.attr_protected(*attributes)
+ write_inheritable_attribute(:attr_protected, Set.new(attributes.map {|a| a.to_s}) + (protected_attributes || []))
+ end
+
+ # Returns an array of all the attributes that have been protected from mass-assignment.
+ def self.protected_attributes # :nodoc:
+ read_inheritable_attribute(:attr_protected)
+ end
+
+ # Note that +attr_accessible+ is still applied to the received hash. Thus,
+ # with this technique you can at most _narrow_ the list of accessible
+ # attributes for a particular mass-assignment call.
+ def self.attr_accessible(*attributes)
+ write_inheritable_attribute(:attr_accessible, Set.new(attributes.map(&:to_s)) + (accessible_attributes || []))
+ end
+
+ # Returns an array of all the attributes that have been made accessible to mass-assignment.
+ def self.accessible_attributes # :nodoc:
+ read_inheritable_attribute(:attr_accessible)
+ end
+
# Accepts arguments in two forms. For example, if you had a SignupPresenter that presented User, and Account, you could specify arguments in the following two forms:
#
# 1. SignupPresenter.new(:user_login => 'james', :user_password => 'swordfish', :user_password_confirmation => 'swordfish', :account_subdomain => 'giraffesoft')
@@ -96,8 +121,10 @@ def initialize(args = {})
#
def attributes=(attrs)
return if attrs.nil?
-
+
+ attrs = attrs.stringify_keys
multi_parameter_attributes = {}
+ attrs = remove_attributes_protected_from_mass_assignment(attrs)
attrs.each do |k,v|
if (base_attribute = k.to_s.split("(").first) != k.to_s
@@ -148,6 +175,11 @@ def valid?
end
end
+ # Do any of the attributes have unsaved changes?
+ def changed?
+ presented_instances.map(&:changed?).any?
+ end
+
# Save all of the presentables, wrapped in a transaction.
#
# Returns true or false based on success.
@@ -212,7 +244,7 @@ def save?(presented_key, presented_instance)
def id # :nodoc:
nil
end
-
+
def new_record?
true
end
@@ -266,5 +298,18 @@ def attribute_protected?(name)
def run_callbacks_with_halt(callback)
run_callbacks(callback) { |result, object| result == false }
end
+
+ def remove_attributes_protected_from_mass_assignment(attributes)
+ if self.class.accessible_attributes.nil? && self.class.protected_attributes.nil?
+ attributes
+ elsif self.class.protected_attributes.nil?
+ attributes.reject { |key, value| !self.class.accessible_attributes.include?(key.gsub(/\(.+/, ""))}
+ elsif self.class.accessible_attributes.nil?
+ attributes.reject { |key, value| self.class.protected_attributes.include?(key.gsub(/\(.+/,""))}
+ else
+ raise "Declare either attr_protected or attr_accessible for #{self.class}, but not both."
+ end
+ end
+
end
end
@@ -1,8 +1,8 @@
module ActivePresenter
module VERSION
MAJOR = 1
- MINOR = 2
- TINY = 1
+ MINOR = 3
+ TINY = 0
STRING = [MAJOR, MINOR, TINY].join('.')
end
View
@@ -305,7 +305,7 @@
end.steps
end
- expect ActiveRecord::Errors.any_instance.to.receive(:clear) do
+ expect ActiveRecord::Errors.any_instance.to.receive(:clear).twice do
CallbackCantValidatePresenter.new.valid?
end
@@ -335,4 +335,28 @@
p.save
p.secondary_address_street
end
+
+ # attr_protected
+ expect "" do
+ p = SignupPresenter.new(:account_secret => 'swordfish')
+ p.account.secret
+ end
+
+ expect "comment" do
+ p = HistoricalPresenter.new(:history_comment => 'comment', :user => User.new(hash_for_user))
+ p.save
+ p.history_comment
+ end
+
+ expect false do
+ SignupPresenter.new.changed?
+ end
+
+ expect true do
+ p = SignupPresenter.new(:user => User.new(hash_for_user))
+ p.save
+ p.user_login = 'something_else'
+ p.changed?
+ end
+
end
View
@@ -1,4 +1,4 @@
-require File.dirname(__FILE__)+'/../lib/active_presenter'
+require File.dirname(__FILE__)+'/../lib/active_presenter' unless defined?(ActivePresenter)
require 'expectations'
require 'logger'
@@ -34,6 +34,7 @@
create_table :accounts do |t|
t.string :subdomain, :default => ''
t.string :title, :default => ''
+ t.string :secret, :default => ''
end
create_table :addresses do |t|
@@ -43,6 +44,14 @@
create_table :account_infos do |t|
t.string :info
end
+
+ create_table :histories do |t|
+ t.integer :user_id
+ t.string :comment, :default => ''
+ t.string :action, :default => ''
+ t.datetime :created_at
+ end
+
end
class User < ActiveRecord::Base
@@ -60,6 +69,7 @@ def presence_of_password
end
end
class Account < ActiveRecord::Base; end
+class History < ActiveRecord::Base; end
class Address < ActiveRecord::Base; end
class AccountInfo < ActiveRecord::Base; end
@@ -69,12 +79,18 @@ class PresenterWithTwoAddresses < ActivePresenter::Base
class SignupPresenter < ActivePresenter::Base
presents :account, :user
+ attr_protected :account_secret
end
class EndingWithSPresenter < ActivePresenter::Base
presents :address
end
+class HistoricalPresenter < ActivePresenter::Base
+ presents :user, :history
+ attr_accessible :history_comment
+end
+
class CantSavePresenter < ActivePresenter::Base
presents :address

0 comments on commit 5039f88

Please sign in to comment.