aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb2
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb2
-rw-r--r--activerecord/lib/active_record/locking/pessimistic.rb6
-rw-r--r--activerecord/lib/active_record/relation.rb5
-rw-r--r--activerecord/lib/active_record/validations/uniqueness.rb15
-rw-r--r--activerecord/test/cases/relations_test.rb26
6 files changed, 46 insertions, 10 deletions
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index 0d8e45adb5..4edbe216be 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -37,7 +37,7 @@ module ActiveRecord
# Implemented by subclasses
def replace(record)
- raise NotImplementedError
+ raise NotImplementedError, "Subclasses must implement a replace(record) method"
end
def set_new_record(record)
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index 6b2b1ebafe..9a31675782 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -23,7 +23,7 @@ module ActiveRecord
# p2.first_name = "should fail"
# p2.save # Raises a ActiveRecord::StaleObjectError
#
- # Optimistic locking will also check for stale data when objects are destroyed. Example:
+ # Optimistic locking will also check for stale data when objects are destroyed. Example:
#
# p1 = Person.find(1)
# p2 = Person.find(1)
diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb
index 557b277d6b..862cf8f72a 100644
--- a/activerecord/lib/active_record/locking/pessimistic.rb
+++ b/activerecord/lib/active_record/locking/pessimistic.rb
@@ -9,9 +9,8 @@ module ActiveRecord
# Account.find(1, :lock => true)
#
# Pass <tt>:lock => 'some locking clause'</tt> to give a database-specific locking clause
- # of your own such as 'LOCK IN SHARE MODE' or 'FOR UPDATE NOWAIT'.
+ # of your own such as 'LOCK IN SHARE MODE' or 'FOR UPDATE NOWAIT'. Example:
#
- # Example:
# Account.transaction do
# # select * from accounts where name = 'shugo' limit 1 for update
# shugo = Account.where("name = 'shugo'").lock(true).first
@@ -24,6 +23,7 @@ module ActiveRecord
#
# You can also use ActiveRecord::Base#lock! method to lock one record by id.
# This may be better if you don't need to lock every row. Example:
+ #
# Account.transaction do
# # select * from accounts where ...
# accounts = Account.where(...).all
@@ -44,7 +44,7 @@ module ActiveRecord
module Pessimistic
# Obtain a row lock on this record. Reloads the record to obtain the requested
# lock. Pass an SQL locking clause to append the end of the SELECT statement
- # or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
+ # or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
# the locked record.
def lock!(lock = true)
reload(:lock => lock) if persisted?
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 5af20bf38b..371403f510 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -110,7 +110,10 @@ module ActiveRecord
# Returns true if there are no records.
def empty?
- loaded? ? @records.empty? : count.zero?
+ return @records.empty? if loaded?
+
+ c = count
+ c.respond_to?(:zero?) ? c.zero? : c.empty?
end
def any?
diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb
index a96796f9ff..9cd6c26322 100644
--- a/activerecord/lib/active_record/validations/uniqueness.rb
+++ b/activerecord/lib/active_record/validations/uniqueness.rb
@@ -173,10 +173,17 @@ module ActiveRecord
# This technique is also known as optimistic concurrency control:
# http://en.wikipedia.org/wiki/Optimistic_concurrency_control
#
- # Active Record currently provides no way to distinguish unique
- # index constraint errors from other types of database errors, so you
- # will have to parse the (database-specific) exception message to detect
- # such a case.
+ # The bundled ActiveRecord::ConnectionAdapters distinguish unique index
+ # constraint errors from other types of database errors by throwing an
+ # ActiveRecord::RecordNotUnique exception.
+ # For other adapters you will have to parse the (database-specific) exception
+ # message to detect such a case.
+ # The following bundled adapters throw the ActiveRecord::RecordNotUnique exception:
+ # * ActiveRecord::ConnectionAdapters::MysqlAdapter
+ # * ActiveRecord::ConnectionAdapters::Mysql2Adapter
+ # * ActiveRecord::ConnectionAdapters::SQLiteAdapter
+ # * ActiveRecord::ConnectionAdapters::SQLite3Adapter
+ # * ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
#
def validates_uniqueness_of(*attr_names)
validates_with UniquenessValidator, _merge_attributes(attr_names)
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index ac586e2a63..680e1d50cf 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -673,6 +673,32 @@ class RelationTest < ActiveRecord::TestCase
assert_equal expected, posts.count
end
+ def test_empty
+ posts = Post.scoped
+
+ assert_queries(1) { assert_equal false, posts.empty? }
+ assert ! posts.loaded?
+
+ no_posts = posts.where(:title => "")
+ assert_queries(1) { assert_equal true, no_posts.empty? }
+ assert ! no_posts.loaded?
+
+ best_posts = posts.where(:comments_count => 0)
+ best_posts.to_a # force load
+ assert_no_queries { assert_equal false, best_posts.empty? }
+ end
+
+ def test_empty_complex_chained_relations
+ posts = Post.select("comments_count").where("id is not null").group("author_id").where("comments_count > 0")
+
+ assert_queries(1) { assert_equal false, posts.empty? }
+ assert ! posts.loaded?
+
+ no_posts = posts.where(:title => "")
+ assert_queries(1) { assert_equal true, no_posts.empty? }
+ assert ! no_posts.loaded?
+ end
+
def test_any
posts = Post.scoped