aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorEmilio Tagua <miloops@gmail.com>2009-10-13 15:06:43 -0300
committerEmilio Tagua <miloops@gmail.com>2009-10-13 15:06:43 -0300
commit991d1bc200d6fdc379bc83610bc92a4e220c669e (patch)
tree84ace4c9c117ba7bc82824dbddf15485a9305bd2 /activerecord/lib
parent0cf4662ec589813c4fdc22de3398730cab05c5ed (diff)
parent9cd50e7752650a3d6bf8545b51d50619d6e70c0b (diff)
downloadrails-991d1bc200d6fdc379bc83610bc92a4e220c669e.tar.gz
rails-991d1bc200d6fdc379bc83610bc92a4e220c669e.tar.bz2
rails-991d1bc200d6fdc379bc83610bc92a4e220c669e.zip
Merge commit 'rails/master'
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/associations/association_collection.rb2
-rw-r--r--activerecord/lib/active_record/callbacks.rb4
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/abstract_adapter.rb4
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb42
-rw-r--r--activerecord/lib/active_record/validations.rb14
5 files changed, 41 insertions, 25 deletions
diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb
index 1b7bf42b91..25e329c0c1 100644
--- a/activerecord/lib/active_record/associations/association_collection.rb
+++ b/activerecord/lib/active_record/associations/association_collection.rb
@@ -476,7 +476,7 @@ module ActiveRecord
def callback(method, record)
callbacks_for(method).each do |callback|
- ActiveSupport::Callbacks::Callback.new(method, callback, record).call(@owner, record)
+ ActiveSupport::DeprecatedCallbacks::Callback.new(method, callback, record).call(@owner, record)
end
end
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index 40a25811c4..b25893a1c3 100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -20,7 +20,7 @@ module ActiveRecord
# * (6) <tt>after_save</tt>
#
# That's a total of eight callbacks, which gives you immense power to react and prepare for each state in the
- # Active Record lifecycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar, except that each
+ # Active Record lifecycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar, except that each
# <tt>_on_create</tt> callback is replaced by the corresponding <tt>_on_update</tt> callback.
#
# Examples:
@@ -210,7 +210,7 @@ module ActiveRecord
# instead of quietly returning +false+.
module Callbacks
extend ActiveSupport::Concern
- include ActiveSupport::NewCallbacks
+ include ActiveSupport::Callbacks
CALLBACKS = [
:after_initialize, :after_find, :before_validation, :after_validation,
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 78c7a4b697..cdf0aebfee 100755
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -32,7 +32,7 @@ module ActiveRecord
class AbstractAdapter
include Quoting, DatabaseStatements, SchemaStatements
include QueryCache
- include ActiveSupport::Callbacks
+ include ActiveSupport::DeprecatedCallbacks
define_callbacks :checkout, :checkin
@@row_even = true
@@ -75,7 +75,7 @@ module ActiveRecord
def supports_ddl_transactions?
false
end
-
+
# Does this adapter support savepoints? PostgreSQL and MySQL do, SQLite
# does not.
def supports_savepoints?
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index ec6c02db38..edcf547e01 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -3,11 +3,14 @@ require 'active_support/core_ext/object/try'
module ActiveRecord
module NestedAttributes #:nodoc:
+ class TooManyRecords < ActiveRecordError
+ end
+
extend ActiveSupport::Concern
included do
- class_inheritable_accessor :reject_new_nested_attributes_procs, :instance_writer => false
- self.reject_new_nested_attributes_procs = {}
+ class_inheritable_accessor :nested_attributes_options, :instance_writer => false
+ self.nested_attributes_options = {}
end
# == Nested Attributes
@@ -203,6 +206,12 @@ module ActiveRecord
# do not have a <tt>_destroy</tt> value that evaluates to true.
# Passing <tt>:all_blank</tt> instead of a Proc will create a proc
# that will reject a record where all the attributes are blank.
+ # [:limit]
+ # Allows you to specify the maximum number of the associated records that
+ # can be processes with the nested attributes. If the size of the
+ # nested attributes array exceeds the specified limit, NestedAttributes::TooManyRecords
+ # exception is raised. If omitted, any number associations can be processed.
+ # Note that the :limit option is only applicable to one-to-many associations.
#
# Examples:
# # creates avatar_attributes=
@@ -214,7 +223,7 @@ module ActiveRecord
def accepts_nested_attributes_for(*attr_names)
options = { :allow_destroy => false }
options.update(attr_names.extract_options!)
- options.assert_valid_keys(:allow_destroy, :reject_if)
+ options.assert_valid_keys(:allow_destroy, :reject_if, :limit)
attr_names.each do |association_name|
if reflection = reflect_on_association(association_name)
@@ -227,10 +236,10 @@ module ActiveRecord
reflection.options[:autosave] = true
- self.reject_new_nested_attributes_procs[association_name.to_sym] = if options[:reject_if] == :all_blank
- proc { |attributes| attributes.all? {|k,v| v.blank?} }
- else
- options[:reject_if]
+ self.nested_attributes_options[association_name.to_sym] = options
+
+ if options[:reject_if] == :all_blank
+ self.nested_attributes_options[association_name.to_sym][:reject_if] = proc { |attributes| attributes.all? {|k,v| v.blank?} }
end
# def pirate_attributes=(attributes)
@@ -238,7 +247,7 @@ module ActiveRecord
# end
class_eval %{
def #{association_name}_attributes=(attributes)
- assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes, #{options[:allow_destroy]})
+ assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
end
}, __FILE__, __LINE__
else
@@ -282,7 +291,8 @@ module ActiveRecord
# If the given attributes include a matching <tt>:id</tt> attribute _and_ a
# <tt>:_destroy</tt> key set to a truthy value, then the existing record
# will be marked for destruction.
- def assign_nested_attributes_for_one_to_one_association(association_name, attributes, allow_destroy)
+ def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
+ options = self.nested_attributes_options[association_name]
attributes = attributes.with_indifferent_access
if attributes['id'].blank?
@@ -295,7 +305,7 @@ module ActiveRecord
end
end
elsif (existing_record = send(association_name)) && existing_record.id.to_s == attributes['id'].to_s
- assign_to_or_mark_for_destruction(existing_record, attributes, allow_destroy)
+ assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
end
end
@@ -326,11 +336,17 @@ module ActiveRecord
# { :name => 'John' },
# { :id => '2', :_destroy => true }
# ])
- def assign_nested_attributes_for_collection_association(association_name, attributes_collection, allow_destroy)
+ def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
+ options = self.nested_attributes_options[association_name]
+
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
end
+ if options[:limit] && attributes_collection.size > options[:limit]
+ raise TooManyRecords, "Maximum #{options[:limit]} records are allowed. Got #{attributes_collection.size} records instead."
+ end
+
if attributes_collection.is_a? Hash
attributes_collection = attributes_collection.sort_by { |index, _| index.to_i }.map { |_, attributes| attributes }
end
@@ -343,7 +359,7 @@ module ActiveRecord
send(association_name).build(attributes.except(*UNASSIGNABLE_KEYS))
end
elsif existing_record = send(association_name).detect { |record| record.id.to_s == attributes['id'].to_s }
- assign_to_or_mark_for_destruction(existing_record, attributes, allow_destroy)
+ assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
end
end
end
@@ -372,7 +388,7 @@ module ActiveRecord
end
def call_reject_if(association_name, attributes)
- callback = self.class.reject_new_nested_attributes_procs[association_name]
+ callback = self.nested_attributes_options[association_name][:reject_if]
case callback
when Symbol
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index ab79b520a2..e61b253192 100644
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -59,15 +59,15 @@ module ActiveRecord
end
# Translates an error message in it's default scope (<tt>activerecord.errrors.messages</tt>).
- # Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>, if it's not there,
- # it's looked up in <tt>models.MODEL.MESSAGE</tt> and if that is not there it returns the translation of the
- # default message (e.g. <tt>activerecord.errors.messages.MESSAGE</tt>). The translated model name,
+ # Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>, if it's not there,
+ # it's looked up in <tt>models.MODEL.MESSAGE</tt> and if that is not there it returns the translation of the
+ # default message (e.g. <tt>activerecord.errors.messages.MESSAGE</tt>). The translated model name,
# translated attribute name and the value are available for interpolation.
#
# When using inheritance in your models, it will check all the inherited models too, but only if the model itself
# hasn't been found. Say you have <tt>class Admin < User; end</tt> and you wanted the translation for the <tt>:blank</tt>
# error +message+ for the <tt>title</tt> +attribute+, it looks for these translations:
- #
+ #
# <ol>
# <li><tt>activerecord.errors.models.admin.attributes.title.blank</tt></li>
# <li><tt>activerecord.errors.models.admin.blank</tt></li>
@@ -80,10 +80,10 @@ module ActiveRecord
message, options[:default] = options[:default], message if options[:default].is_a?(Symbol)
defaults = @base.class.self_and_descendants_from_active_record.map do |klass|
- [ :"models.#{klass.name.underscore}.attributes.#{attribute}.#{message}",
+ [ :"models.#{klass.name.underscore}.attributes.#{attribute}.#{message}",
:"models.#{klass.name.underscore}.#{message}" ]
end
-
+
defaults << options.delete(:default)
defaults = defaults.compact.flatten << :"messages.#{message}"
@@ -104,7 +104,7 @@ module ActiveRecord
module Validations
extend ActiveSupport::Concern
- include ActiveSupport::Callbacks
+ include ActiveSupport::DeprecatedCallbacks
include ActiveModel::Validations
included do