aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorDavid Heinemeier Hansson <david@loudthinking.com>2011-05-01 16:59:33 -0700
committerDavid Heinemeier Hansson <david@loudthinking.com>2011-05-01 16:59:33 -0700
commita8861c8f5b57ea653e1518325a686fd97995aef4 (patch)
treea0d348d1b99ec15c6601d6f47a5a84365e06e93d /activerecord/lib
parent32ef3ccaa6beae4ef73969f51d5159f4cc4d9ff7 (diff)
parent86d7ed33754f80690395309dd307c6d9ecc0022f (diff)
downloadrails-a8861c8f5b57ea653e1518325a686fd97995aef4.tar.gz
rails-a8861c8f5b57ea653e1518325a686fd97995aef4.tar.bz2
rails-a8861c8f5b57ea653e1518325a686fd97995aef4.zip
Merge pull request #357 from joshk/assign_attributes.
Assign protected attributes with create/new and control the role.
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb20
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb4
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb16
-rw-r--r--activerecord/lib/active_record/base.rb33
4 files changed, 48 insertions, 25 deletions
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 33a184d48d..6cdec8c487 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -93,20 +93,20 @@ module ActiveRecord
first_or_last(:last, *args)
end
- def build(attributes = {}, &block)
- build_or_create(attributes, :build, &block)
+ def build(attributes = {}, options = {}, &block)
+ build_or_create(:build, attributes, options, &block)
end
- def create(attributes = {}, &block)
+ def create(attributes = {}, options = {}, &block)
unless owner.persisted?
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
end
- build_or_create(attributes, :create, &block)
+ build_or_create(:create, attributes, options, &block)
end
- def create!(attrs = {}, &block)
- record = create(attrs, &block)
+ def create!(attrs = {}, options = {}, &block)
+ record = create(attrs, options, &block)
Array.wrap(record).each(&:save!)
record
end
@@ -403,9 +403,9 @@ module ActiveRecord
end + existing
end
- def build_or_create(attributes, method)
+ def build_or_create(method, attributes, options)
records = Array.wrap(attributes).map do |attrs|
- record = build_record(attrs)
+ record = build_record(attrs, options)
add_to_target(record) do
yield(record) if block_given?
@@ -421,8 +421,8 @@ module ActiveRecord
raise NotImplementedError
end
- def build_record(attributes)
- reflection.build_association(scoped.scope_for_create.merge(attributes))
+ def build_record(attributes, options)
+ reflection.build_association(scoped.scope_for_create.merge(attributes), options)
end
def delete_or_destroy(records, method)
diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb
index 9d2b29685b..7708228d23 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -60,10 +60,10 @@ module ActiveRecord
through_record
end
- def build_record(attributes)
+ def build_record(attributes, options = {})
ensure_not_nested
- record = super(attributes)
+ record = super(attributes, options)
inverse = source_reflection.inverse_of
if inverse
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index 4edbe216be..ea4d73d414 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -17,16 +17,16 @@ module ActiveRecord
replace(record)
end
- def create(attributes = {})
- new_record(:create, attributes)
+ def create(attributes = {}, options = {})
+ new_record(:create, attributes, options)
end
- def create!(attributes = {})
- build(attributes).tap { |record| record.save! }
+ def create!(attributes = {}, options = {})
+ build(attributes, options).tap { |record| record.save! }
end
- def build(attributes = {})
- new_record(:build, attributes)
+ def build(attributes = {}, options = {})
+ new_record(:build, attributes, options)
end
private
@@ -44,9 +44,9 @@ module ActiveRecord
replace(record)
end
- def new_record(method, attributes)
+ def new_record(method, attributes, options)
attributes = scoped.scope_for_create.merge(attributes || {})
- record = reflection.send("#{method}_association", attributes)
+ record = reflection.send("#{method}_association", attributes, options)
set_new_record(record)
record
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 8d17e3e2c6..1919ceb158 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -475,10 +475,19 @@ module ActiveRecord #:nodoc:
# The +attributes+ parameter can be either be a Hash or an Array of Hashes. These Hashes describe the
# attributes on the objects that are to be created.
#
+ # +create+ respects mass-assignment security and accepts either +:as+ or +:without_protection+ options
+ # in the +options+ parameter.
+ #
# ==== Examples
# # Create a single new object
# User.create(:first_name => 'Jamie')
#
+ # # Create a single new object using the :admin mass-assignment security scope
+ # User.create({ :first_name => 'Jamie', :is_admin => true }, :as => :admin)
+ #
+ # # Create a single new object bypassing mass-assignment security
+ # User.create({ :first_name => 'Jamie', :is_admin => true }, :without_protection => true)
+ #
# # Create an Array of new objects
# User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])
#
@@ -491,11 +500,11 @@ module ActiveRecord #:nodoc:
# User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u|
# u.is_admin = false
# end
- def create(attributes = nil, &block)
+ def create(attributes = nil, options = {}, &block)
if attributes.is_a?(Array)
- attributes.collect { |attr| create(attr, &block) }
+ attributes.collect { |attr| create(attr, options, &block) }
else
- object = new(attributes)
+ object = new(attributes, options)
yield(object) if block_given?
object.save
object
@@ -1465,7 +1474,20 @@ MSG
# attributes but not yet saved (pass a hash with key names matching the associated table column names).
# In both instances, valid attribute keys are determined by the column names of the associated table --
# hence you can't have attributes that aren't part of the table columns.
- def initialize(attributes = nil)
+ #
+ # +initialize+ respects mass-assignment security and accepts either +:as+ or +:without_protection+ options
+ # in the +options+ parameter.
+ #
+ # ==== Examples
+ # # Instantiates a single new object
+ # User.new(:first_name => 'Jamie')
+ #
+ # # Instantiates a single new object using the :admin mass-assignment security scope
+ # User.new({ :first_name => 'Jamie', :is_admin => true }, :as => :admin)
+ #
+ # # Instantiates a single new object bypassing mass-assignment security
+ # User.new({ :first_name => 'Jamie', :is_admin => true }, :without_protection => true)
+ def initialize(attributes = nil, options = {})
@attributes = attributes_from_column_definition
@association_cache = {}
@aggregation_cache = {}
@@ -1481,7 +1503,8 @@ MSG
set_serialized_attributes
populate_with_current_scope_attributes
- self.attributes = attributes unless attributes.nil?
+
+ assign_attributes(attributes, options) if attributes
result = yield self if block_given?
run_callbacks :initialize