aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG10
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb29
-rw-r--r--activerecord/lib/active_record/base.rb2
-rw-r--r--activerecord/lib/active_record/relation.rb3
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb24
-rw-r--r--activerecord/test/cases/base_test.rb12
-rw-r--r--activerecord/test/cases/relations_test.rb18
7 files changed, 29 insertions, 69 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index e82906186e..a54526dd41 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -4,10 +4,12 @@ Wed Sep 7 15:25:02 2011 Aaron Patterson <aaron@tenderlovemaking.com>
keys are per process id.
* lib/active_record/connection_adapters/sqlite_adapter.rb: ditto
-* Add first_or_create, first_or_create!, first_or_build and first_or_new methods to Active Record. This is a better approach over the old find_or_create_by dynamic methods because it's clearer which arguments are used to find the record and which are used to create it:
+* Add first_or_create, first_or_create!, first_or_initialize methods to Active Record. This is a
+ better approach over the old find_or_create_by dynamic methods because it's clearer which
+ arguments are used to find the record and which are used to create it:
+
+ User.where(:first_name => "Scarlett").first_or_create!(:last_name => "Johansson")
- User.where(:first_name => "Scarlett").first_or_create!(:last_name => "Johansson", :hot => true)
-
[Andrés Mejía]
* Support bulk change_table in mysql2 adapter, as well as the mysql one. [Jon Leighton]
@@ -34,7 +36,7 @@ a URI that specifies the connection configuration. For example:
[Prem Sichanugrist]
-*Rails 3.1.0 (unreleased)*
+*Rails 3.1.0 (August 30, 2011)*
* Add a proxy_association method to association proxies, which can be called by association
extensions to access information about the association. This replaces proxy_owner etc with
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index dc6dc2e63a..d7bfaa5655 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -38,27 +38,24 @@ module ActiveRecord
end
end
- # Checks whether the method is defined in the model or any of its subclasses
- # that also derive from Active Record. Raises DangerousAttributeError if the
- # method is defined by Active Record though.
def instance_method_already_implemented?(method_name)
- method_name = method_name.to_s
- index = ancestors.index(ActiveRecord::Base) || ancestors.length
- @_defined_class_methods ||= ancestors.first(index).map { |m|
- m.instance_methods(false) | m.private_instance_methods(false)
- }.flatten.map {|m| m.to_s }.to_set
+ if dangerous_attribute_method?(method_name)
+ raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord"
+ end
- @@_defined_activerecord_methods ||= defined_activerecord_methods
- raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord" if @@_defined_activerecord_methods.include?(method_name)
- @_defined_class_methods.include?(method_name) || generated_attribute_methods.method_defined?(method_name)
+ super
end
- def defined_activerecord_methods
+ # A method name is 'dangerous' if it is already defined by Active Record, but
+ # not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
+ def dangerous_attribute_method?(method_name)
active_record = ActiveRecord::Base
- super_klass = ActiveRecord::Base.superclass
- methods = (active_record.instance_methods - super_klass.instance_methods) +
- (active_record.private_instance_methods - super_klass.private_instance_methods)
- methods.map {|m| m.to_s }.to_set
+ superclass = ActiveRecord::Base.superclass
+
+ (active_record.method_defined?(method_name) ||
+ active_record.private_method_defined?(method_name)) &&
+ !superclass.method_defined?(method_name) &&
+ !superclass.private_method_defined?(method_name)
end
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 92f80c6eaa..558b341c06 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -442,7 +442,7 @@ module ActiveRecord #:nodoc:
class << self # Class methods
delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped
- delegate :first_or_create, :first_or_create!, :first_or_new, :first_or_build, :to => :scoped
+ delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :scoped
delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped
delegate :find_each, :find_in_batches, :to => :scoped
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index d3f1347e03..ecefaa633c 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -132,10 +132,9 @@ module ActiveRecord
# Like <tt>first_or_create</tt> but calls <tt>new</tt> instead of <tt>create</tt>.
#
# Expects arguments in the same format as <tt>Base.new</tt>.
- def first_or_new(attributes = nil, options = {}, &block)
+ def first_or_initialize(attributes = nil, options = {}, &block)
first || new(attributes, options, &block)
end
- alias :first_or_build :first_or_new
def respond_to?(method, include_private = false)
arel.respond_to?(method, include_private) ||
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index e324a252dd..b1b41fed0d 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -431,30 +431,6 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert topic.is_test?
end
- def test_kernel_methods_not_implemented_in_activerecord
- %w(test name display y).each do |method|
- assert !ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
- end
- end
-
- def test_defined_kernel_methods_implemented_in_model
- %w(test name display y).each do |method|
- klass = Class.new ActiveRecord::Base
- klass.class_eval "def #{method}() 'defined #{method}' end"
- assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
- end
- end
-
- def test_defined_kernel_methods_implemented_in_model_abstract_subclass
- %w(test name display y).each do |method|
- abstract = Class.new ActiveRecord::Base
- abstract.class_eval "def #{method}() 'defined #{method}' end"
- abstract.abstract_class = true
- klass = Class.new abstract
- assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
- end
- end
-
def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
%w(save create_or_update).each do |method|
klass = Class.new ActiveRecord::Base
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index cb92f79e0e..12c1cfb30e 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -294,16 +294,8 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal parrot, the_same_parrot
end
- def test_first_or_new
- parrot = Bird.first_or_new(:color => 'green', :name => 'parrot')
- assert_kind_of Bird, parrot
- assert !parrot.persisted?
- assert parrot.new_record?
- assert parrot.valid?
- end
-
- def test_first_or_build
- parrot = Bird.first_or_build(:color => 'green', :name => 'parrot')
+ def test_first_or_initialize
+ parrot = Bird.first_or_initialize(:color => 'green', :name => 'parrot')
assert_kind_of Bird, parrot
assert !parrot.persisted?
assert parrot.new_record?
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 0f50ac9a2b..95408a5f29 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -956,8 +956,8 @@ class RelationTest < ActiveRecord::TestCase
assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create!([ {:name => 'parrot'}, {:pirate_id => 1} ]) }
end
- def test_first_or_new
- parrot = Bird.where(:color => 'green').first_or_new(:name => 'parrot')
+ def test_first_or_initialize
+ parrot = Bird.where(:color => 'green').first_or_initialize(:name => 'parrot')
assert_kind_of Bird, parrot
assert !parrot.persisted?
assert parrot.valid?
@@ -966,8 +966,8 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 'green', parrot.color
end
- def test_first_or_new_with_no_parameters
- parrot = Bird.where(:color => 'green').first_or_new
+ def test_first_or_initialize_with_no_parameters
+ parrot = Bird.where(:color => 'green').first_or_initialize
assert_kind_of Bird, parrot
assert !parrot.persisted?
assert !parrot.valid?
@@ -975,8 +975,8 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 'green', parrot.color
end
- def test_first_or_new_with_block
- parrot = Bird.where(:color => 'green').first_or_new { |bird| bird.name = 'parrot' }
+ def test_first_or_initialize_with_block
+ parrot = Bird.where(:color => 'green').first_or_initialize { |bird| bird.name = 'parrot' }
assert_kind_of Bird, parrot
assert !parrot.persisted?
assert parrot.valid?
@@ -985,12 +985,6 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 'parrot', parrot.name
end
- def test_first_or_build_is_alias_for_first_or_new
- birds = Bird.scoped
- assert birds.respond_to?(:first_or_build)
- assert_equal birds.method(:first_or_new), birds.method(:first_or_build)
- end
-
def test_explicit_create_scope
hens = Bird.where(:name => 'hen')
assert_equal 'hen', hens.new.name