aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md31
-rw-r--r--activerecord/activerecord.gemspec2
-rw-r--r--activerecord/lib/active_record.rb1
-rw-r--r--activerecord/lib/active_record/associations/association.rb13
-rw-r--r--activerecord/lib/active_record/associations/association_scope.rb15
-rw-r--r--activerecord/lib/active_record/associations/belongs_to_association.rb7
-rw-r--r--activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb3
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb21
-rw-r--r--activerecord/lib/active_record/associations/through_association.rb2
-rw-r--r--activerecord/lib/active_record/base.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb59
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb26
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb24
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb26
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb568
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb563
-rw-r--r--activerecord/lib/active_record/core.rb7
-rw-r--r--activerecord/lib/active_record/counter_cache.rb2
-rw-r--r--activerecord/lib/active_record/model_schema.rb2
-rw-r--r--activerecord/lib/active_record/null_relation.rb53
-rw-r--r--activerecord/lib/active_record/persistence.rb4
-rw-r--r--activerecord/lib/active_record/railtie.rb6
-rw-r--r--activerecord/lib/active_record/relation.rb109
-rw-r--r--activerecord/lib/active_record/relation/batches.rb9
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb118
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb155
-rw-r--r--activerecord/lib/active_record/relation/merger.rb121
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb286
-rw-r--r--activerecord/lib/active_record/relation/spawn_methods.rb150
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb2
-rw-r--r--activerecord/lib/active_record/scoping.rb121
-rw-r--r--activerecord/lib/active_record/scoping/default.rb11
-rw-r--r--activerecord/lib/active_record/scoping/named.rb25
-rw-r--r--activerecord/lib/active_record/session_store.rb2
-rw-r--r--activerecord/lib/active_record/validations/uniqueness.rb1
-rw-r--r--activerecord/lib/rails/generators/active_record/model/model_generator.rb3
-rw-r--r--activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb30
-rw-r--r--activerecord/test/cases/adapters/mysql/reserved_word_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql/schema_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb4
-rw-r--r--activerecord/test/cases/adapters/mysql2/reserved_word_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/schema_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/hstore_test.rb16
-rw-r--r--activerecord/test/cases/adapters/sqlite3/quoting_test.rb2
-rw-r--r--activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb2
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb40
-rw-r--r--activerecord/test/cases/associations/cascaded_eager_loading_test.rb28
-rw-r--r--activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb4
-rw-r--r--activerecord/test/cases/associations/eager_load_nested_include_test.rb4
-rw-r--r--activerecord/test/cases/associations/eager_singularization_test.rb14
-rw-r--r--activerecord/test/cases/associations/eager_test.rb394
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb53
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb161
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb8
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb12
-rw-r--r--activerecord/test/cases/associations/has_one_through_associations_test.rb26
-rw-r--r--activerecord/test/cases/associations/inner_join_association_test.rb6
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb54
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb88
-rw-r--r--activerecord/test/cases/associations_test.rb8
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb10
-rw-r--r--activerecord/test/cases/autosave_association_test.rb34
-rw-r--r--activerecord/test/cases/base_test.rb161
-rw-r--r--activerecord/test/cases/batches_test.rb16
-rw-r--r--activerecord/test/cases/calculations_test.rb143
-rw-r--r--activerecord/test/cases/connection_pool_test.rb24
-rw-r--r--activerecord/test/cases/custom_locking_test.rb2
-rw-r--r--activerecord/test/cases/deprecated_finder_test.rb30
-rw-r--r--activerecord/test/cases/dirty_test.rb4
-rw-r--r--activerecord/test/cases/explain_test.rb4
-rw-r--r--activerecord/test/cases/finder_test.rb295
-rw-r--r--activerecord/test/cases/fixtures_test.rb2
-rw-r--r--activerecord/test/cases/helper.rb2
-rw-r--r--activerecord/test/cases/inheritance_test.rb32
-rw-r--r--activerecord/test/cases/locking_test.rb13
-rw-r--r--activerecord/test/cases/method_scoping_test.rb558
-rw-r--r--activerecord/test/cases/migration/column_attributes_test.rb6
-rw-r--r--activerecord/test/cases/migration/references_index_test.rb99
-rw-r--r--activerecord/test/cases/migration/rename_column_test.rb6
-rw-r--r--activerecord/test/cases/migration_test.rb25
-rw-r--r--activerecord/test/cases/modules_test.rb16
-rw-r--r--activerecord/test/cases/named_scope_test.rb101
-rw-r--r--activerecord/test/cases/persistence_test.rb30
-rw-r--r--activerecord/test/cases/query_cache_test.rb6
-rw-r--r--activerecord/test/cases/readonly_test.rb12
-rw-r--r--activerecord/test/cases/reflection_test.rb2
-rw-r--r--activerecord/test/cases/relation_scoping_test.rb42
-rw-r--r--activerecord/test/cases/relation_test.rb151
-rw-r--r--activerecord/test/cases/relations_test.rb62
-rw-r--r--activerecord/test/cases/validations/association_validation_test.rb2
-rw-r--r--activerecord/test/cases/validations/uniqueness_validation_test.rb6
-rw-r--r--activerecord/test/cases/validations_test.rb24
-rw-r--r--activerecord/test/models/car.rb1
-rw-r--r--activerecord/test/models/comment.rb4
-rw-r--r--activerecord/test/models/developer.rb20
-rw-r--r--activerecord/test/models/post.rb15
-rw-r--r--activerecord/test/models/topic.rb20
101 files changed, 2396 insertions, 3113 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 26f6093bc2..aa84dacf07 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,5 +1,34 @@
## Rails 4.0.0 (unreleased) ##
+* Added an :index option to automatically create indexes for references
+ and belongs_to statements in migrations.
+
+ The `references` and `belongs_to` methods now support an `index`
+ option that receives either a boolean value or an options hash
+ that is identical to options available to the add_index method:
+
+ create_table :messages do |t|
+ t.references :person, :index => true
+ end
+
+ Is the same as:
+
+ create_table :messages do |t|
+ t.references :person
+ end
+ add_index :messages, :person_id
+
+ Generators have also been updated to use the new syntax.
+
+ [Joshua Wood]
+
+* Added bang methods for mutating `ActiveRecord::Relation` objects.
+ For example, while `foo.where(:bar)` will return a new object
+ leaving `foo` unchanged, `foo.where!(:bar)` will mutate the foo
+ object
+
+ *Jon Leighton*
+
* Added `#find_by` and `#find_by!` to mirror the functionality
provided by dynamic finders in a way that allows dynamic input more
easily:
@@ -210,7 +239,7 @@
* PostgreSQL hstore types are automatically deserialized from the database.
-## Rails 3.2.3 (unreleased) ##
+## Rails 3.2.3 (March 30, 2012) ##
* Added find_or_create_by_{attribute}! dynamic method. *Andrew White*
diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec
index 26eb74df0f..e8e5f4adfe 100644
--- a/activerecord/activerecord.gemspec
+++ b/activerecord/activerecord.gemspec
@@ -22,4 +22,6 @@ Gem::Specification.new do |s|
s.add_dependency('activesupport', version)
s.add_dependency('activemodel', version)
s.add_dependency('arel', '~> 3.0.2')
+
+ s.add_dependency('active_record_deprecated_finders', '0.0.1')
end
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 0cb0644bcf..c4b10a8dae 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -25,6 +25,7 @@ require 'active_support'
require 'active_support/i18n'
require 'active_model'
require 'arel'
+require 'active_record_deprecated_finders'
require 'active_record/version'
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index fb0ca15c23..e75003f261 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -25,10 +25,7 @@ module ActiveRecord
def initialize(owner, reflection)
reflection.check_validity!
- @target = nil
@owner, @reflection = owner, reflection
- @updated = false
- @stale_state = nil
reset
reset_scope
@@ -39,13 +36,14 @@ module ActiveRecord
# post.comments.aliased_table_name # => "comments"
#
def aliased_table_name
- reflection.klass.table_name
+ klass.table_name
end
# Resets the \loaded flag to +false+ and sets the \target to +nil+.
def reset
@loaded = false
@target = nil
+ @stale_state = nil
end
# Reloads the \target and returns +self+ on success.
@@ -134,7 +132,8 @@ module ActiveRecord
# ActiveRecord::RecordNotFound is rescued within the method, and it is
# not reraised. The proxy is \reset and +nil+ is the return value.
def load_target
- @target ||= find_target if find_target?
+ @target = find_target if (@stale_state && stale_target?) || find_target?
+
loaded! unless loaded?
target
rescue ActiveRecord::RecordNotFound
@@ -215,10 +214,6 @@ module ActiveRecord
def stale_state
end
- def association_class
- @reflection.klass
- end
-
def build_record(attributes, options)
reflection.build_association(attributes, options) do |record|
attributes = create_scope.except(*(record.changed - [reflection.foreign_key]))
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index 2972b7e13e..5a44d3a156 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -15,19 +15,20 @@ module ActiveRecord
def scope
scope = klass.unscoped
- scope = scope.extending(*Array(options[:extend]))
+
+ scope.extending!(*Array(options[:extend]))
# It's okay to just apply all these like this. The options will only be present if the
# association supports that option; this is enforced by the association builder.
- scope = scope.apply_finder_options(options.slice(
- :readonly, :include, :references, :order, :limit, :joins, :group, :having, :offset, :select))
+ scope.merge!(options.slice(
+ :readonly, :references, :order, :limit, :joins, :group, :having, :offset, :select, :uniq))
- if options[:through] && !options[:include]
- scope = scope.includes(source_options[:include])
+ if options[:include]
+ scope.includes! options[:include]
+ elsif options[:through]
+ scope.includes! source_options[:include]
end
- scope = scope.uniq if options[:uniq]
-
add_constraints(scope)
end
diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb
index 97f531d064..ddfc6f6c05 100644
--- a/activerecord/lib/active_record/associations/belongs_to_association.rb
+++ b/activerecord/lib/active_record/associations/belongs_to_association.rb
@@ -14,6 +14,11 @@ module ActiveRecord
self.target = record
end
+ def reset
+ super
+ @updated = false
+ end
+
def updated?
@updated
end
@@ -72,7 +77,7 @@ module ActiveRecord
end
def stale_state
- owner[reflection.foreign_key].to_s
+ owner[reflection.foreign_key] && owner[reflection.foreign_key].to_s
end
end
end
diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
index 2ee5dbbd70..88ce03a3cd 100644
--- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
+++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
@@ -27,7 +27,8 @@ module ActiveRecord
end
def stale_state
- [super, owner[reflection.foreign_type].to_s]
+ foreign_key = super
+ foreign_key && [foreign_key.to_s, owner[reflection.foreign_type].to_s]
end
end
end
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index da4c311bce..14aa557b6c 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -71,7 +71,7 @@ module ActiveRecord
end
def reset
- @loaded = false
+ super
@target = []
end
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 5eda0387c4..ad029d1101 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -61,11 +61,15 @@ module ActiveRecord
@association
end
- def scoped
+ def scoped(options = nil)
association = @association
- association.scoped.extending do
+ scope = association.scoped
+
+ scope.extending! do
define_method(:proxy_association) { association }
end
+ scope.merge!(options) if options
+ scope
end
def respond_to?(name, include_private = false)
@@ -126,6 +130,19 @@ module ActiveRecord
proxy_association.reload
self
end
+
+ # Define array public methods because we know it should be invoked over
+ # the target, so we can have a performance improvement using those methods
+ # in association collections
+ Array.public_instance_methods.each do |m|
+ unless method_defined?(m)
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{m}(*args, &block)
+ target.public_send(:#{m}, *args, &block) if load_target
+ end
+ RUBY
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb
index fd0e90aaf0..be890e5767 100644
--- a/activerecord/lib/active_record/associations/through_association.rb
+++ b/activerecord/lib/active_record/associations/through_association.rb
@@ -62,7 +62,7 @@ module ActiveRecord
# properly support stale-checking for nested associations.
def stale_state
if through_reflection.macro == :belongs_to
- owner[through_reflection.foreign_key].to_s
+ owner[through_reflection.foreign_key] && owner[through_reflection.foreign_key].to_s
end
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index d25a821688..fc3906d395 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -305,7 +305,7 @@ module ActiveRecord #:nodoc:
# * AssociationTypeMismatch - The object assigned to the association wasn't of the type
# specified in the association definition.
# * SerializationTypeMismatch - The serialized object wasn't of the class specified as the second parameter.
- # * ConnectionNotEstablished+ - No connection has been established. Use <tt>establish_connection</tt>
+ # * ConnectionNotEstablished - No connection has been established. Use <tt>establish_connection</tt>
# before querying.
# * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist
# or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 561e48d52e..a609867898 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -2,6 +2,7 @@ require 'thread'
require 'monitor'
require 'set'
require 'active_support/core_ext/module/deprecation'
+require 'timeout'
module ActiveRecord
# Raised when a connection could not be obtained within the connection
@@ -11,9 +12,6 @@ module ActiveRecord
# Raised when a connection pool is full and another connection is requested
class PoolFullError < ConnectionNotEstablished
- def initialize size, timeout
- super("Connection pool of size #{size} and timeout #{timeout}s is full")
- end
end
module ConnectionAdapters
@@ -94,6 +92,21 @@ module ActiveRecord
attr_accessor :automatic_reconnect, :timeout
attr_reader :spec, :connections, :size, :reaper
+ class Latch # :nodoc:
+ def initialize
+ @mutex = Mutex.new
+ @cond = ConditionVariable.new
+ end
+
+ def release
+ @mutex.synchronize { @cond.broadcast }
+ end
+
+ def await
+ @mutex.synchronize { @cond.wait @mutex }
+ end
+ end
+
# Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
# object which describes database connection information (e.g. adapter,
# host name, username, password, etc), as well as the maximum size for
@@ -115,6 +128,7 @@ module ActiveRecord
# default max pool size to 5
@size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
+ @latch = Latch.new
@connections = []
@automatic_reconnect = true
end
@@ -139,8 +153,10 @@ module ActiveRecord
# #release_connection releases the connection-thread association
# and returns the connection to the pool.
def release_connection(with_id = current_connection_id)
- conn = @reserved_connections.delete(with_id)
- checkin conn if conn
+ synchronize do
+ conn = @reserved_connections.delete(with_id)
+ checkin conn if conn
+ end
end
# If a connection already exists yield it to the block. If no connection
@@ -205,23 +221,23 @@ module ActiveRecord
# Raises:
# - PoolFullError: no connection can be obtained from the pool.
def checkout
- # Checkout an available connection
- synchronize do
- # Try to find a connection that hasn't been leased, and lease it
- conn = connections.find { |c| c.lease }
-
- # If all connections were leased, and we have room to expand,
- # create a new connection and lease it.
- if !conn && connections.size < size
- conn = checkout_new_connection
- conn.lease
- end
+ loop do
+ # Checkout an available connection
+ synchronize do
+ # Try to find a connection that hasn't been leased, and lease it
+ conn = connections.find { |c| c.lease }
+
+ # If all connections were leased, and we have room to expand,
+ # create a new connection and lease it.
+ if !conn && connections.size < size
+ conn = checkout_new_connection
+ conn.lease
+ end
- if conn
- checkout_and_verify conn
- else
- raise PoolFullError.new(size, timeout)
+ return checkout_and_verify(conn) if conn
end
+
+ Timeout.timeout(@timeout, PoolFullError) { @latch.await }
end
end
@@ -238,6 +254,7 @@ module ActiveRecord
release conn
end
+ @latch.release
end
# Remove a connection from the connection pool. The connection will
@@ -250,6 +267,7 @@ module ActiveRecord
# from the reserved hash will be a little easier.
release conn
end
+ @latch.release
end
# Removes dead connections from the pool. A dead connection can occur
@@ -262,6 +280,7 @@ module ActiveRecord
remove conn if conn.in_use? && stale > conn.last_use && !conn.active?
end
end
+ @latch.release
end
private
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index f08040a1a7..7b2961a04a 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -57,21 +57,21 @@ module ActiveRecord
end
# Executes insert +sql+ statement in the context of this connection using
- # +binds+ as the bind substitutes. +name+ is the logged along with
+ # +binds+ as the bind substitutes. +name+ is logged along with
# the executed +sql+ statement.
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
exec_query(sql, name, binds)
end
# Executes delete +sql+ statement in the context of this connection using
- # +binds+ as the bind substitutes. +name+ is the logged along with
+ # +binds+ as the bind substitutes. +name+ is logged along with
# the executed +sql+ statement.
def exec_delete(sql, name, binds)
exec_query(sql, name, binds)
end
# Executes update +sql+ statement in the context of this connection using
- # +binds+ as the bind substitutes. +name+ is the logged along with
+ # +binds+ as the bind substitutes. +name+ is logged along with
# the executed +sql+ statement.
def exec_update(sql, name, binds)
exec_query(sql, name, binds)
@@ -312,13 +312,27 @@ module ActiveRecord
# on mysql (even when aliasing the tables), but mysql allows using JOIN directly in
# an UPDATE statement, so in the mysql adapters we redefine this to do that.
def join_to_update(update, select) #:nodoc:
- subselect = select.clone
- subselect.projections = [update.key]
+ key = update.key
+ subselect = subquery_for(key, select)
- update.where update.key.in(subselect)
+ update.where key.in(subselect)
+ end
+
+ def join_to_delete(delete, select, key) #:nodoc:
+ subselect = subquery_for(key, select)
+
+ delete.where key.in(subselect)
end
protected
+
+ # Return a subquery for the given key using the join information.
+ def subquery_for(key, select)
+ subselect = select.clone
+ subselect.projections = [key]
+ subselect
+ end
+
# Returns an array of record hashes with the column names as keys and
# column values as values.
def select(sql, name = nil, binds = [])
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 7ee8f40631..3546873550 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -65,11 +65,12 @@ module ActiveRecord
class TableDefinition
# An array of ColumnDefinition objects, representing the column changes
# that have been defined.
- attr_accessor :columns
+ attr_accessor :columns, :indexes
def initialize(base)
@columns = []
@columns_hash = {}
+ @indexes = {}
@base = base
end
@@ -212,19 +213,22 @@ module ActiveRecord
#
# TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
# column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of
- # options, these will be used when creating the <tt>_type</tt> column. So what can be written like this:
+ # options, these will be used when creating the <tt>_type</tt> column. The <tt>:index</tt> option
+ # will also create an index, similar to calling <tt>add_index</tt>. So what can be written like this:
#
# create_table :taggings do |t|
# t.integer :tag_id, :tagger_id, :taggable_id
# t.string :tagger_type
# t.string :taggable_type, :default => 'Photo'
# end
+ # add_index :taggings, :tag_id, :name => 'index_taggings_on_tag_id'
+ # add_index :taggings, [:tagger_id, :tagger_type]
#
# Can also be written as follows using references:
#
# create_table :taggings do |t|
- # t.references :tag
- # t.references :tagger, :polymorphic => true
+ # t.references :tag, :index => { :name => 'index_taggings_on_tag_id' }
+ # t.references :tagger, :polymorphic => true, :index => true
# t.references :taggable, :polymorphic => { :default => 'Photo' }
# end
def column(name, type, options = {})
@@ -255,6 +259,14 @@ module ActiveRecord
end # end
EOV
end
+
+ # Adds index options to the indexes hash, keyed by column name
+ # This is primarily used to track indexes that need to be created after the table
+ # === Examples
+ # index(:account_id, :name => 'index_projects_on_account_id')
+ def index(column_name, options = {})
+ indexes[column_name] = options
+ end
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
# <tt>:updated_at</tt> to the table.
@@ -267,9 +279,11 @@ module ActiveRecord
def references(*args)
options = args.extract_options!
polymorphic = options.delete(:polymorphic)
+ index_options = options.delete(:index)
args.each do |col|
column("#{col}_id", :integer, options)
column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
+ index(polymorphic ? %w(id type).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : nil) if index_options
end
end
alias :belongs_to :references
@@ -435,9 +449,11 @@ module ActiveRecord
def references(*args)
options = args.extract_options!
polymorphic = options.delete(:polymorphic)
+ index_options = options.delete(:index)
args.each do |col|
@base.add_column(@table_name, "#{col}_id", :integer, options)
@base.add_column(@table_name, "#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
+ @base.add_index(@table_name, polymorphic ? %w(id type).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : nil) if index_options
end
end
alias :belongs_to :references
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 8b9e830040..30a4f9aa35 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -16,7 +16,7 @@ module ActiveRecord
# Truncates a table alias according to the limits of the current adapter.
def table_alias_for(table_name)
- table_name[0...table_alias_length].gsub(/\./, '_')
+ table_name[0...table_alias_length].tr('.', '_')
end
# Checks to see if the table +table_name+ exists on the database.
@@ -171,6 +171,7 @@ module ActiveRecord
create_sql << td.to_sql
create_sql << ") #{options[:options]}"
execute create_sql
+ td.indexes.each_pair { |c,o| add_index table_name, c, o }
end
# Creates a new join table with the name created using the lexical order of the first two
@@ -375,7 +376,7 @@ module ActiveRecord
# Note: SQLite doesn't support index length
#
# ====== Creating an index with a sort order (desc or asc, asc is the default)
- # add_index(:accounts, [:branch_id, :party_id, :surname], :order => {:branch_id => :desc, :part_id => :asc})
+ # add_index(:accounts, [:branch_id, :party_id, :surname], :order => {:branch_id => :desc, :party_id => :asc})
# generates
# CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
#
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 1d713e472b..c6faae77cc 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -163,11 +163,6 @@ module ActiveRecord
# QUOTING ==================================================
- # Override to return the quoted table name. Defaults to column quoting.
- def quote_table_name(name)
- quote_column_name(name)
- end
-
# Returns a bind substitution value given a +column+ and list of current
# +binds+
def substitute_at(column, index)
@@ -299,7 +294,7 @@ module ActiveRecord
raise exception
end
- def translate_exception(e, message)
+ def translate_exception(exception, message)
# override in derived class
ActiveRecord::StatementInvalid.new(message)
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 64f922b7ad..a848838a4e 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -294,19 +294,10 @@ module ActiveRecord
# In the simple case, MySQL allows us to place JOINs directly into the UPDATE
# query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
- # these, we must use a subquery. However, MySQL is too stupid to create a
- # temporary table for this automatically, so we have to give it some prompting
- # in the form of a subsubquery. Ugh!
+ # these, we must use a subquery.
def join_to_update(update, select) #:nodoc:
if select.limit || select.offset || select.orders.any?
- subsubselect = select.clone
- subsubselect.projections = [update.key]
-
- subselect = Arel::SelectManager.new(select.engine)
- subselect.project Arel.sql(update.key.name)
- subselect.from subsubselect.as('__active_record_temp')
-
- update.where update.key.in(subselect)
+ super
else
update.table select.source
update.wheres = select.constraints
@@ -525,7 +516,7 @@ module ActiveRecord
def pk_and_sequence_for(table)
execute_and_free("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA') do |result|
create_table = each_hash(result).first[:"Create Table"]
- if create_table.to_s =~ /PRIMARY KEY\s+\((.+)\)/
+ if create_table.to_s =~ /PRIMARY KEY\s+(?:USING\s+\w+\s+)?\((.+)\)/
keys = $1.split(",").map { |key| key.delete('`"') }
keys.length == 1 ? [keys.first, nil] : nil
else
@@ -558,6 +549,17 @@ module ActiveRecord
protected
+ # MySQL is too stupid to create a temporary table for use subquery, so we have
+ # to give it some prompting in the form of a subsubquery. Ugh!
+ def subquery_for(key, select)
+ subsubselect = select.clone
+ subsubselect.projections = [key]
+
+ subselect = Arel::SelectManager.new(select.engine)
+ subselect.project Arel.sql(key.name)
+ subselect.from subsubselect.as('__active_record_temp')
+ end
+
def add_index_length(option_strings, column_names, options = {})
if options.is_a?(Hash) && length = options[:length]
case length
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 78c00d9341..273c165084 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -88,9 +88,8 @@ module ActiveRecord
def escape_hstore(value)
value.nil? ? 'NULL'
- : value =~ /[=\s,>]/ ? '"%s"' % value.gsub(/(["\\])/, '\\\\\1')
: value == "" ? '""'
- : value.to_s.gsub(/(["\\])/, '\\\\\1')
+ : '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
end
end
# :startdoc:
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index ee5d10859c..83f75e3505 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -1,6 +1,8 @@
-require 'active_record/connection_adapters/sqlite_adapter'
+require 'active_record/connection_adapters/abstract_adapter'
+require 'active_record/connection_adapters/statement_pool'
+require 'arel/visitors/bind_visitor'
-gem 'sqlite3', '~> 1.3.5'
+gem 'sqlite3', '~> 1.3.6'
require 'sqlite3'
module ActiveRecord
@@ -35,7 +37,184 @@ module ActiveRecord
end
module ConnectionAdapters #:nodoc:
- class SQLite3Adapter < SQLiteAdapter # :nodoc:
+ class SQLite3Column < Column #:nodoc:
+ class << self
+ def binary_to_string(value)
+ if value.encoding != Encoding::ASCII_8BIT
+ value = value.force_encoding(Encoding::ASCII_8BIT)
+ end
+ value
+ end
+ end
+ end
+
+ # The SQLite3 adapter works SQLite 3.6.16 or newer
+ # with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3).
+ #
+ # Options:
+ #
+ # * <tt>:database</tt> - Path to the database file.
+ class SQLite3Adapter < AbstractAdapter
+ class Version
+ include Comparable
+
+ def initialize(version_string)
+ @version = version_string.split('.').map { |v| v.to_i }
+ end
+
+ def <=>(version_string)
+ @version <=> version_string.split('.').map { |v| v.to_i }
+ end
+ end
+
+ class StatementPool < ConnectionAdapters::StatementPool
+ def initialize(connection, max)
+ super
+ @cache = Hash.new { |h,pid| h[pid] = {} }
+ end
+
+ def each(&block); cache.each(&block); end
+ def key?(key); cache.key?(key); end
+ def [](key); cache[key]; end
+ def length; cache.length; end
+
+ def []=(sql, key)
+ while @max <= cache.size
+ dealloc(cache.shift.last[:stmt])
+ end
+ cache[sql] = key
+ end
+
+ def clear
+ cache.values.each do |hash|
+ dealloc hash[:stmt]
+ end
+ cache.clear
+ end
+
+ private
+ def cache
+ @cache[$$]
+ end
+
+ def dealloc(stmt)
+ stmt.close unless stmt.closed?
+ end
+ end
+
+ class BindSubstitution < Arel::Visitors::SQLite # :nodoc:
+ include Arel::Visitors::BindVisitor
+ end
+
+ def initialize(connection, logger, config)
+ super(connection, logger)
+ @statements = StatementPool.new(@connection,
+ config.fetch(:statement_limit) { 1000 })
+ @config = config
+
+ if config.fetch(:prepared_statements) { true }
+ @visitor = Arel::Visitors::SQLite.new self
+ else
+ @visitor = BindSubstitution.new self
+ end
+ end
+
+ def adapter_name #:nodoc:
+ 'SQLite'
+ end
+
+ # Returns true
+ def supports_ddl_transactions?
+ true
+ end
+
+ # Returns true if SQLite version is '3.6.8' or greater, false otherwise.
+ def supports_savepoints?
+ sqlite_version >= '3.6.8'
+ end
+
+ # Returns true, since this connection adapter supports prepared statement
+ # caching.
+ def supports_statement_cache?
+ true
+ end
+
+ # Returns true, since this connection adapter supports migrations.
+ def supports_migrations? #:nodoc:
+ true
+ end
+
+ # Returns true.
+ def supports_primary_key? #:nodoc:
+ true
+ end
+
+ def requires_reloading?
+ true
+ end
+
+ # Returns true
+ def supports_add_column?
+ true
+ end
+
+ # Disconnects from the database if already connected. Otherwise, this
+ # method does nothing.
+ def disconnect!
+ super
+ clear_cache!
+ @connection.close rescue nil
+ end
+
+ # Clears the prepared statements cache.
+ def clear_cache!
+ @statements.clear
+ end
+
+ # Returns true
+ def supports_count_distinct? #:nodoc:
+ true
+ end
+
+ # Returns true
+ def supports_autoincrement? #:nodoc:
+ true
+ end
+
+ def supports_index_sort_order?
+ true
+ end
+
+ def native_database_types #:nodoc:
+ {
+ :primary_key => default_primary_key_type,
+ :string => { :name => "varchar", :limit => 255 },
+ :text => { :name => "text" },
+ :integer => { :name => "integer" },
+ :float => { :name => "float" },
+ :decimal => { :name => "decimal" },
+ :datetime => { :name => "datetime" },
+ :timestamp => { :name => "datetime" },
+ :time => { :name => "time" },
+ :date => { :name => "date" },
+ :binary => { :name => "blob" },
+ :boolean => { :name => "boolean" }
+ }
+ end
+
+ # Returns the current database encoding format as a string, eg: 'UTF-8'
+ def encoding
+ @connection.encoding.to_s
+ end
+
+ # Returns true.
+ def supports_explain?
+ true
+ end
+
+
+ # QUOTING ==================================================
+
def quote(value, column = nil)
if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
s = column.class.string_to_binary(value).unpack("H*")[0]
@@ -45,10 +224,387 @@ module ActiveRecord
end
end
- # Returns the current database encoding format as a string, eg: 'UTF-8'
- def encoding
- @connection.encoding.to_s
+
+ def quote_string(s) #:nodoc:
+ @connection.class.quote(s)
+ end
+
+ def quote_column_name(name) #:nodoc:
+ %Q("#{name.to_s.gsub('"', '""')}")
+ end
+
+ # Quote date/time values for use in SQL input. Includes microseconds
+ # if the value is a Time responding to usec.
+ def quoted_date(value) #:nodoc:
+ if value.respond_to?(:usec)
+ "#{super}.#{sprintf("%06d", value.usec)}"
+ else
+ super
+ end
+ end
+
+ def type_cast(value, column) # :nodoc:
+ return value.to_f if BigDecimal === value
+ return super unless String === value
+ return super unless column && value
+
+ value = super
+ if column.type == :string && value.encoding == Encoding::ASCII_8BIT
+ logger.error "Binary data inserted for `string` type on column `#{column.name}`" if logger
+ value.encode! 'utf-8'
+ end
+ value
+ end
+
+ # DATABASE STATEMENTS ======================================
+
+ def explain(arel, binds = [])
+ sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
+ ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
+ end
+
+ class ExplainPrettyPrinter
+ # Pretty prints the result of a EXPLAIN QUERY PLAN in a way that resembles
+ # the output of the SQLite shell:
+ #
+ # 0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
+ # 0|1|1|SCAN TABLE posts (~100000 rows)
+ #
+ def pp(result) # :nodoc:
+ result.rows.map do |row|
+ row.join('|')
+ end.join("\n") + "\n"
+ end
+ end
+
+ def exec_query(sql, name = nil, binds = [])
+ log(sql, name, binds) do
+
+ # Don't cache statements without bind values
+ if binds.empty?
+ stmt = @connection.prepare(sql)
+ cols = stmt.columns
+ records = stmt.to_a
+ stmt.close
+ stmt = records
+ else
+ cache = @statements[sql] ||= {
+ :stmt => @connection.prepare(sql)
+ }
+ stmt = cache[:stmt]
+ cols = cache[:cols] ||= stmt.columns
+ stmt.reset!
+ stmt.bind_params binds.map { |col, val|
+ type_cast(val, col)
+ }
+ end
+
+ ActiveRecord::Result.new(cols, stmt.to_a)
+ end
+ end
+
+ def exec_delete(sql, name = 'SQL', binds = [])
+ exec_query(sql, name, binds)
+ @connection.changes
end
+ alias :exec_update :exec_delete
+
+ def last_inserted_id(result)
+ @connection.last_insert_row_id
+ end
+
+ def execute(sql, name = nil) #:nodoc:
+ log(sql, name) { @connection.execute(sql) }
+ end
+
+ def update_sql(sql, name = nil) #:nodoc:
+ super
+ @connection.changes
+ end
+
+ def delete_sql(sql, name = nil) #:nodoc:
+ sql += " WHERE 1=1" unless sql =~ /WHERE/i
+ super sql, name
+ end
+
+ def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
+ super
+ id_value || @connection.last_insert_row_id
+ end
+ alias :create :insert_sql
+
+ def select_rows(sql, name = nil)
+ exec_query(sql, name).rows
+ end
+
+ def create_savepoint
+ execute("SAVEPOINT #{current_savepoint_name}")
+ end
+
+ def rollback_to_savepoint
+ execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
+ end
+
+ def release_savepoint
+ execute("RELEASE SAVEPOINT #{current_savepoint_name}")
+ end
+
+ def begin_db_transaction #:nodoc:
+ log('begin transaction',nil) { @connection.transaction }
+ end
+
+ def commit_db_transaction #:nodoc:
+ log('commit transaction',nil) { @connection.commit }
+ end
+
+ def rollback_db_transaction #:nodoc:
+ log('rollback transaction',nil) { @connection.rollback }
+ end
+
+ # SCHEMA STATEMENTS ========================================
+
+ def tables(name = 'SCHEMA', table_name = nil) #:nodoc:
+ sql = <<-SQL
+ SELECT name
+ FROM sqlite_master
+ WHERE type = 'table' AND NOT name = 'sqlite_sequence'
+ SQL
+ sql << " AND name = #{quote_table_name(table_name)}" if table_name
+
+ exec_query(sql, name).map do |row|
+ row['name']
+ end
+ end
+
+ def table_exists?(name)
+ name && tables('SCHEMA', name).any?
+ end
+
+ # Returns an array of +SQLite3Column+ objects for the table specified by +table_name+.
+ def columns(table_name) #:nodoc:
+ table_structure(table_name).map do |field|
+ case field["dflt_value"]
+ when /^null$/i
+ field["dflt_value"] = nil
+ when /^'(.*)'$/
+ field["dflt_value"] = $1.gsub("''", "'")
+ when /^"(.*)"$/
+ field["dflt_value"] = $1.gsub('""', '"')
+ end
+
+ SQLite3Column.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0)
+ end
+ end
+
+ # Returns an array of indexes for the given table.
+ def indexes(table_name, name = nil) #:nodoc:
+ exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row|
+ IndexDefinition.new(
+ table_name,
+ row['name'],
+ row['unique'] != 0,
+ exec_query("PRAGMA index_info('#{row['name']}')").map { |col|
+ col['name']
+ })
+ end
+ end
+
+ def primary_key(table_name) #:nodoc:
+ column = table_structure(table_name).find { |field|
+ field['pk'] == 1
+ }
+ column && column['name']
+ end
+
+ def remove_index!(table_name, index_name) #:nodoc:
+ exec_query "DROP INDEX #{quote_column_name(index_name)}"
+ end
+
+ # Renames a table.
+ #
+ # Example:
+ # rename_table('octopuses', 'octopi')
+ def rename_table(name, new_name)
+ exec_query "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
+ end
+
+ # See: http://www.sqlite.org/lang_altertable.html
+ # SQLite has an additional restriction on the ALTER TABLE statement
+ def valid_alter_table_options( type, options)
+ type.to_sym != :primary_key
+ end
+
+ def add_column(table_name, column_name, type, options = {}) #:nodoc:
+ if supports_add_column? && valid_alter_table_options( type, options )
+ super(table_name, column_name, type, options)
+ else
+ alter_table(table_name) do |definition|
+ definition.column(column_name, type, options)
+ end
+ end
+ end
+
+ def remove_column(table_name, *column_names) #:nodoc:
+ raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
+ column_names.flatten.each do |column_name|
+ alter_table(table_name) do |definition|
+ definition.columns.delete(definition[column_name])
+ end
+ end
+ end
+ alias :remove_columns :remove_column
+
+ def change_column_default(table_name, column_name, default) #:nodoc:
+ alter_table(table_name) do |definition|
+ definition[column_name].default = default
+ end
+ end
+
+ def change_column_null(table_name, column_name, null, default = nil)
+ unless null || default.nil?
+ exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
+ end
+ alter_table(table_name) do |definition|
+ definition[column_name].null = null
+ end
+ end
+
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
+ alter_table(table_name) do |definition|
+ include_default = options_include_default?(options)
+ definition[column_name].instance_eval do
+ self.type = type
+ self.limit = options[:limit] if options.include?(:limit)
+ self.default = options[:default] if include_default
+ self.null = options[:null] if options.include?(:null)
+ self.precision = options[:precision] if options.include?(:precision)
+ self.scale = options[:scale] if options.include?(:scale)
+ end
+ end
+ end
+
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
+ unless columns(table_name).detect{|c| c.name == column_name.to_s }
+ raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
+ end
+ alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
+ end
+
+ def empty_insert_statement_value
+ "VALUES(NULL)"
+ end
+
+ protected
+ def select(sql, name = nil, binds = []) #:nodoc:
+ exec_query(sql, name, binds)
+ end
+
+ def table_structure(table_name)
+ structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA').to_hash
+ raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
+ structure
+ end
+
+ def alter_table(table_name, options = {}) #:nodoc:
+ altered_table_name = "altered_#{table_name}"
+ caller = lambda {|definition| yield definition if block_given?}
+
+ transaction do
+ move_table(table_name, altered_table_name,
+ options.merge(:temporary => true))
+ move_table(altered_table_name, table_name, &caller)
+ end
+ end
+
+ def move_table(from, to, options = {}, &block) #:nodoc:
+ copy_table(from, to, options, &block)
+ drop_table(from)
+ end
+
+ def copy_table(from, to, options = {}) #:nodoc:
+ options = options.merge(:id => (!columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
+ create_table(to, options) do |definition|
+ @definition = definition
+ columns(from).each do |column|
+ column_name = options[:rename] ?
+ (options[:rename][column.name] ||
+ options[:rename][column.name.to_sym] ||
+ column.name) : column.name
+
+ @definition.column(column_name, column.type,
+ :limit => column.limit, :default => column.default,
+ :precision => column.precision, :scale => column.scale,
+ :null => column.null)
+ end
+ @definition.primary_key(primary_key(from)) if primary_key(from)
+ yield @definition if block_given?
+ end
+
+ copy_table_indexes(from, to, options[:rename] || {})
+ copy_table_contents(from, to,
+ @definition.columns.map {|column| column.name},
+ options[:rename] || {})
+ end
+
+ def copy_table_indexes(from, to, rename = {}) #:nodoc:
+ indexes(from).each do |index|
+ name = index.name
+ if to == "altered_#{from}"
+ name = "temp_#{name}"
+ elsif from == "altered_#{to}"
+ name = name[5..-1]
+ end
+
+ to_column_names = columns(to).map { |c| c.name }
+ columns = index.columns.map {|c| rename[c] || c }.select do |column|
+ to_column_names.include?(column)
+ end
+
+ unless columns.empty?
+ # index name can't be the same
+ opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
+ opts[:unique] = true if index.unique
+ add_index(to, columns, opts)
+ end
+ end
+ end
+
+ def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
+ column_mappings = Hash[columns.map {|name| [name, name]}]
+ rename.each { |a| column_mappings[a.last] = a.first }
+ from_columns = columns(from).collect {|col| col.name}
+ columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
+ quoted_columns = columns.map { |col| quote_column_name(col) } * ','
+
+ quoted_to = quote_table_name(to)
+ exec_query("SELECT * FROM #{quote_table_name(from)}").each do |row|
+ sql = "INSERT INTO #{quoted_to} (#{quoted_columns}) VALUES ("
+ sql << columns.map {|col| quote row[column_mappings[col]]} * ', '
+ sql << ')'
+ exec_query sql
+ end
+ end
+
+ def sqlite_version
+ @sqlite_version ||= SQLite3Adapter::Version.new(select_value('select sqlite_version(*)'))
+ end
+
+ def default_primary_key_type
+ if supports_autoincrement?
+ 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL'
+ else
+ 'INTEGER PRIMARY KEY NOT NULL'
+ end
+ end
+
+ def translate_exception(exception, message)
+ case exception.message
+ when /column(s)? .* (is|are) not unique/
+ RecordNotUnique.new(message, exception)
+ else
+ super
+ end
+ end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
deleted file mode 100644
index 3d8dfab05c..0000000000
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ /dev/null
@@ -1,563 +0,0 @@
-require 'active_record/connection_adapters/abstract_adapter'
-require 'active_record/connection_adapters/statement_pool'
-require 'arel/visitors/bind_visitor'
-
-module ActiveRecord
- module ConnectionAdapters #:nodoc:
- class SQLiteColumn < Column #:nodoc:
- class << self
- def binary_to_string(value)
- if value.encoding != Encoding::ASCII_8BIT
- value = value.force_encoding(Encoding::ASCII_8BIT)
- end
- value
- end
- end
- end
-
- # The SQLite adapter works with both the 2.x and 3.x series of SQLite with the sqlite-ruby
- # drivers (available both as gems and from http://rubyforge.org/projects/sqlite-ruby/).
- #
- # Options:
- #
- # * <tt>:database</tt> - Path to the database file.
- class SQLiteAdapter < AbstractAdapter
- class Version
- include Comparable
-
- def initialize(version_string)
- @version = version_string.split('.').map { |v| v.to_i }
- end
-
- def <=>(version_string)
- @version <=> version_string.split('.').map { |v| v.to_i }
- end
- end
-
- class StatementPool < ConnectionAdapters::StatementPool
- def initialize(connection, max)
- super
- @cache = Hash.new { |h,pid| h[pid] = {} }
- end
-
- def each(&block); cache.each(&block); end
- def key?(key); cache.key?(key); end
- def [](key); cache[key]; end
- def length; cache.length; end
-
- def []=(sql, key)
- while @max <= cache.size
- dealloc(cache.shift.last[:stmt])
- end
- cache[sql] = key
- end
-
- def clear
- cache.values.each do |hash|
- dealloc hash[:stmt]
- end
- cache.clear
- end
-
- private
- def cache
- @cache[$$]
- end
-
- def dealloc(stmt)
- stmt.close unless stmt.closed?
- end
- end
-
- class BindSubstitution < Arel::Visitors::SQLite # :nodoc:
- include Arel::Visitors::BindVisitor
- end
-
- def initialize(connection, logger, config)
- super(connection, logger)
- @statements = StatementPool.new(@connection,
- config.fetch(:statement_limit) { 1000 })
- @config = config
-
- if config.fetch(:prepared_statements) { true }
- @visitor = Arel::Visitors::SQLite.new self
- else
- @visitor = BindSubstitution.new self
- end
- end
-
- def adapter_name #:nodoc:
- 'SQLite'
- end
-
- # Returns true if SQLite version is '2.0.0' or greater, false otherwise.
- def supports_ddl_transactions?
- sqlite_version >= '2.0.0'
- end
-
- # Returns true if SQLite version is '3.6.8' or greater, false otherwise.
- def supports_savepoints?
- sqlite_version >= '3.6.8'
- end
-
- # Returns true, since this connection adapter supports prepared statement
- # caching.
- def supports_statement_cache?
- true
- end
-
- # Returns true, since this connection adapter supports migrations.
- def supports_migrations? #:nodoc:
- true
- end
-
- # Returns true.
- def supports_primary_key? #:nodoc:
- true
- end
-
- # Returns true.
- def supports_explain?
- true
- end
-
- def requires_reloading?
- true
- end
-
- # Returns true if SQLite version is '3.1.6' or greater, false otherwise.
- def supports_add_column?
- sqlite_version >= '3.1.6'
- end
-
- # Disconnects from the database if already connected. Otherwise, this
- # method does nothing.
- def disconnect!
- super
- clear_cache!
- @connection.close rescue nil
- end
-
- # Clears the prepared statements cache.
- def clear_cache!
- @statements.clear
- end
-
- # Returns true if SQLite version is '3.2.6' or greater, false otherwise.
- def supports_count_distinct? #:nodoc:
- sqlite_version >= '3.2.6'
- end
-
- # Returns true if SQLite version is '3.1.0' or greater, false otherwise.
- def supports_autoincrement? #:nodoc:
- sqlite_version >= '3.1.0'
- end
-
- def supports_index_sort_order?
- sqlite_version >= '3.3.0'
- end
-
- def native_database_types #:nodoc:
- {
- :primary_key => default_primary_key_type,
- :string => { :name => "varchar", :limit => 255 },
- :text => { :name => "text" },
- :integer => { :name => "integer" },
- :float => { :name => "float" },
- :decimal => { :name => "decimal" },
- :datetime => { :name => "datetime" },
- :timestamp => { :name => "datetime" },
- :time => { :name => "time" },
- :date => { :name => "date" },
- :binary => { :name => "blob" },
- :boolean => { :name => "boolean" }
- }
- end
-
-
- # QUOTING ==================================================
-
- def quote_string(s) #:nodoc:
- @connection.class.quote(s)
- end
-
- def quote_column_name(name) #:nodoc:
- %Q("#{name.to_s.gsub('"', '""')}")
- end
-
- # Quote date/time values for use in SQL input. Includes microseconds
- # if the value is a Time responding to usec.
- def quoted_date(value) #:nodoc:
- if value.respond_to?(:usec)
- "#{super}.#{sprintf("%06d", value.usec)}"
- else
- super
- end
- end
-
- def type_cast(value, column) # :nodoc:
- return value.to_f if BigDecimal === value
- return super unless String === value
- return super unless column && value
-
- value = super
- if column.type == :string && value.encoding == Encoding::ASCII_8BIT
- logger.error "Binary data inserted for `string` type on column `#{column.name}`" if logger
- value.encode! 'utf-8'
- end
- value
- end
-
- # DATABASE STATEMENTS ======================================
-
- def explain(arel, binds = [])
- sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
- ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
- end
-
- class ExplainPrettyPrinter
- # Pretty prints the result of a EXPLAIN QUERY PLAN in a way that resembles
- # the output of the SQLite shell:
- #
- # 0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
- # 0|1|1|SCAN TABLE posts (~100000 rows)
- #
- def pp(result) # :nodoc:
- result.rows.map do |row|
- row.join('|')
- end.join("\n") + "\n"
- end
- end
-
- def exec_query(sql, name = nil, binds = [])
- log(sql, name, binds) do
-
- # Don't cache statements without bind values
- if binds.empty?
- stmt = @connection.prepare(sql)
- cols = stmt.columns
- records = stmt.to_a
- stmt.close
- stmt = records
- else
- cache = @statements[sql] ||= {
- :stmt => @connection.prepare(sql)
- }
- stmt = cache[:stmt]
- cols = cache[:cols] ||= stmt.columns
- stmt.reset!
- stmt.bind_params binds.map { |col, val|
- type_cast(val, col)
- }
- end
-
- ActiveRecord::Result.new(cols, stmt.to_a)
- end
- end
-
- def exec_delete(sql, name = 'SQL', binds = [])
- exec_query(sql, name, binds)
- @connection.changes
- end
- alias :exec_update :exec_delete
-
- def last_inserted_id(result)
- @connection.last_insert_row_id
- end
-
- def execute(sql, name = nil) #:nodoc:
- log(sql, name) { @connection.execute(sql) }
- end
-
- def update_sql(sql, name = nil) #:nodoc:
- super
- @connection.changes
- end
-
- def delete_sql(sql, name = nil) #:nodoc:
- sql += " WHERE 1=1" unless sql =~ /WHERE/i
- super sql, name
- end
-
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
- super
- id_value || @connection.last_insert_row_id
- end
- alias :create :insert_sql
-
- def select_rows(sql, name = nil)
- exec_query(sql, name).rows
- end
-
- def create_savepoint
- execute("SAVEPOINT #{current_savepoint_name}")
- end
-
- def rollback_to_savepoint
- execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
- end
-
- def release_savepoint
- execute("RELEASE SAVEPOINT #{current_savepoint_name}")
- end
-
- def begin_db_transaction #:nodoc:
- log('begin transaction',nil) { @connection.transaction }
- end
-
- def commit_db_transaction #:nodoc:
- log('commit transaction',nil) { @connection.commit }
- end
-
- def rollback_db_transaction #:nodoc:
- log('rollback transaction',nil) { @connection.rollback }
- end
-
- # SCHEMA STATEMENTS ========================================
-
- def tables(name = 'SCHEMA', table_name = nil) #:nodoc:
- sql = <<-SQL
- SELECT name
- FROM sqlite_master
- WHERE type = 'table' AND NOT name = 'sqlite_sequence'
- SQL
- sql << " AND name = #{quote_table_name(table_name)}" if table_name
-
- exec_query(sql, name).map do |row|
- row['name']
- end
- end
-
- def table_exists?(name)
- name && tables('SCHEMA', name).any?
- end
-
- # Returns an array of +SQLiteColumn+ objects for the table specified by +table_name+.
- def columns(table_name) #:nodoc:
- table_structure(table_name).map do |field|
- case field["dflt_value"]
- when /^null$/i
- field["dflt_value"] = nil
- when /^'(.*)'$/
- field["dflt_value"] = $1.gsub(/''/, "'")
- when /^"(.*)"$/
- field["dflt_value"] = $1.gsub(/""/, '"')
- end
-
- SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0)
- end
- end
-
- # Returns an array of indexes for the given table.
- def indexes(table_name, name = nil) #:nodoc:
- exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row|
- IndexDefinition.new(
- table_name,
- row['name'],
- row['unique'] != 0,
- exec_query("PRAGMA index_info('#{row['name']}')").map { |col|
- col['name']
- })
- end
- end
-
- def primary_key(table_name) #:nodoc:
- column = table_structure(table_name).find { |field|
- field['pk'] == 1
- }
- column && column['name']
- end
-
- def remove_index!(table_name, index_name) #:nodoc:
- exec_query "DROP INDEX #{quote_column_name(index_name)}"
- end
-
- # Renames a table.
- #
- # Example:
- # rename_table('octopuses', 'octopi')
- def rename_table(name, new_name)
- exec_query "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
- end
-
- # See: http://www.sqlite.org/lang_altertable.html
- # SQLite has an additional restriction on the ALTER TABLE statement
- def valid_alter_table_options( type, options)
- type.to_sym != :primary_key
- end
-
- def add_column(table_name, column_name, type, options = {}) #:nodoc:
- if supports_add_column? && valid_alter_table_options( type, options )
- super(table_name, column_name, type, options)
- else
- alter_table(table_name) do |definition|
- definition.column(column_name, type, options)
- end
- end
- end
-
- def remove_column(table_name, *column_names) #:nodoc:
- raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
- column_names.flatten.each do |column_name|
- alter_table(table_name) do |definition|
- definition.columns.delete(definition[column_name])
- end
- end
- end
- alias :remove_columns :remove_column
-
- def change_column_default(table_name, column_name, default) #:nodoc:
- alter_table(table_name) do |definition|
- definition[column_name].default = default
- end
- end
-
- def change_column_null(table_name, column_name, null, default = nil)
- unless null || default.nil?
- exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
- end
- alter_table(table_name) do |definition|
- definition[column_name].null = null
- end
- end
-
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
- alter_table(table_name) do |definition|
- include_default = options_include_default?(options)
- definition[column_name].instance_eval do
- self.type = type
- self.limit = options[:limit] if options.include?(:limit)
- self.default = options[:default] if include_default
- self.null = options[:null] if options.include?(:null)
- self.precision = options[:precision] if options.include?(:precision)
- self.scale = options[:scale] if options.include?(:scale)
- end
- end
- end
-
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
- unless columns(table_name).detect{|c| c.name == column_name.to_s }
- raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
- end
- alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
- end
-
- def empty_insert_statement_value
- "VALUES(NULL)"
- end
-
- protected
- def select(sql, name = nil, binds = []) #:nodoc:
- exec_query(sql, name, binds)
- end
-
- def table_structure(table_name)
- structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA').to_hash
- raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
- structure
- end
-
- def alter_table(table_name, options = {}) #:nodoc:
- altered_table_name = "altered_#{table_name}"
- caller = lambda {|definition| yield definition if block_given?}
-
- transaction do
- move_table(table_name, altered_table_name,
- options.merge(:temporary => true))
- move_table(altered_table_name, table_name, &caller)
- end
- end
-
- def move_table(from, to, options = {}, &block) #:nodoc:
- copy_table(from, to, options, &block)
- drop_table(from)
- end
-
- def copy_table(from, to, options = {}) #:nodoc:
- options = options.merge(:id => (!columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
- create_table(to, options) do |definition|
- @definition = definition
- columns(from).each do |column|
- column_name = options[:rename] ?
- (options[:rename][column.name] ||
- options[:rename][column.name.to_sym] ||
- column.name) : column.name
-
- @definition.column(column_name, column.type,
- :limit => column.limit, :default => column.default,
- :precision => column.precision, :scale => column.scale,
- :null => column.null)
- end
- @definition.primary_key(primary_key(from)) if primary_key(from)
- yield @definition if block_given?
- end
-
- copy_table_indexes(from, to, options[:rename] || {})
- copy_table_contents(from, to,
- @definition.columns.map {|column| column.name},
- options[:rename] || {})
- end
-
- def copy_table_indexes(from, to, rename = {}) #:nodoc:
- indexes(from).each do |index|
- name = index.name
- if to == "altered_#{from}"
- name = "temp_#{name}"
- elsif from == "altered_#{to}"
- name = name[5..-1]
- end
-
- to_column_names = columns(to).map { |c| c.name }
- columns = index.columns.map {|c| rename[c] || c }.select do |column|
- to_column_names.include?(column)
- end
-
- unless columns.empty?
- # index name can't be the same
- opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
- opts[:unique] = true if index.unique
- add_index(to, columns, opts)
- end
- end
- end
-
- def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
- column_mappings = Hash[columns.map {|name| [name, name]}]
- rename.each { |a| column_mappings[a.last] = a.first }
- from_columns = columns(from).collect {|col| col.name}
- columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
- quoted_columns = columns.map { |col| quote_column_name(col) } * ','
-
- quoted_to = quote_table_name(to)
- exec_query("SELECT * FROM #{quote_table_name(from)}").each do |row|
- sql = "INSERT INTO #{quoted_to} (#{quoted_columns}) VALUES ("
- sql << columns.map {|col| quote row[column_mappings[col]]} * ', '
- sql << ')'
- exec_query sql
- end
- end
-
- def sqlite_version
- @sqlite_version ||= SQLiteAdapter::Version.new(select_value('select sqlite_version(*)'))
- end
-
- def default_primary_key_type
- if supports_autoincrement?
- 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL'
- else
- 'INTEGER PRIMARY KEY NOT NULL'
- end
- end
-
- def translate_exception(exception, message)
- case exception.message
- when /column(s)? .* (is|are) not unique/
- RecordNotUnique.new(message, exception)
- else
- super
- end
- end
-
- end
- end
-end
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 76c424e8b4..eb8f4ad669 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -137,12 +137,12 @@ module ActiveRecord
private
def relation #:nodoc:
- @relation ||= Relation.new(self, arel_table)
+ relation = Relation.new(self, arel_table)
if finder_needs_type_condition?
- @relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
+ relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
else
- @relation
+ relation
end
end
end
@@ -351,7 +351,6 @@ module ActiveRecord
@attributes[pk] = nil unless @attributes.key?(pk)
- @relation = nil
@aggregation_cache = {}
@association_cache = {}
@attributes_cache = {}
diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb
index f52979ebd9..b163ef3c12 100644
--- a/activerecord/lib/active_record/counter_cache.rb
+++ b/activerecord/lib/active_record/counter_cache.rb
@@ -69,7 +69,7 @@ module ActiveRecord
"#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
end
- update_all(updates.join(', '), primary_key => id)
+ where(primary_key => id).update_all updates.join(', ')
end
# Increment a number field by one, usually representing a count.
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index c85d590ce1..7f38dda11e 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -172,8 +172,8 @@ module ActiveRecord
end
def reset_sequence_name #:nodoc:
- @sequence_name = connection.default_sequence_name(table_name, primary_key)
@explicit_sequence_name = false
+ @sequence_name = connection.default_sequence_name(table_name, primary_key)
end
# Sets the name of the sequence to use when generating ids to the given
diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb
index 60c37ac2b7..c2d3eeb8ce 100644
--- a/activerecord/lib/active_record/null_relation.rb
+++ b/activerecord/lib/active_record/null_relation.rb
@@ -6,5 +6,58 @@ module ActiveRecord
def exec_queries
@records = []
end
+
+ def pluck(column_name)
+ []
+ end
+
+ def delete_all(conditions = nil)
+ 0
+ end
+
+ def update_all(updates, conditions = nil, options = {})
+ 0
+ end
+
+ def delete(id_or_array)
+ 0
+ end
+
+ def size
+ 0
+ end
+
+ def empty?
+ true
+ end
+
+ def any?
+ false
+ end
+
+ def many?
+ false
+ end
+
+ def to_sql
+ @to_sql ||= ""
+ end
+
+ def where_values_hash
+ {}
+ end
+
+ def count
+ 0
+ end
+
+ def calculate(operation, column_name, options = {})
+ nil
+ end
+
+ def exists?(id = false)
+ false
+ end
+
end
end \ No newline at end of file
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index bb504ae90f..12e232a97f 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -178,7 +178,7 @@ module ActiveRecord
verify_readonly_attribute(name)
raise ActiveRecordError, "can not update on a new record object" unless persisted?
raw_write_attribute(name, value)
- self.class.update_all({ name => value }, self.class.primary_key => id) == 1
+ self.class.where(self.class.primary_key => id).update_all(name => value) == 1
end
# Updates the attributes of the model from the passed-in hash and saves the
@@ -313,7 +313,7 @@ module ActiveRecord
@changed_attributes.except!(*changes.keys)
primary_key = self.class.primary_key
- self.class.unscoped.update_all(changes, { primary_key => self[primary_key] }) == 1
+ self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
end
end
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index ee3a6bf8c0..eb2769f1ef 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -68,7 +68,9 @@ module ActiveRecord
# and then establishes the connection.
initializer "active_record.initialize_database" do |app|
ActiveSupport.on_load(:active_record) do
- self.configurations = app.config.database_configuration
+ unless ENV['DATABASE_URL']
+ self.configurations = app.config.database_configuration
+ end
establish_connection
end
end
@@ -115,7 +117,7 @@ module ActiveRecord
if app.config.use_schema_cache_dump
filename = File.join(app.config.paths["db"].first, "schema_cache.dump")
if File.file?(filename)
- cache = Marshal.load(open(filename, 'rb') { |f| f.read })
+ cache = Marshal.load File.binread filename
if cache.version == ActiveRecord::Migrator.current_version
ActiveRecord::Base.connection.schema_cache = cache
else
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index b125449127..333d31d8a3 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -6,28 +6,30 @@ module ActiveRecord
# = Active Record Relation
class Relation
JoinOperation = Struct.new(:relation, :join_class, :on)
- ASSOCIATION_METHODS = [:includes, :eager_load, :preload]
- MULTI_VALUE_METHODS = [:select, :group, :order, :joins, :where, :having, :bind, :references]
- SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering, :reverse_order, :uniq]
+
+ MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
+ :order, :joins, :where, :having, :bind, :references,
+ :extending]
+
+ SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
+ :reverse_order, :uniq, :create_with]
+
+ VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
attr_reader :table, :klass, :loaded
- attr_accessor :extensions, :default_scoped
+ attr_accessor :default_scoped
alias :loaded? :loaded
alias :default_scoped? :default_scoped
- def initialize(klass, table)
- @klass, @table = klass, table
-
+ def initialize(klass, table, values = {})
+ @klass = klass
+ @table = table
+ @values = values
@implicit_readonly = nil
@loaded = false
@default_scoped = false
-
- SINGLE_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_value", nil)}
- (ASSOCIATION_METHODS + MULTI_VALUE_METHODS).each {|v| instance_variable_set(:"@#{v}_values", [])}
- @extensions = []
- @create_with_value = {}
end
def insert(values)
@@ -78,7 +80,8 @@ module ActiveRecord
end
def initialize_copy(other)
- @bind_values = @bind_values.dup
+ @values = @values.dup
+ @values[:bind] = @values[:bind].dup if @values[:bind]
reset
end
@@ -168,17 +171,17 @@ module ActiveRecord
default_scoped = with_default_scope
if default_scoped.equal?(self)
- @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, @bind_values)
+ @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bind_values)
- preload = @preload_values
- preload += @includes_values unless eager_loading?
+ preload = preload_values
+ preload += includes_values unless eager_loading?
preload.each do |associations|
ActiveRecord::Associations::Preloader.new(@records, associations).run
end
# @readonly_value is true only if set explicitly. @implicit_readonly is true if there
# are JOINS and no explicit SELECT.
- readonly = @readonly_value.nil? ? @implicit_readonly : @readonly_value
+ readonly = readonly_value.nil? ? @implicit_readonly : readonly_value
@records.each { |record| record.readonly! } if readonly
else
@records = default_scoped.to_a
@@ -218,7 +221,7 @@ module ActiveRecord
if block_given?
to_a.many? { |*block_args| yield(*block_args) }
else
- @limit_value ? to_a.many? : size > 1
+ limit_value ? to_a.many? : size > 1
end
end
@@ -233,7 +236,10 @@ module ActiveRecord
# Please check unscoped if you want to remove all previous scopes (including
# the default_scope) during the execution of a block.
def scoping
- @klass.with_scope(self, :overwrite) { yield }
+ previous, klass.current_scope = klass.current_scope, self
+ yield
+ ensure
+ klass.current_scope = previous
end
# Updates all records with details given if they match a set of conditions supplied, limits and order can
@@ -254,39 +260,26 @@ module ActiveRecord
# Customer.update_all :wants_email => true
#
# # Update all books with 'Rails' in their title
- # Book.update_all "author = 'David'", "title LIKE '%Rails%'"
- #
- # # Update all avatars migrated more recently than a week ago
- # Avatar.update_all ['migrated_at = ?', Time.now.utc], ['migrated_at > ?', 1.week.ago]
- #
- # # Update all books that match conditions, but limit it to 5 ordered by date
- # Book.update_all "author = 'David'", "title LIKE '%Rails%'", :order => 'created_at', :limit => 5
- #
- # # Conditions from the current relation also works
# Book.where('title LIKE ?', '%Rails%').update_all(:author => 'David')
#
- # # The same idea applies to limit and order
+ # # Update all books that match conditions, but limit it to 5 ordered by date
# Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(:author => 'David')
- def update_all(updates, conditions = nil, options = {})
- if conditions || options.present?
- where(conditions).apply_finder_options(options.slice(:limit, :order)).update_all(updates)
- else
- stmt = Arel::UpdateManager.new(arel.engine)
-
- stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
- stmt.table(table)
- stmt.key = table[primary_key]
+ def update_all(updates)
+ stmt = Arel::UpdateManager.new(arel.engine)
- if joins_values.any?
- @klass.connection.join_to_update(stmt, arel)
- else
- stmt.take(arel.limit)
- stmt.order(*arel.orders)
- stmt.wheres = arel.constraints
- end
+ stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
+ stmt.table(table)
+ stmt.key = table[primary_key]
- @klass.connection.update stmt, 'SQL', bind_values
+ if joins_values.any?
+ @klass.connection.join_to_update(stmt, arel)
+ else
+ stmt.take(arel.limit)
+ stmt.order(*arel.orders)
+ stmt.wheres = arel.constraints
end
+
+ @klass.connection.update stmt, 'SQL', bind_values
end
# Updates an object (or multiple objects) and saves it to the database, if validations pass.
@@ -400,8 +393,16 @@ module ActiveRecord
if conditions
where(conditions).delete_all
else
- statement = arel.compile_delete
- affected = @klass.connection.delete(statement, 'SQL', bind_values)
+ stmt = Arel::DeleteManager.new(arel.engine)
+ stmt.from(table)
+
+ if joins_values.any?
+ @klass.connection.join_to_delete(stmt, arel, table[primary_key])
+ else
+ stmt.wheres = arel.constraints
+ end
+
+ affected = @klass.connection.delete(stmt, 'SQL', bind_values)
reset
affected
@@ -446,7 +447,7 @@ module ActiveRecord
end
def to_sql
- @to_sql ||= klass.connection.to_sql(arel, @bind_values.dup)
+ @to_sql ||= klass.connection.to_sql(arel, bind_values.dup)
end
def where_values_hash
@@ -468,8 +469,8 @@ module ActiveRecord
def eager_loading?
@should_eager_load ||=
- @eager_load_values.any? ||
- @includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?)
+ eager_load_values.any? ||
+ includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?)
end
# Joins that are also marked for preloading. In which case we should just eager load them.
@@ -477,7 +478,7 @@ module ActiveRecord
# represent the same association, but that aren't matched by this. Also, we could have
# nested hashes which partially match, e.g. { :a => :b } & { :a => [:b, :c] }
def joined_includes_values
- @includes_values & @joins_values
+ includes_values & joins_values
end
def ==(other)
@@ -511,6 +512,10 @@ module ActiveRecord
to_a.blank?
end
+ def values
+ @values.dup
+ end
+
private
def references_eager_loaded_tables?
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index 2fd89882ff..15f838a5ab 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -46,19 +46,14 @@ module ActiveRecord
# group.each { |person| person.party_all_night! }
# end
def find_in_batches(options = {})
+ options.assert_valid_keys(:start, :batch_size)
+
relation = self
unless arel.orders.blank? && arel.taken.blank?
ActiveRecord::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size")
end
- if (finder_options = options.except(:start, :batch_size)).present?
- raise "You can't specify an order, it's forced to be #{batch_order}" if options[:order].present?
- raise "You can't specify a limit, it's forced to be the batch_size" if options[:limit].present?
-
- relation = apply_finder_options(finder_options)
- end
-
start = options.delete(:start).to_i
batch_size = options.delete(:batch_size) || 1000
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index f613014f23..db894c8aa9 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -3,56 +3,19 @@ require 'active_support/core_ext/object/try'
module ActiveRecord
module Calculations
- # Count operates using three different approaches.
+ # Count the records.
#
- # * Count all: By not passing any parameters to count, it will return a count of all the rows for the model.
- # * Count using column: By passing a column name to count, it will return a count of all the
- # rows for the model with supplied column present.
- # * Count using options will find the row count matched by the options used.
+ # Person.count
+ # # => the total count of all people
#
- # The third approach, count using options, accepts an option hash as the only parameter. The options are:
+ # Person.count(:age)
+ # # => returns the total count of all people whose age is present in database
#
- # * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ].
- # See conditions in the intro to ActiveRecord::Base.
- # * <tt>:joins</tt>: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id"
- # (rarely needed) or named associations in the same form used for the <tt>:include</tt> option, which will
- # perform an INNER JOIN on the associated table(s). If the value is a string, then the records
- # will be returned read-only since they will have attributes that do not correspond to the table's columns.
- # Pass <tt>:readonly => false</tt> to override.
- # * <tt>:include</tt>: Named associations that should be loaded alongside using LEFT OUTER JOINs.
- # The symbols named refer to already defined associations. When using named associations, count
- # returns the number of DISTINCT items for the model you're counting.
- # See eager loading under Associations.
- # * <tt>:order</tt>: An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations).
- # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
- # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example,
- # want to do a join but not include the joined columns.
- # * <tt>:distinct</tt>: Set this to true to make this a distinct calculation, such as
- # SELECT COUNT(DISTINCT posts.id) ...
- # * <tt>:from</tt> - By default, this is the table name of the class, but can be changed to an
- # alternate table name (or even the name of a database view).
+ # Person.count(:all)
+ # # => performs a COUNT(*) (:all is an alias for '*')
#
- # Examples for counting all:
- # Person.count # returns the total count of all people
- #
- # Examples for counting by column:
- # Person.count(:age) # returns the total count of all people whose age is present in database
- #
- # Examples for count with options:
- # Person.count(:conditions => "age > 26")
- #
- # # because of the named association, it finds the DISTINCT count using LEFT OUTER JOIN.
- # Person.count(:conditions => "age > 26 AND job.salary > 60000", :include => :job)
- #
- # # finds the number of rows matching the conditions and joins.
- # Person.count(:conditions => "age > 26 AND job.salary > 60000",
- # :joins => "LEFT JOIN jobs on jobs.person_id = person.id")
- #
- # Person.count('id', :conditions => "age > 26") # Performs a COUNT(id)
- # Person.count(:all, :conditions => "age > 26") # Performs a COUNT(*) (:all is an alias for '*')
- #
- # Note: <tt>Person.count(:all)</tt> will not work because it will use <tt>:all</tt> as the condition.
- # Use Person.count instead.
+ # Person.count(:age, distinct: true)
+ # # => counts the number of different age values
def count(column_name = nil, options = {})
column_name, options = nil, column_name if column_name.is_a?(Hash)
calculate(:count, column_name, options)
@@ -98,21 +61,22 @@ module ActiveRecord
end
# This calculates aggregate values in the given column. Methods for count, sum, average,
- # minimum, and maximum have been added as shortcuts. Options such as <tt>:conditions</tt>,
- # <tt>:order</tt>, <tt>:group</tt>, <tt>:having</tt>, and <tt>:joins</tt> can be passed to customize the query.
+ # minimum, and maximum have been added as shortcuts.
#
# There are two basic forms of output:
+ #
# * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float
# for AVG, and the given column's type for everything else.
- # * Grouped values: This returns an ordered hash of the values and groups them by the
- # <tt>:group</tt> option. It takes either a column name, or the name of a belongs_to association.
#
- # values = Person.maximum(:age, :group => 'last_name')
+ # * Grouped values: This returns an ordered hash of the values and groups them. It
+ # takes either a column name, or the name of a belongs_to association.
+ #
+ # values = Person.group('last_name').maximum(:age)
# puts values["Drake"]
# => 43
#
# drake = Family.find_by_last_name('Drake')
- # values = Person.maximum(:age, :group => :family) # Person belongs_to :family
+ # values = Person.group(:family).maximum(:age) # Person belongs_to :family
# puts values[drake]
# => 43
#
@@ -120,47 +84,25 @@ module ActiveRecord
# ...
# end
#
- # Options:
- # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ].
- # See conditions in the intro to ActiveRecord::Base.
- # * <tt>:include</tt>: Eager loading, see Associations for details. Since calculations don't load anything,
- # the purpose of this is to access fields on joined tables in your conditions, order, or group clauses.
- # * <tt>:joins</tt> - An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id".
- # (Rarely needed).
- # The records will be returned read-only since they will have attributes that do not correspond to the
- # table's columns.
- # * <tt>:order</tt> - An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations).
- # * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
- # * <tt>:select</tt> - By default, this is * as in SELECT * FROM, but can be changed if you for example
- # want to do a join, but not include the joined columns.
- # * <tt>:distinct</tt> - Set this to true to make this a distinct calculation, such as
- # SELECT COUNT(DISTINCT posts.id) ...
- #
# Examples:
# Person.calculate(:count, :all) # The same as Person.count
# Person.average(:age) # SELECT AVG(age) FROM people...
- # Person.minimum(:age, :conditions => ['last_name != ?', 'Drake']) # Selects the minimum age for
- # # everyone with a last name other than 'Drake'
#
# # Selects the minimum age for any family without any minors
- # Person.minimum(:age, :having => 'min(age) > 17', :group => :last_name)
+ # Person.group(:last_name).having("min(age) > 17").minimum(:age)
#
# Person.sum("2 * age")
def calculate(operation, column_name, options = {})
- if options.except(:distinct).present?
- apply_finder_options(options.except(:distinct)).calculate(operation, column_name, :distinct => options[:distinct])
- else
- relation = with_default_scope
-
- if relation.equal?(self)
- if eager_loading? || (includes_values.present? && references_eager_loaded_tables?)
- construct_relation_for_association_calculations.calculate(operation, column_name, options)
- else
- perform_calculation(operation, column_name, options)
- end
+ relation = with_default_scope
+
+ if relation.equal?(self)
+ if eager_loading? || (includes_values.present? && references_eager_loaded_tables?)
+ construct_relation_for_association_calculations.calculate(operation, column_name, options)
else
- relation.calculate(operation, column_name, options)
+ perform_calculation(operation, column_name, options)
end
+ else
+ relation.calculate(operation, column_name, options)
end
rescue ThrowResult
0
@@ -216,7 +158,7 @@ module ActiveRecord
distinct = nil if column_name =~ /\s*DISTINCT\s+/i
end
- if @group_values.any?
+ if group_values.any?
execute_grouped_calculation(operation, column_name, distinct)
else
execute_simple_calculation(operation, column_name, distinct)
@@ -259,7 +201,7 @@ module ActiveRecord
end
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
- group_attr = @group_values
+ group_attr = group_values
association = @klass.reflect_on_association(group_attr.first.to_sym)
associated = group_attr.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
group_fields = Array(associated ? association.foreign_key : group_attr)
@@ -282,7 +224,7 @@ module ActiveRecord
operation,
distinct).as(aggregate_alias)
]
- select_values += @select_values unless @having_values.empty?
+ select_values += select_values unless having_values.empty?
select_values.concat group_fields.zip(group_aliases).map { |field,aliaz|
"#{field} AS #{aliaz}"
@@ -347,8 +289,8 @@ module ActiveRecord
end
def select_for_count
- if @select_values.present?
- select = @select_values.join(", ")
+ if select_values.present?
+ select = select_values.join(", ")
select if select !~ /[,*]/
end
end
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 74f8e30404..416b55f5c5 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -3,83 +3,24 @@ require 'active_support/core_ext/hash/indifferent_access'
module ActiveRecord
module FinderMethods
- # Find operates with four different retrieval approaches:
- #
- # * Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
- # If no record can be found for all of the listed ids, then RecordNotFound will be raised.
- # * Find first - This will return the first record matched by the options used. These options can either be specific
- # conditions or merely an order. If no record can be matched, +nil+ is returned. Use
- # <tt>Model.find(:first, *args)</tt> or its shortcut <tt>Model.first(*args)</tt>.
- # * Find last - This will return the last record matched by the options used. These options can either be specific
- # conditions or merely an order. If no record can be matched, +nil+ is returned. Use
- # <tt>Model.find(:last, *args)</tt> or its shortcut <tt>Model.last(*args)</tt>.
- # * Find all - This will return all the records matched by the options used.
- # If no records are found, an empty array is returned. Use
- # <tt>Model.find(:all, *args)</tt> or its shortcut <tt>Model.all(*args)</tt>.
- #
- # All approaches accept an options hash as their last parameter.
- #
- # ==== Options
- #
- # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1", <tt>["user_name = ?", username]</tt>,
- # or <tt>["user_name = :user_name", { :user_name => user_name }]</tt>. See conditions in the intro.
- # * <tt>:order</tt> - An SQL fragment like "created_at DESC, name".
- # * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
- # * <tt>:having</tt> - Combined with +:group+ this can be used to filter the records that a
- # <tt>GROUP BY</tt> returns. Uses the <tt>HAVING</tt> SQL-clause.
- # * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
- # * <tt>:offset</tt> - An integer determining the offset from where the rows should be fetched. So at 5,
- # it would skip rows 0 through 4.
- # * <tt>:joins</tt> - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed),
- # named associations in the same form used for the <tt>:include</tt> option, which will perform an
- # <tt>INNER JOIN</tt> on the associated table(s),
- # or an array containing a mixture of both strings and named associations.
- # If the value is a string, then the records will be returned read-only since they will
- # have attributes that do not correspond to the table's columns.
- # Pass <tt>:readonly => false</tt> to override.
- # * <tt>:include</tt> - Names associations that should be loaded alongside. The symbols named refer
- # to already defined associations. See eager loading under Associations.
- # * <tt>:select</tt> - By default, this is "*" as in "SELECT * FROM", but can be changed if you,
- # for example, want to do a join but not include the joined columns. Takes a string with the SELECT SQL fragment (e.g. "id, name").
- # * <tt>:from</tt> - By default, this is the table name of the class, but can be changed
- # to an alternate table name (or even the name of a database view).
- # * <tt>:readonly</tt> - Mark the returned records read-only so they cannot be saved or updated.
- # * <tt>:lock</tt> - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
- # <tt>:lock => true</tt> gives connection's default exclusive lock, usually "FOR UPDATE".
+ # Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
+ # If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key
+ # is an integer, find by id coerces its arguments using +to_i+.
#
# ==== Examples
#
- # # find by id
# Person.find(1) # returns the object for ID = 1
+ # Person.find("1") # returns the object for ID = 1
# Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
# Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
# Person.find([1]) # returns an array for the object with ID = 1
# Person.where("administrator = 1").order("created_on DESC").find(1)
#
# Note that returned records may not be in the same order as the ids you
- # provide since database rows are unordered. Give an explicit <tt>:order</tt>
+ # provide since database rows are unordered. Give an explicit <tt>order</tt>
# to ensure the results are sorted.
#
- # ==== Examples
- #
- # # find first
- # Person.first # returns the first object fetched by SELECT * FROM people
- # Person.where(["user_name = ?", user_name]).first
- # Person.where(["user_name = :u", { :u => user_name }]).first
- # Person.order("created_on DESC").offset(5).first
- #
- # # find last
- # Person.last # returns the last object fetched by SELECT * FROM people
- # Person.where(["user_name = ?", user_name]).last
- # Person.order("created_on DESC").offset(5).last
- #
- # # find all
- # Person.all # returns an array of objects for all the rows fetched by SELECT * FROM people
- # Person.where(["category IN (?)", categories]).limit(50).all
- # Person.where({ :friends => ["Bob", "Steve", "Fred"] }).all
- # Person.offset(10).limit(10).all
- # Person.includes([:account, :friends]).all
- # Person.group("category").all
+ # ==== Find with lock
#
# Example for find with a lock: Imagine two concurrent transactions:
# each will read <tt>person.visits == 2</tt>, add 1 to it, and save, resulting
@@ -93,19 +34,10 @@ module ActiveRecord
# person.save!
# end
def find(*args)
- return to_a.find { |*block_args| yield(*block_args) } if block_given?
-
- options = args.extract_options!
-
- if options.present?
- apply_finder_options(options).find(*args)
+ if block_given?
+ to_a.find { |*block_args| yield(*block_args) }
else
- case args.first
- when :first, :last, :all
- send(args.first)
- else
- find_with_ids(*args)
- end
+ find_with_ids(*args)
end
end
@@ -128,18 +60,14 @@ module ActiveRecord
where(*args).first!
end
- # A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass in all the
- # same arguments to this method as you can to <tt>find(:first)</tt>.
- def first(*args)
- if args.any?
- if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
- limit(*args).to_a
- else
- apply_finder_options(args.first).first
- end
- else
- find_first
- end
+ # Examples:
+ #
+ # Person.first # returns the first object fetched by SELECT * FROM people
+ # Person.where(["user_name = ?", user_name]).first
+ # Person.where(["user_name = :u", { :u => user_name }]).first
+ # Person.order("created_on DESC").offset(5).first
+ def first(limit = nil)
+ limit ? limit(limit).to_a : find_first
end
# Same as +first+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
@@ -148,18 +76,17 @@ module ActiveRecord
first or raise RecordNotFound
end
- # A convenience wrapper for <tt>find(:last, *args)</tt>. You can pass in all the
- # same arguments to this method as you can to <tt>find(:last)</tt>.
- def last(*args)
- if args.any?
- if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
- if order_values.empty?
- order("#{primary_key} DESC").limit(*args).reverse
- else
- to_a.last(*args)
- end
+ # Examples:
+ #
+ # Person.last # returns the last object fetched by SELECT * FROM people
+ # Person.where(["user_name = ?", user_name]).last
+ # Person.order("created_on DESC").offset(5).last
+ def last(limit = nil)
+ if limit
+ if order_values.empty?
+ order("#{primary_key} DESC").limit(limit).reverse
else
- apply_finder_options(args.first).last
+ to_a.last(limit)
end
else
find_last
@@ -172,10 +99,16 @@ module ActiveRecord
last or raise RecordNotFound
end
- # A convenience wrapper for <tt>find(:all, *args)</tt>. You can pass in all the
- # same arguments to this method as you can to <tt>find(:all)</tt>.
- def all(*args)
- args.any? ? apply_finder_options(args.first).to_a : to_a
+ # Examples:
+ #
+ # Person.all # returns an array of objects for all the rows fetched by SELECT * FROM people
+ # Person.where(["category IN (?)", categories]).limit(50).all
+ # Person.where({ :friends => ["Bob", "Steve", "Fred"] }).all
+ # Person.offset(10).limit(10).all
+ # Person.includes([:account, :friends]).all
+ # Person.group("category").all
+ def all
+ to_a
end
# Returns true if a record exists in the table that matches the +id+ or
@@ -234,12 +167,12 @@ module ActiveRecord
end
def construct_join_dependency_for_association_find
- including = (@eager_load_values + @includes_values).uniq
+ including = (eager_load_values + includes_values).uniq
ActiveRecord::Associations::JoinDependency.new(@klass, including, [])
end
def construct_relation_for_association_calculations
- including = (@eager_load_values + @includes_values).uniq
+ including = (eager_load_values + includes_values).uniq
join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first)
relation = except(:includes, :eager_load, :preload)
apply_join_dependency(relation, join_dependency)
@@ -338,7 +271,7 @@ module ActiveRecord
id = id.id if ActiveRecord::Base === id
column = columns_hash[primary_key]
- substitute = connection.substitute_at(column, @bind_values.length)
+ substitute = connection.substitute_at(column, bind_values.length)
relation = where(table[primary_key].eq(substitute))
relation.bind_values += [[column, id]]
record = relation.first
@@ -356,15 +289,15 @@ module ActiveRecord
result = where(table[primary_key].in(ids)).all
expected_size =
- if @limit_value && ids.size > @limit_value
- @limit_value
+ if limit_value && ids.size > limit_value
+ limit_value
else
ids.size
end
# 11 ids with limit 3, offset 9 should give 2 results.
- if @offset_value && (ids.size - @offset_value < expected_size)
- expected_size = ids.size - @offset_value
+ if offset_value && (ids.size - offset_value < expected_size)
+ expected_size = ids.size - offset_value
end
if result.size == expected_size
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
new file mode 100644
index 0000000000..3f880ce5e9
--- /dev/null
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -0,0 +1,121 @@
+require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/hash/keys'
+
+module ActiveRecord
+ class Relation
+ class HashMerger
+ attr_reader :relation, :hash
+
+ def initialize(relation, hash)
+ hash.assert_valid_keys(*Relation::VALUE_METHODS)
+
+ @relation = relation
+ @hash = hash
+ end
+
+ def merge
+ Merger.new(relation, other).merge
+ end
+
+ # Applying values to a relation has some side effects. E.g.
+ # interpolation might take place for where values. So we should
+ # build a relation to merge in rather than directly merging
+ # the values.
+ def other
+ other = Relation.new(relation.klass, relation.table)
+ hash.each { |k, v| other.send("#{k}!", v) }
+ other
+ end
+ end
+
+ class Merger
+ attr_reader :relation, :values
+
+ def initialize(relation, other)
+ if other.default_scoped? && other.klass != relation.klass
+ other = other.with_default_scope
+ end
+
+ @relation = relation
+ @values = other.values
+ end
+
+ def normal_values
+ Relation::SINGLE_VALUE_METHODS +
+ Relation::MULTI_VALUE_METHODS -
+ [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering]
+ end
+
+ def merge
+ normal_values.each do |name|
+ value = values[name]
+ relation.send("#{name}!", value) unless value.blank?
+ end
+
+ merge_multi_values
+ merge_single_values
+
+ relation
+ end
+
+ private
+
+ def merge_multi_values
+ relation.where_values = merged_wheres
+ relation.bind_values = merged_binds
+
+ if values[:reordering]
+ # override any order specified in the original relation
+ relation.reorder! values[:order]
+ elsif values[:order]
+ # merge in order_values from r
+ relation.order! values[:order]
+ end
+
+ relation.extend(*values[:extending]) unless values[:extending].blank?
+ end
+
+ def merge_single_values
+ relation.lock_value = values[:lock] unless relation.lock_value
+ relation.reverse_order_value = values[:reverse_order]
+
+ unless values[:create_with].blank?
+ relation.create_with_value = (relation.create_with_value || {}).merge(values[:create_with])
+ end
+ end
+
+ def merged_binds
+ if values[:bind]
+ (relation.bind_values + values[:bind]).uniq(&:first)
+ else
+ relation.bind_values
+ end
+ end
+
+ def merged_wheres
+ if values[:where]
+ merged_wheres = relation.where_values + values[:where]
+
+ unless relation.where_values.empty?
+ # Remove duplicates, last one wins.
+ seen = Hash.new { |h,table| h[table] = {} }
+ merged_wheres = merged_wheres.reverse.reject { |w|
+ nuke = false
+ if w.respond_to?(:operator) && w.operator == :==
+ name = w.left.name
+ table = w.left.relation.name
+ nuke = seen[table][name]
+ seen[table][name] = true
+ end
+ nuke
+ }.reverse
+ end
+
+ merged_wheres
+ else
+ relation.where_values
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index d737b34115..855477eaed 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -5,37 +5,67 @@ module ActiveRecord
module QueryMethods
extend ActiveSupport::Concern
- attr_accessor :includes_values, :eager_load_values, :preload_values,
- :select_values, :group_values, :order_values, :joins_values,
- :where_values, :having_values, :bind_values,
- :limit_value, :offset_value, :lock_value, :readonly_value, :create_with_value,
- :from_value, :reordering_value, :reverse_order_value,
- :uniq_value, :references_values
+ Relation::MULTI_VALUE_METHODS.each do |name|
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def #{name}_values # def select_values
+ @values[:#{name}] || [] # @values[:select] || []
+ end # end
+ #
+ def #{name}_values=(values) # def select_values=(values)
+ @values[:#{name}] = values # @values[:select] = values
+ end # end
+ CODE
+ end
+
+ (Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |name|
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def #{name}_value # def readonly_value
+ @values[:#{name}] # @values[:readonly]
+ end # end
+ #
+ def #{name}_value=(value) # def readonly_value=(value)
+ @values[:#{name}] = value # @values[:readonly] = value
+ end # end
+ CODE
+ end
+
+ def create_with_value
+ @values[:create_with] || {}
+ end
+
+ def create_with_value=(value)
+ @values[:create_with] = value
+ end
+
+ alias extensions extending_values
def includes(*args)
- args.reject! {|a| a.blank? }
+ args.empty? ? self : clone.includes!(*args)
+ end
- return self if args.empty?
+ def includes!(*args)
+ args.reject! {|a| a.blank? }
- relation = clone
- relation.includes_values = (relation.includes_values + args).flatten.uniq
- relation
+ self.includes_values = (includes_values + args).flatten.uniq
+ self
end
def eager_load(*args)
- return self if args.blank?
+ args.blank? ? self : clone.eager_load!(*args)
+ end
- relation = clone
- relation.eager_load_values += args
- relation
+ def eager_load!(*args)
+ self.eager_load_values += args
+ self
end
def preload(*args)
- return self if args.blank?
+ args.blank? ? self : clone.preload!(*args)
+ end
- relation = clone
- relation.preload_values += args
- relation
+ def preload!(*args)
+ self.preload_values += args
+ self
end
# Used to indicate that an association is referenced by an SQL string, and should
@@ -49,11 +79,12 @@ module ActiveRecord
# User.includes(:posts).where("posts.name = 'foo'").references(:posts)
# # => Query now knows the string references posts, so adds a JOIN
def references(*args)
- return self if args.blank?
+ args.blank? ? self : clone.references!(*args)
+ end
- relation = clone
- relation.references_values = (references_values + args.flatten.map(&:to_s)).uniq
- relation
+ def references!(*args)
+ self.references_values = (references_values + args.flatten.map(&:to_s)).uniq
+ self
end
# Works in two unique ways.
@@ -87,34 +118,40 @@ module ActiveRecord
# => ActiveModel::MissingAttributeError: missing attribute: other_field
def select(value = Proc.new)
if block_given?
- to_a.select {|*block_args| value.call(*block_args) }
+ to_a.select { |*block_args| value.call(*block_args) }
else
- relation = clone
- relation.select_values += Array.wrap(value)
- relation
+ clone.select!(value)
end
end
+ def select!(value)
+ self.select_values += Array.wrap(value)
+ self
+ end
+
def group(*args)
- return self if args.blank?
+ args.blank? ? self : clone.group!(*args)
+ end
- relation = clone
- relation.group_values += args.flatten
- relation
+ def group!(*args)
+ self.group_values += args.flatten
+ self
end
def order(*args)
- return self if args.blank?
+ args.blank? ? self : clone.order!(*args)
+ end
+ def order!(*args)
args = args.flatten
+
references = args.reject { |arg| Arel::Node === arg }
.map { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }
.compact
+ references!(references) if references.any?
- relation = clone
- relation = relation.references(references) if references.any?
- relation.order_values += args
- relation
+ self.order_values += args
+ self
end
# Replaces any existing order defined on the relation with the specified order.
@@ -128,72 +165,88 @@ module ActiveRecord
# generates a query with 'ORDER BY id ASC, name ASC'.
#
def reorder(*args)
- return self if args.blank?
+ args.blank? ? self : clone.reorder!(*args)
+ end
- relation = clone
- relation.reordering_value = true
- relation.order_values = args.flatten
- relation
+ def reorder!(*args)
+ self.reordering_value = true
+ self.order_values = args.flatten
+ self
end
def joins(*args)
- return self if args.compact.blank?
-
- relation = clone
+ args.compact.blank? ? self : clone.joins!(*args)
+ end
+ def joins!(*args)
args.flatten!
- relation.joins_values += args
- relation
+ self.joins_values += args
+ self
end
def bind(value)
- relation = clone
- relation.bind_values += [value]
- relation
+ clone.bind!(value)
+ end
+
+ def bind!(value)
+ self.bind_values += [value]
+ self
end
def where(opts, *rest)
- return self if opts.blank?
+ opts.blank? ? self : clone.where!(opts, *rest)
+ end
- relation = clone
- relation = relation.references(PredicateBuilder.references(opts)) if Hash === opts
- relation.where_values += build_where(opts, rest)
- relation
+ def where!(opts, *rest)
+ references!(PredicateBuilder.references(opts)) if Hash === opts
+
+ self.where_values += build_where(opts, rest)
+ self
end
def having(opts, *rest)
- return self if opts.blank?
+ opts.blank? ? self : clone.having!(opts, *rest)
+ end
- relation = clone
- relation = relation.references(PredicateBuilder.references(opts)) if Hash === opts
- relation.having_values += build_where(opts, rest)
- relation
+ def having!(opts, *rest)
+ references!(PredicateBuilder.references(opts)) if Hash === opts
+
+ self.having_values += build_where(opts, rest)
+ self
end
def limit(value)
- relation = clone
- relation.limit_value = value
- relation
+ clone.limit!(value)
+ end
+
+ def limit!(value)
+ self.limit_value = value
+ self
end
def offset(value)
- relation = clone
- relation.offset_value = value
- relation
+ clone.offset!(value)
+ end
+
+ def offset!(value)
+ self.offset_value = value
+ self
end
def lock(locks = true)
- relation = clone
+ clone.lock!(locks)
+ end
+ def lock!(locks = true)
case locks
when String, TrueClass, NilClass
- relation.lock_value = locks || true
+ self.lock_value = locks || true
else
- relation.lock_value = false
+ self.lock_value = false
end
- relation
+ self
end
# Returns a chainable relation with zero records, specifically an
@@ -230,21 +283,30 @@ module ActiveRecord
end
def readonly(value = true)
- relation = clone
- relation.readonly_value = value
- relation
+ clone.readonly!(value)
+ end
+
+ def readonly!(value = true)
+ self.readonly_value = value
+ self
end
def create_with(value)
- relation = clone
- relation.create_with_value = value ? create_with_value.merge(value) : {}
- relation
+ clone.create_with!(value)
+ end
+
+ def create_with!(value)
+ self.create_with_value = value ? create_with_value.merge(value) : {}
+ self
end
def from(value)
- relation = clone
- relation.from_value = value
- relation
+ clone.from!(value)
+ end
+
+ def from!(value)
+ self.from_value = value
+ self
end
# Specifies whether the records should be unique or not. For example:
@@ -258,9 +320,12 @@ module ActiveRecord
# User.select(:name).uniq.uniq(false)
# # => You can also remove the uniqueness
def uniq(value = true)
- relation = clone
- relation.uniq_value = value
- relation
+ clone.uniq!(value)
+ end
+
+ def uniq!(value = true)
+ self.uniq_value = value
+ self
end
# Used to extend a scope with additional methods, either through
@@ -299,20 +364,30 @@ module ActiveRecord
# # pagination code goes here
# end
# end
- def extending(*modules)
- modules << Module.new(&Proc.new) if block_given?
+ def extending(*modules, &block)
+ if modules.any? || block
+ clone.extending!(*modules, &block)
+ else
+ self
+ end
+ end
- return self if modules.empty?
+ def extending!(*modules, &block)
+ modules << Module.new(&block) if block_given?
- relation = clone
- relation.send(:apply_modules, modules.flatten)
- relation
+ self.extending_values = modules.flatten
+ extend(*extending_values) if extending_values.any?
+
+ self
end
def reverse_order
- relation = clone
- relation.reverse_order_value = !relation.reverse_order_value
- relation
+ clone.reverse_order!
+ end
+
+ def reverse_order!
+ self.reverse_order_value = !reverse_order_value
+ self
end
def arel
@@ -322,26 +397,26 @@ module ActiveRecord
def build_arel
arel = table.from table
- build_joins(arel, @joins_values) unless @joins_values.empty?
+ build_joins(arel, joins_values) unless joins_values.empty?
- collapse_wheres(arel, (@where_values - ['']).uniq)
+ collapse_wheres(arel, (where_values - ['']).uniq)
- arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty?
+ arel.having(*having_values.uniq.reject{|h| h.blank?}) unless having_values.empty?
- arel.take(connection.sanitize_limit(@limit_value)) if @limit_value
- arel.skip(@offset_value.to_i) if @offset_value
+ arel.take(connection.sanitize_limit(limit_value)) if limit_value
+ arel.skip(offset_value.to_i) if offset_value
- arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty?
+ arel.group(*group_values.uniq.reject{|g| g.blank?}) unless group_values.empty?
- order = @order_values
- order = reverse_sql_order(order) if @reverse_order_value
+ order = order_values
+ order = reverse_sql_order(order) if reverse_order_value
arel.order(*order.uniq.reject{|o| o.blank?}) unless order.empty?
- build_select(arel, @select_values.uniq)
+ build_select(arel, select_values.uniq)
- arel.distinct(@uniq_value)
- arel.from(@from_value) if @from_value
- arel.lock(@lock_value) if @lock_value
+ arel.distinct(uniq_value)
+ arel.from(from_value) if from_value
+ arel.lock(lock_value) if lock_value
arel
end
@@ -443,13 +518,6 @@ module ActiveRecord
end
end
- def apply_modules(modules)
- unless modules.empty?
- @extensions += modules
- modules.each {|extension| extend(extension) }
- end
- end
-
def reverse_sql_order(order_query)
order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty?
diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb
index 03ba8c8628..41e55dfd0e 100644
--- a/activerecord/lib/active_record/relation/spawn_methods.rb
+++ b/activerecord/lib/active_record/relation/spawn_methods.rb
@@ -1,81 +1,37 @@
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/hash/except'
+require 'active_support/core_ext/hash/slice'
+require 'active_record/relation/merger'
module ActiveRecord
module SpawnMethods
- def merge(r)
- return self unless r
- return to_a & r if r.is_a?(Array)
-
- merged_relation = clone
-
- r = r.with_default_scope if r.default_scoped? && r.klass != klass
-
- Relation::ASSOCIATION_METHODS.each do |method|
- value = r.send(:"#{method}_values")
-
- unless value.empty?
- if method == :includes
- merged_relation = merged_relation.includes(value)
- else
- merged_relation.send(:"#{method}_values=", value)
- end
- end
- end
-
- (Relation::MULTI_VALUE_METHODS - [:joins, :where, :order, :binds]).each do |method|
- value = r.send(:"#{method}_values")
- next if value.empty?
-
- value += merged_relation.send(:"#{method}_values")
- merged_relation.send :"#{method}_values=", value
- end
-
- merged_relation.joins_values += r.joins_values
-
- merged_wheres = @where_values + r.where_values
-
- merged_binds = (@bind_values + r.bind_values).uniq(&:first)
-
- unless @where_values.empty?
- # Remove duplicates, last one wins.
- seen = Hash.new { |h,table| h[table] = {} }
- merged_wheres = merged_wheres.reverse.reject { |w|
- nuke = false
- if w.respond_to?(:operator) && w.operator == :==
- name = w.left.name
- table = w.left.relation.name
- nuke = seen[table][name]
- seen[table][name] = true
- end
- nuke
- }.reverse
- end
-
- merged_relation.where_values = merged_wheres
- merged_relation.bind_values = merged_binds
-
- (Relation::SINGLE_VALUE_METHODS - [:lock, :create_with, :reordering]).each do |method|
- value = r.send(:"#{method}_value")
- merged_relation.send(:"#{method}_value=", value) unless value.nil?
- end
-
- merged_relation.lock_value = r.lock_value unless merged_relation.lock_value
-
- merged_relation = merged_relation.create_with(r.create_with_value) unless r.create_with_value.empty?
-
- if (r.reordering_value)
- # override any order specified in the original relation
- merged_relation.reordering_value = true
- merged_relation.order_values = r.order_values
+
+ # Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an <tt>ActiveRecord::Relation</tt>.
+ # Returns an array representing the union of the resulting records with <tt>other</tt>, if <tt>other</tt> is an array.
+ #
+ # ==== Examples
+ #
+ # Post.where(:published => true).joins(:comments).merge( Comment.where(:spam => false) )
+ # # Performs a single join query with both where conditions.
+ #
+ # recent_posts = Post.order('created_at DESC').first(5)
+ # Post.where(:published => true).merge(recent_posts)
+ # # Returns the union of all published posts with the 5 most recently created posts.
+ # # (This is just an example. You'd probably want to do this with a single query!)
+ #
+ def merge(other)
+ if other.is_a?(Array)
+ to_a & other
+ elsif other
+ clone.merge!(other)
else
- # merge in order_values from r
- merged_relation.order_values += r.order_values
+ self
end
+ end
- # Apply scope extension modules
- merged_relation.send :apply_modules, r.extensions
-
- merged_relation
+ def merge!(other)
+ klass = other.is_a?(Hash) ? Relation::HashMerger : Relation::Merger
+ klass.new(self, other).merge
end
# Removes from the query the condition(s) specified in +skips+.
@@ -86,20 +42,9 @@ module ActiveRecord
# Post.where('id > 10').order('id asc').except(:where) # discards the where condition but keeps the order
#
def except(*skips)
- result = self.class.new(@klass, table)
+ result = self.class.new(@klass, table, values.except(*skips))
result.default_scoped = default_scoped
-
- ((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) - skips).each do |method|
- result.send(:"#{method}_values=", send(:"#{method}_values"))
- end
-
- (Relation::SINGLE_VALUE_METHODS - skips).each do |method|
- result.send(:"#{method}_value=", send(:"#{method}_value"))
- end
-
- # Apply scope extension modules
- result.send(:apply_modules, extensions)
-
+ result.extend(*extending_values) if extending_values.any?
result
end
@@ -111,44 +56,11 @@ module ActiveRecord
# Post.order('id asc').only(:where, :order) # uses the specified order
#
def only(*onlies)
- result = self.class.new(@klass, table)
+ result = self.class.new(@klass, table, values.slice(*onlies))
result.default_scoped = default_scoped
-
- ((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) & onlies).each do |method|
- result.send(:"#{method}_values=", send(:"#{method}_values"))
- end
-
- (Relation::SINGLE_VALUE_METHODS & onlies).each do |method|
- result.send(:"#{method}_value=", send(:"#{method}_value"))
- end
-
- # Apply scope extension modules
- result.send(:apply_modules, extensions)
-
+ result.extend(*extending_values) if extending_values.any?
result
end
- VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, :extend, :references,
- :order, :select, :readonly, :group, :having, :from, :lock ]
-
- def apply_finder_options(options)
- relation = clone
- return relation unless options
-
- options.assert_valid_keys(VALID_FIND_OPTIONS)
- finders = options.dup
- finders.delete_if { |key, value| value.nil? && key != :limit }
-
- ((VALID_FIND_OPTIONS - [:conditions, :include, :extend]) & finders.keys).each do |finder|
- relation = relation.send(finder, finders[finder])
- end
-
- relation = relation.where(finders[:conditions]) if options.has_key?(:conditions)
- relation = relation.includes(finders[:include]) if options.has_key?(:include)
- relation = relation.extending(finders[:extend]) if options.has_key?(:extend)
-
- relation
- end
-
end
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 95fd33c1d1..7cbe2db408 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -55,7 +55,7 @@ module ActiveRecord
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
-# It's strongly recommended to check this file into your version control system.
+# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(#{define_params}) do
diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb
index a8f5e96190..66a486ae0a 100644
--- a/activerecord/lib/active_record/scoping.rb
+++ b/activerecord/lib/active_record/scoping.rb
@@ -10,118 +10,6 @@ module ActiveRecord
end
module ClassMethods
- # with_scope lets you apply options to inner block incrementally. It takes a hash and the keys must be
- # <tt>:find</tt> or <tt>:create</tt>. <tt>:find</tt> parameter is <tt>Relation</tt> while
- # <tt>:create</tt> parameters are an attributes hash.
- #
- # class Article < ActiveRecord::Base
- # def self.create_with_scope
- # with_scope(:find => where(:blog_id => 1), :create => { :blog_id => 1 }) do
- # find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1
- # a = create(1)
- # a.blog_id # => 1
- # end
- # end
- # end
- #
- # In nested scopings, all previous parameters are overwritten by the innermost rule, with the exception of
- # <tt>where</tt>, <tt>includes</tt>, and <tt>joins</tt> operations in <tt>Relation</tt>, which are merged.
- #
- # <tt>joins</tt> operations are uniqued so multiple scopes can join in the same table without table aliasing
- # problems. If you need to join multiple tables, but still want one of the tables to be uniqued, use the
- # array of strings format for your joins.
- #
- # class Article < ActiveRecord::Base
- # def self.find_with_scope
- # with_scope(:find => where(:blog_id => 1).limit(1), :create => { :blog_id => 1 }) do
- # with_scope(:find => limit(10)) do
- # all # => SELECT * from articles WHERE blog_id = 1 LIMIT 10
- # end
- # with_scope(:find => where(:author_id => 3)) do
- # all # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1
- # end
- # end
- # end
- # end
- #
- # You can ignore any previous scopings by using the <tt>with_exclusive_scope</tt> method.
- #
- # class Article < ActiveRecord::Base
- # def self.find_with_exclusive_scope
- # with_scope(:find => where(:blog_id => 1).limit(1)) do
- # with_exclusive_scope(:find => limit(10)) do
- # all # => SELECT * from articles LIMIT 10
- # end
- # end
- # end
- # end
- #
- # *Note*: the +:find+ scope also has effect on update and deletion methods, like +update_all+ and +delete_all+.
- def with_scope(scope = {}, action = :merge, &block)
- # If another Active Record class has been passed in, get its current scope
- scope = scope.current_scope if !scope.is_a?(Relation) && scope.respond_to?(:current_scope)
-
- previous_scope = self.current_scope
-
- if scope.is_a?(Hash)
- # Dup first and second level of hash (method and params).
- scope = scope.dup
- scope.each do |method, params|
- scope[method] = params.dup unless params == true
- end
-
- scope.assert_valid_keys([ :find, :create ])
- relation = construct_finder_arel(scope[:find] || {})
- relation.default_scoped = true unless action == :overwrite
-
- if previous_scope && previous_scope.create_with_value && scope[:create]
- scope_for_create = if action == :merge
- previous_scope.create_with_value.merge(scope[:create])
- else
- scope[:create]
- end
-
- relation = relation.create_with(scope_for_create)
- else
- scope_for_create = scope[:create]
- scope_for_create ||= previous_scope.create_with_value if previous_scope
- relation = relation.create_with(scope_for_create) if scope_for_create
- end
-
- scope = relation
- end
-
- scope = previous_scope.merge(scope) if previous_scope && action == :merge
-
- self.current_scope = scope
- begin
- yield
- ensure
- self.current_scope = previous_scope
- end
- end
-
- protected
-
- # Works like with_scope, but discards any nested properties.
- def with_exclusive_scope(method_scoping = {}, &block)
- if method_scoping.values.any? { |e| e.is_a?(ActiveRecord::Relation) }
- raise ArgumentError, <<-MSG
- New finder API can not be used with_exclusive_scope. You can either call unscoped to get an anonymous scope not bound to the default_scope:
-
- User.unscoped.where(:active => true)
-
- Or call unscoped with a block:
-
- User.unscoped do
- User.where(:active => true).all
- end
-
- MSG
- end
- with_scope(method_scoping, :overwrite, &block)
- end
-
def current_scope #:nodoc:
Thread.current["#{self}_current_scope"]
end
@@ -129,15 +17,6 @@ module ActiveRecord
def current_scope=(scope) #:nodoc:
Thread.current["#{self}_current_scope"] = scope
end
-
- private
-
- def construct_finder_arel(options = {}, scope = nil)
- relation = options.is_a?(Hash) ? unscoped.apply_finder_options(options) : options
- relation = scope.merge(relation) if scope
- relation
- end
-
end
def populate_with_current_scope_attributes
diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb
index b0609a8c08..db833fc7f1 100644
--- a/activerecord/lib/active_record/scoping/default.rb
+++ b/activerecord/lib/active_record/scoping/default.rb
@@ -31,7 +31,7 @@ module ActiveRecord
# Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
# }
#
- # It is recommended to use the block form of unscoped because chaining
+ # It is recommended that you use the block form of unscoped because chaining
# unscoped with <tt>scope</tt> does not work. Assuming that
# <tt>published</tt> is a <tt>scope</tt>, the following two statements
# are equal: the default_scope is applied on both.
@@ -87,7 +87,7 @@ module ActiveRecord
# # Should return a scope, you can call 'super' here etc.
# end
# end
- def default_scope(scope = {})
+ def default_scope(scope = nil)
scope = Proc.new if block_given?
if scope.is_a?(Relation) || !scope.respond_to?(:call)
@@ -103,14 +103,13 @@ module ActiveRecord
end
def build_default_scope #:nodoc:
- if method(:default_scope).owner != ActiveRecord::Scoping::Default::ClassMethods
+ if !Base.is_a?(method(:default_scope).owner)
+ # The user has defined their own default scope method, so call that
evaluate_default_scope { default_scope }
elsif default_scopes.any?
evaluate_default_scope do
default_scopes.inject(relation) do |default_scope, scope|
- if scope.is_a?(Hash)
- default_scope.apply_finder_options(scope)
- elsif !scope.is_a?(Relation) && scope.respond_to?(:call)
+ if !scope.is_a?(Relation) && scope.respond_to?(:call)
default_scope.merge(unscoped { scope.call })
else
default_scope.merge(scope)
diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb
index 077e2d067e..2af476c1ba 100644
--- a/activerecord/lib/active_record/scoping/named.rb
+++ b/activerecord/lib/active_record/scoping/named.rb
@@ -29,17 +29,16 @@ module ActiveRecord
# You can define a \scope that applies to all finders using
# ActiveRecord::Base.default_scope.
def scoped(options = nil)
- if options
- scoped.apply_finder_options(options)
+ if current_scope
+ scope = current_scope.clone
else
- if current_scope
- current_scope.clone
- else
- scope = relation.clone
- scope.default_scoped = true
- scope
- end
+ scope = relation
+ scope.default_scoped = true
+ scope
end
+
+ scope.merge!(options) if options
+ scope
end
##
@@ -49,7 +48,7 @@ module ActiveRecord
if current_scope
current_scope.scope_for_create
else
- scope = relation.clone
+ scope = relation
scope.default_scoped = true
scope.scope_for_create
end
@@ -172,7 +171,7 @@ module ActiveRecord
# Article.published.featured.latest_article
# Article.featured.titles
- def scope(name, body = {}, &block)
+ def scope(name, body, &block)
extension = Module.new(&block) if block
# Check body.is_a?(Relation) to prevent the relation actually being
@@ -189,9 +188,7 @@ module ActiveRecord
end
singleton_class.send(:define_method, name) do |*args|
- options = body.respond_to?(:call) ? unscoped { body.call(*args) } : body
- options = scoped.apply_finder_options(options) if options.is_a?(Hash)
-
+ options = body.respond_to?(:call) ? unscoped { body.call(*args) } : body
relation = scoped.merge(options)
extension ? relation.extending(extension) : relation
diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb
index ce43ae8066..ed47a26749 100644
--- a/activerecord/lib/active_record/session_store.rb
+++ b/activerecord/lib/active_record/session_store.rb
@@ -119,7 +119,7 @@ module ActiveRecord
class << self; remove_possible_method :find_by_session_id; end
def self.find_by_session_id(session_id)
- find :first, :conditions => {:session_id=>session_id}
+ where(session_id: session_id).first
end
end
end
diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb
index db618f617f..9e4b588ac2 100644
--- a/activerecord/lib/active_record/validations/uniqueness.rb
+++ b/activerecord/lib/active_record/validations/uniqueness.rb
@@ -196,7 +196,6 @@ module ActiveRecord
# The following bundled adapters throw the ActiveRecord::RecordNotUnique exception:
# * ActiveRecord::ConnectionAdapters::MysqlAdapter
# * ActiveRecord::ConnectionAdapters::Mysql2Adapter
- # * ActiveRecord::ConnectionAdapters::SQLiteAdapter
# * ActiveRecord::ConnectionAdapters::SQLite3Adapter
# * ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
#
diff --git a/activerecord/lib/rails/generators/active_record/model/model_generator.rb b/activerecord/lib/rails/generators/active_record/model/model_generator.rb
index f3bb70fb41..8e6ef20285 100644
--- a/activerecord/lib/rails/generators/active_record/model/model_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/model/model_generator.rb
@@ -14,6 +14,7 @@ module ActiveRecord
def create_migration_file
return unless options[:migration] && options[:parent].nil?
+ attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
migration_template "migration.rb", "db/migrate/create_#{table_name}.rb"
end
@@ -27,7 +28,7 @@ module ActiveRecord
end
def attributes_with_index
- attributes.select { |a| a.has_index? || (a.reference? && options[:indexes]) }
+ attributes.select { |a| !a.reference? && a.has_index? }
end
def accessible_attributes
diff --git a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
index 5aa4743e7b..475a292f85 100644
--- a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
@@ -56,6 +56,36 @@ module ActiveRecord
end
end
+ def test_pk_and_sequence_for
+ pk, seq = @conn.pk_and_sequence_for('ex')
+ assert_equal 'id', pk
+ assert_equal @conn.default_sequence_name('ex', 'id'), seq
+ end
+
+ def test_pk_and_sequence_for_with_non_standard_primary_key
+ @conn.exec_query('drop table if exists ex_with_non_standard_pk')
+ @conn.exec_query(<<-eosql)
+ CREATE TABLE `ex_with_non_standard_pk` (
+ `code` INT(11) DEFAULT NULL auto_increment,
+ PRIMARY KEY (`code`))
+ eosql
+ pk, seq = @conn.pk_and_sequence_for('ex_with_non_standard_pk')
+ assert_equal 'code', pk
+ assert_equal @conn.default_sequence_name('ex_with_non_standard_pk', 'code'), seq
+ end
+
+ def test_pk_and_sequence_for_with_custom_index_type_pk
+ @conn.exec_query('drop table if exists ex_with_custom_index_type_pk')
+ @conn.exec_query(<<-eosql)
+ CREATE TABLE `ex_with_custom_index_type_pk` (
+ `id` INT(11) DEFAULT NULL auto_increment,
+ PRIMARY KEY USING BTREE (`id`))
+ eosql
+ pk, seq = @conn.pk_and_sequence_for('ex_with_custom_index_type_pk')
+ assert_equal 'id', pk
+ assert_equal @conn.default_sequence_name('ex_with_custom_index_type_pk', 'id'), seq
+ end
+
private
def insert(ctx, data)
binds = data.map { |name, value|
diff --git a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
index 292c7efebb..6faceaf7c0 100644
--- a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
+++ b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
@@ -130,7 +130,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
end
def test_associations_work_with_reserved_words
- assert_nothing_raised { Select.find(:all, :include => [:groups]) }
+ assert_nothing_raised { Select.scoped(:includes => [:groups]).all }
end
#the following functions were added to DRY test cases
diff --git a/activerecord/test/cases/adapters/mysql/schema_test.rb b/activerecord/test/cases/adapters/mysql/schema_test.rb
index 29f885c6e7..d94bb629a7 100644
--- a/activerecord/test/cases/adapters/mysql/schema_test.rb
+++ b/activerecord/test/cases/adapters/mysql/schema_test.rb
@@ -20,7 +20,7 @@ module ActiveRecord
end
def test_schema
- assert @omgpost.find(:first)
+ assert @omgpost.first
end
def test_primary_key
diff --git a/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb b/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb
index cd9c1041dc..5e8065d80d 100644
--- a/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb
@@ -9,7 +9,7 @@ module ActiveRecord
def test_update_question_marks
str = "foo?bar"
- x = Topic.find :first
+ x = Topic.first
x.title = str
x.content = str
x.save!
@@ -28,7 +28,7 @@ module ActiveRecord
def test_update_null_bytes
str = "foo\0bar"
- x = Topic.find :first
+ x = Topic.first
x.title = str
x.content = str
x.save!
diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
index 3a9744e78f..32d4282623 100644
--- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
@@ -130,7 +130,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
end
def test_associations_work_with_reserved_words
- assert_nothing_raised { Select.find(:all, :include => [:groups]) }
+ assert_nothing_raised { Select.scoped(:includes => [:groups]).all }
end
#the following functions were added to DRY test cases
diff --git a/activerecord/test/cases/adapters/mysql2/schema_test.rb b/activerecord/test/cases/adapters/mysql2/schema_test.rb
index de4d9c2b33..2c0ed73c92 100644
--- a/activerecord/test/cases/adapters/mysql2/schema_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/schema_test.rb
@@ -20,7 +20,7 @@ module ActiveRecord
end
def test_schema
- assert @omgpost.find(:first)
+ assert @omgpost.first
end
def test_primary_key
diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
index 1644a58d92..23bafde17b 100644
--- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
require "cases/helper"
require 'active_record/base'
require 'active_record/connection_adapters/postgresql_adapter'
@@ -88,7 +90,7 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
def test_rewrite
@connection.execute "insert into hstores (tags) VALUES ('1=>2')"
- x = Hstore.find :first
+ x = Hstore.first
x.tags = { '"a\'' => 'b' }
assert x.save!
end
@@ -96,13 +98,13 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
def test_select
@connection.execute "insert into hstores (tags) VALUES ('1=>2')"
- x = Hstore.find :first
+ x = Hstore.first
assert_equal({'1' => '2'}, x.tags)
end
def test_select_multikey
@connection.execute "insert into hstores (tags) VALUES ('1=>2,2=>3')"
- x = Hstore.find :first
+ x = Hstore.first
assert_equal({'1' => '2', '2' => '3'}, x.tags)
end
@@ -134,13 +136,19 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
assert_cycle('a=>b' => 'bar', '1"foo' => '2')
end
+ def test_quoting_special_characters
+ assert_cycle('ca' => 'cà', 'ac' => 'àc')
+ end
+
private
def assert_cycle hash
+ # test creation
x = Hstore.create!(:tags => hash)
x.reload
assert_equal(hash, x.tags)
- # make sure updates work
+ # test updating
+ x = Hstore.create!(:tags => {})
x.tags = hash
x.save!
x.reload
diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
index 1dbeb66af6..2ba9143cd5 100644
--- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
@@ -5,7 +5,7 @@ require 'securerandom'
module ActiveRecord
module ConnectionAdapters
- class SQLiteAdapter
+ class SQLite3Adapter
class QuotingTest < ActiveRecord::TestCase
def setup
@conn = Base.sqlite3_connection :database => ':memory:',
diff --git a/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb b/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb
index ae272e2c4b..2f04c60a9a 100644
--- a/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb
@@ -1,7 +1,7 @@
require 'cases/helper'
module ActiveRecord::ConnectionAdapters
- class SQLiteAdapter
+ class SQLite3Adapter
class StatementPoolTest < ActiveRecord::TestCase
def test_cache_is_per_pid
return skip('must support fork') unless Process.respond_to?(:fork)
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 1160d236c9..b351196fbd 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -73,14 +73,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
def test_eager_loading_with_primary_key
Firm.create("name" => "Apple")
Client.create("name" => "Citibank", :firm_name => "Apple")
- citibank_result = Client.find(:first, :conditions => {:name => "Citibank"}, :include => :firm_with_primary_key)
+ citibank_result = Client.scoped(:where => {:name => "Citibank"}, :includes => :firm_with_primary_key).first
assert citibank_result.association_cache.key?(:firm_with_primary_key)
end
def test_eager_loading_with_primary_key_as_symbol
Firm.create("name" => "Apple")
Client.create("name" => "Citibank", :firm_name => "Apple")
- citibank_result = Client.find(:first, :conditions => {:name => "Citibank"}, :include => :firm_with_primary_key_symbols)
+ citibank_result = Client.scoped(:where => {:name => "Citibank"}, :includes => :firm_with_primary_key_symbols).first
assert citibank_result.association_cache.key?(:firm_with_primary_key_symbols)
end
@@ -168,6 +168,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
sponsor.sponsorable = Member.new :name => "Bert"
assert_equal Member, sponsor.association(:sponsorable).send(:klass)
+ assert_equal "members", sponsor.association(:sponsorable).aliased_table_name
end
def test_with_polymorphic_and_condition
@@ -181,7 +182,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
def test_with_select
assert_equal Company.find(2).firm_with_select.attributes.size, 1
- assert_equal Company.find(2, :include => :firm_with_select ).firm_with_select.attributes.size, 1
+ assert_equal Company.scoped(:includes => :firm_with_select ).find(2).firm_with_select.attributes.size, 1
end
def test_belongs_to_counter
@@ -333,7 +334,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
def test_new_record_with_foreign_key_but_no_object
c = Client.new("firm_id" => 1)
# sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
- assert_equal Firm.find(:first, :order => "id"), c.firm_with_basic_id
+ assert_equal Firm.scoped(:order => "id").first, c.firm_with_basic_id
end
def test_setting_foreign_key_after_nil_target_loaded
@@ -393,9 +394,9 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
end
def test_association_assignment_sticks
- post = Post.find(:first)
+ post = Post.first
- author1, author2 = Author.find(:all, :limit => 2)
+ author1, author2 = Author.scoped(:limit => 2).all
assert_not_nil author1
assert_not_nil author2
@@ -497,14 +498,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_nothing_raised do
Account.find(@account.id).save!
- Account.find(@account.id, :include => :firm).save!
+ Account.scoped(:includes => :firm).find(@account.id).save!
end
@account.firm.delete
assert_nothing_raised do
Account.find(@account.id).save!
- Account.find(@account.id, :include => :firm).save!
+ Account.scoped(:includes => :firm).find(@account.id).save!
end
end
@@ -704,4 +705,27 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal toy, sponsor.reload.sponsorable
end
+
+ test "stale tracking doesn't care about the type" do
+ apple = Firm.create("name" => "Apple")
+ citibank = Account.create("credit_limit" => 10)
+
+ citibank.firm_id = apple.id
+ citibank.firm # load it
+
+ citibank.firm_id = apple.id.to_s
+
+ assert !citibank.association(:firm).stale_target?
+ end
+
+ def test_reflect_the_most_recent_change
+ author1, author2 = Author.limit(2)
+ post = Post.new(:title => "foo", :body=> "bar")
+
+ post.author = author1
+ post.author_id = author2.id
+
+ assert post.save
+ assert_equal post.author_id, author2.id
+ end
end
diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
index 6733f3e889..01f7f18397 100644
--- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
+++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
@@ -16,7 +16,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
:categorizations, :people, :categories, :edges, :vertices
def test_eager_association_loading_with_cascaded_two_levels
- authors = Author.find(:all, :include=>{:posts=>:comments}, :order=>"authors.id")
+ authors = Author.scoped(:includes=>{:posts=>:comments}, :order=>"authors.id").all
assert_equal 3, authors.size
assert_equal 5, authors[0].posts.size
assert_equal 3, authors[1].posts.size
@@ -24,7 +24,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
end
def test_eager_association_loading_with_cascaded_two_levels_and_one_level
- authors = Author.find(:all, :include=>[{:posts=>:comments}, :categorizations], :order=>"authors.id")
+ authors = Author.scoped(:includes=>[{:posts=>:comments}, :categorizations], :order=>"authors.id").all
assert_equal 3, authors.size
assert_equal 5, authors[0].posts.size
assert_equal 3, authors[1].posts.size
@@ -84,7 +84,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
end
def test_eager_association_loading_with_cascaded_two_levels_with_two_has_many_associations
- authors = Author.find(:all, :include=>{:posts=>[:comments, :categorizations]}, :order=>"authors.id")
+ authors = Author.scoped(:includes=>{:posts=>[:comments, :categorizations]}, :order=>"authors.id").all
assert_equal 3, authors.size
assert_equal 5, authors[0].posts.size
assert_equal 3, authors[1].posts.size
@@ -92,7 +92,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
end
def test_eager_association_loading_with_cascaded_two_levels_and_self_table_reference
- authors = Author.find(:all, :include=>{:posts=>[:comments, :author]}, :order=>"authors.id")
+ authors = Author.scoped(:includes=>{:posts=>[:comments, :author]}, :order=>"authors.id").all
assert_equal 3, authors.size
assert_equal 5, authors[0].posts.size
assert_equal authors(:david).name, authors[0].name
@@ -100,13 +100,13 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
end
def test_eager_association_loading_with_cascaded_two_levels_with_condition
- authors = Author.find(:all, :include=>{:posts=>:comments}, :conditions=>"authors.id=1", :order=>"authors.id")
+ authors = Author.scoped(:includes=>{:posts=>:comments}, :where=>"authors.id=1", :order=>"authors.id").all
assert_equal 1, authors.size
assert_equal 5, authors[0].posts.size
end
def test_eager_association_loading_with_cascaded_three_levels_by_ping_pong
- firms = Firm.find(:all, :include=>{:account=>{:firm=>:account}}, :order=>"companies.id")
+ firms = Firm.scoped(:includes=>{:account=>{:firm=>:account}}, :order=>"companies.id").all
assert_equal 2, firms.size
assert_equal firms.first.account, firms.first.account.firm.account
assert_equal companies(:first_firm).account, assert_no_queries { firms.first.account.firm.account }
@@ -114,7 +114,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
end
def test_eager_association_loading_with_has_many_sti
- topics = Topic.find(:all, :include => :replies, :order => 'topics.id')
+ topics = Topic.scoped(:includes => :replies, :order => 'topics.id').all
first, second, = topics(:first).replies.size, topics(:second).replies.size
assert_no_queries do
assert_equal first, topics[0].replies.size
@@ -127,7 +127,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
silly.parent_id = 1
assert silly.save
- topics = Topic.find(:all, :include => :replies, :order => ['topics.id', 'replies_topics.id'])
+ topics = Topic.scoped(:includes => :replies, :order => ['topics.id', 'replies_topics.id']).all
assert_no_queries do
assert_equal 2, topics[0].replies.size
assert_equal 0, topics[1].replies.size
@@ -135,14 +135,14 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
end
def test_eager_association_loading_with_belongs_to_sti
- replies = Reply.find(:all, :include => :topic, :order => 'topics.id')
+ replies = Reply.scoped(:includes => :topic, :order => 'topics.id').all
assert replies.include?(topics(:second))
assert !replies.include?(topics(:first))
assert_equal topics(:first), assert_no_queries { replies.first.topic }
end
def test_eager_association_loading_with_multiple_stis_and_order
- author = Author.find(:first, :include => { :posts => [ :special_comments , :very_special_comment ] }, :order => ['authors.name', 'comments.body', 'very_special_comments_posts.body'], :conditions => 'posts.id = 4')
+ author = Author.scoped(:includes => { :posts => [ :special_comments , :very_special_comment ] }, :order => ['authors.name', 'comments.body', 'very_special_comments_posts.body'], :where => 'posts.id = 4').first
assert_equal authors(:david), author
assert_no_queries do
author.posts.first.special_comments
@@ -151,7 +151,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
end
def test_eager_association_loading_of_stis_with_multiple_references
- authors = Author.find(:all, :include => { :posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } } }, :order => 'comments.body, very_special_comments_posts.body', :conditions => 'posts.id = 4')
+ authors = Author.scoped(:includes => { :posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } } }, :order => 'comments.body, very_special_comments_posts.body', :where => 'posts.id = 4').all
assert_equal [authors(:david)], authors
assert_no_queries do
authors.first.posts.first.special_comments.first.post.special_comments
@@ -160,7 +160,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
end
def test_eager_association_loading_where_first_level_returns_nil
- authors = Author.find(:all, :include => {:post_about_thinking => :comments}, :order => 'authors.id DESC')
+ authors = Author.scoped(:includes => {:post_about_thinking => :comments}, :order => 'authors.id DESC').all
assert_equal [authors(:bob), authors(:mary), authors(:david)], authors
assert_no_queries do
authors[2].post_about_thinking.comments.first
@@ -168,12 +168,12 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
end
def test_eager_association_loading_with_recursive_cascading_four_levels_has_many_through
- source = Vertex.find(:first, :include=>{:sinks=>{:sinks=>{:sinks=>:sinks}}}, :order => 'vertices.id')
+ source = Vertex.scoped(:includes=>{:sinks=>{:sinks=>{:sinks=>:sinks}}}, :order => 'vertices.id').first
assert_equal vertices(:vertex_4), assert_no_queries { source.sinks.first.sinks.first.sinks.first }
end
def test_eager_association_loading_with_recursive_cascading_four_levels_has_and_belongs_to_many
- sink = Vertex.find(:first, :include=>{:sources=>{:sources=>{:sources=>:sources}}}, :order => 'vertices.id DESC')
+ sink = Vertex.scoped(:includes=>{:sources=>{:sources=>{:sources=>:sources}}}, :order => 'vertices.id DESC').first
assert_equal vertices(:vertex_1), assert_no_queries { sink.sources.first.sources.first.sources.first.sources.first }
end
end
diff --git a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
index 3044a8c312..75a6295350 100644
--- a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
+++ b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
@@ -24,11 +24,11 @@ class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase
old = ActiveRecord::Base.store_full_sti_class
ActiveRecord::Base.store_full_sti_class = false
- post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging )
+ post = Namespaced::Post.includes(:tagging).find_by_title('Great stuff')
assert_nil post.tagging
ActiveRecord::Base.store_full_sti_class = true
- post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging )
+ post = Namespaced::Post.includes(:tagging).find_by_title('Great stuff')
assert_instance_of Tagging, post.tagging
ensure
ActiveRecord::Base.store_full_sti_class = old
diff --git a/activerecord/test/cases/associations/eager_load_nested_include_test.rb b/activerecord/test/cases/associations/eager_load_nested_include_test.rb
index 1e1958410c..861a395c58 100644
--- a/activerecord/test/cases/associations/eager_load_nested_include_test.rb
+++ b/activerecord/test/cases/associations/eager_load_nested_include_test.rb
@@ -93,7 +93,7 @@ class EagerLoadPolyAssocsTest < ActiveRecord::TestCase
def test_include_query
res = 0
- res = ShapeExpression.find :all, :include => [ :shape, { :paint => :non_poly } ]
+ res = ShapeExpression.scoped(:includes => [ :shape, { :paint => :non_poly } ]).all
assert_equal NUM_SHAPE_EXPRESSIONS, res.size
assert_queries(0) do
res.each do |se|
@@ -123,7 +123,7 @@ class EagerLoadNestedIncludeWithMissingDataTest < ActiveRecord::TestCase
assert_nothing_raised do
# @davey_mcdave doesn't have any author_favorites
includes = {:posts => :comments, :categorizations => :category, :author_favorites => :favorite_author }
- Author.all :include => includes, :conditions => {:authors => {:name => @davey_mcdave.name}}, :order => 'categories.name'
+ Author.scoped(:includes => includes, :where => {:authors => {:name => @davey_mcdave.name}}, :order => 'categories.name').to_a
end
end
end
diff --git a/activerecord/test/cases/associations/eager_singularization_test.rb b/activerecord/test/cases/associations/eager_singularization_test.rb
index 07d0b24613..5805e71249 100644
--- a/activerecord/test/cases/associations/eager_singularization_test.rb
+++ b/activerecord/test/cases/associations/eager_singularization_test.rb
@@ -103,43 +103,43 @@ class EagerSingularizationTest < ActiveRecord::TestCase
def test_eager_no_extra_singularization_belongs_to
return unless @have_tables
assert_nothing_raised do
- Virus.find(:all, :include => :octopus)
+ Virus.scoped(:includes => :octopus).all
end
end
def test_eager_no_extra_singularization_has_one
return unless @have_tables
assert_nothing_raised do
- Octopus.find(:all, :include => :virus)
+ Octopus.scoped(:includes => :virus).all
end
end
def test_eager_no_extra_singularization_has_many
return unless @have_tables
assert_nothing_raised do
- Bus.find(:all, :include => :passes)
+ Bus.scoped(:includes => :passes).all
end
end
def test_eager_no_extra_singularization_has_and_belongs_to_many
return unless @have_tables
assert_nothing_raised do
- Crisis.find(:all, :include => :messes)
- Mess.find(:all, :include => :crises)
+ Crisis.scoped(:includes => :messes).all
+ Mess.scoped(:includes => :crises).all
end
end
def test_eager_no_extra_singularization_has_many_through_belongs_to
return unless @have_tables
assert_nothing_raised do
- Crisis.find(:all, :include => :successes)
+ Crisis.scoped(:includes => :successes).all
end
end
def test_eager_no_extra_singularization_has_many_through_has_many
return unless @have_tables
assert_nothing_raised do
- Crisis.find(:all, :include => :compresses)
+ Crisis.scoped(:includes => :compresses).all
end
end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index efdb7cbb36..2e44005847 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -35,42 +35,42 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_has_one_through_join_model_with_conditions_on_the_through
- member = Member.find(members(:some_other_guy).id, :include => :favourite_club)
+ member = Member.scoped(:includes => :favourite_club).find(members(:some_other_guy).id)
assert_nil member.favourite_club
end
def test_loading_with_one_association
- posts = Post.find(:all, :include => :comments)
+ posts = Post.scoped(:includes => :comments).all
post = posts.find { |p| p.id == 1 }
assert_equal 2, post.comments.size
assert post.comments.include?(comments(:greetings))
- post = Post.find(:first, :include => :comments, :conditions => "posts.title = 'Welcome to the weblog'")
+ post = Post.scoped(:includes => :comments, :where => "posts.title = 'Welcome to the weblog'").first
assert_equal 2, post.comments.size
assert post.comments.include?(comments(:greetings))
- posts = Post.find(:all, :include => :last_comment)
+ posts = Post.scoped(:includes => :last_comment).all
post = posts.find { |p| p.id == 1 }
assert_equal Post.find(1).last_comment, post.last_comment
end
def test_loading_with_one_association_with_non_preload
- posts = Post.find(:all, :include => :last_comment, :order => 'comments.id DESC')
+ posts = Post.scoped(:includes => :last_comment, :order => 'comments.id DESC').all
post = posts.find { |p| p.id == 1 }
assert_equal Post.find(1).last_comment, post.last_comment
end
def test_loading_conditions_with_or
- posts = authors(:david).posts.find(
- :all, :include => :comments, :references => :comments,
- :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE} = 'SpecialComment'"
- )
+ posts = authors(:david).posts.references(:comments).scoped(
+ :includes => :comments,
+ :where => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE} = 'SpecialComment'"
+ ).all
assert_nil posts.detect { |p| p.author_id != authors(:david).id },
"expected to find only david's posts"
end
def test_with_ordering
- list = Post.find(:all, :include => :comments, :order => "posts.id DESC")
+ list = Post.scoped(:includes => :comments, :order => "posts.id DESC").all
[:other_by_mary, :other_by_bob, :misc_by_mary, :misc_by_bob, :eager_other,
:sti_habtm, :sti_post_and_comments, :sti_comments, :authorless, :thinking, :welcome
].each_with_index do |post, index|
@@ -84,14 +84,14 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_loading_with_multiple_associations
- posts = Post.find(:all, :include => [ :comments, :author, :categories ], :order => "posts.id")
+ posts = Post.scoped(:includes => [ :comments, :author, :categories ], :order => "posts.id").all
assert_equal 2, posts.first.comments.size
assert_equal 2, posts.first.categories.size
assert posts.first.comments.include?(comments(:greetings))
end
def test_duplicate_middle_objects
- comments = Comment.find :all, :conditions => 'post_id = 1', :include => [:post => :author]
+ comments = Comment.scoped(:where => 'post_id = 1', :includes => [:post => :author]).all
assert_no_queries do
comments.each {|comment| comment.post.author.name}
end
@@ -99,25 +99,25 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_preloading_has_many_in_multiple_queries_with_more_ids_than_database_can_handle
Post.connection.expects(:in_clause_length).at_least_once.returns(5)
- posts = Post.find(:all, :include=>:comments)
+ posts = Post.scoped(:includes=>:comments).all
assert_equal 11, posts.size
end
def test_preloading_has_many_in_one_queries_when_database_has_no_limit_on_ids_it_can_handle
Post.connection.expects(:in_clause_length).at_least_once.returns(nil)
- posts = Post.find(:all, :include=>:comments)
+ posts = Post.scoped(:includes=>:comments).all
assert_equal 11, posts.size
end
def test_preloading_habtm_in_multiple_queries_with_more_ids_than_database_can_handle
Post.connection.expects(:in_clause_length).at_least_once.returns(5)
- posts = Post.find(:all, :include=>:categories)
+ posts = Post.scoped(:includes=>:categories).all
assert_equal 11, posts.size
end
def test_preloading_habtm_in_one_queries_when_database_has_no_limit_on_ids_it_can_handle
Post.connection.expects(:in_clause_length).at_least_once.returns(nil)
- posts = Post.find(:all, :include=>:categories)
+ posts = Post.scoped(:includes=>:categories).all
assert_equal 11, posts.size
end
@@ -154,8 +154,8 @@ class EagerAssociationTest < ActiveRecord::TestCase
popular_post.readers.create!(:person => people(:michael))
popular_post.readers.create!(:person => people(:david))
- readers = Reader.find(:all, :conditions => ["post_id = ?", popular_post.id],
- :include => {:post => :comments})
+ readers = Reader.scoped(:where => ["post_id = ?", popular_post.id],
+ :includes => {:post => :comments}).all
readers.each do |reader|
assert_equal [comment], reader.post.comments
end
@@ -167,8 +167,8 @@ class EagerAssociationTest < ActiveRecord::TestCase
car_post.categories << categories(:technology)
comment = car_post.comments.create!(:body => "hmm")
- categories = Category.find(:all, :conditions => { 'posts.id' => car_post.id },
- :include => {:posts => :comments})
+ categories = Category.scoped(:where => { 'posts.id' => car_post.id },
+ :includes => {:posts => :comments}).all
categories.each do |category|
assert_equal [comment], category.posts[0].comments
end
@@ -186,7 +186,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_finding_with_includes_on_has_many_association_with_same_include_includes_only_once
author_id = authors(:david).id
- author = assert_queries(3) { Author.find(author_id, :include => {:posts_with_comments => :comments}) } # find the author, then find the posts, then find the comments
+ author = assert_queries(3) { Author.scoped(:includes => {:posts_with_comments => :comments}).find(author_id) } # find the author, then find the posts, then find the comments
author.posts_with_comments.each do |post_with_comments|
assert_equal post_with_comments.comments.length, post_with_comments.comments.count
assert_nil post_with_comments.comments.uniq!
@@ -197,7 +197,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
author = authors(:david)
post = author.post_about_thinking_with_last_comment
last_comment = post.last_comment
- author = assert_queries(3) { Author.find(author.id, :include => {:post_about_thinking_with_last_comment => :last_comment})} # find the author, then find the posts, then find the comments
+ author = assert_queries(3) { Author.scoped(:includes => {:post_about_thinking_with_last_comment => :last_comment}).find(author.id)} # find the author, then find the posts, then find the comments
assert_no_queries do
assert_equal post, author.post_about_thinking_with_last_comment
assert_equal last_comment, author.post_about_thinking_with_last_comment.last_comment
@@ -208,7 +208,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
post = posts(:welcome)
author = post.author
author_address = author.author_address
- post = assert_queries(3) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author, then find the address
+ post = assert_queries(3) { Post.scoped(:includes => {:author_with_address => :author_address}).find(post.id) } # find the post, then find the author, then find the address
assert_no_queries do
assert_equal author, post.author_with_address
assert_equal author_address, post.author_with_address.author_address
@@ -218,7 +218,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_finding_with_includes_on_null_belongs_to_association_with_same_include_includes_only_once
post = posts(:welcome)
post.update_attributes!(:author => nil)
- post = assert_queries(1) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author which is null so no query for the author or address
+ post = assert_queries(1) { Post.scoped(:includes => {:author_with_address => :author_address}).find(post.id) } # find the post, then find the author which is null so no query for the author or address
assert_no_queries do
assert_equal nil, post.author_with_address
end
@@ -227,85 +227,85 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_finding_with_includes_on_null_belongs_to_polymorphic_association
sponsor = sponsors(:moustache_club_sponsor_for_groucho)
sponsor.update_attributes!(:sponsorable => nil)
- sponsor = assert_queries(1) { Sponsor.find(sponsor.id, :include => :sponsorable) }
+ sponsor = assert_queries(1) { Sponsor.scoped(:includes => :sponsorable).find(sponsor.id) }
assert_no_queries do
assert_equal nil, sponsor.sponsorable
end
end
def test_loading_from_an_association
- posts = authors(:david).posts.find(:all, :include => :comments, :order => "posts.id")
+ posts = authors(:david).posts.scoped(:includes => :comments, :order => "posts.id").all
assert_equal 2, posts.first.comments.size
end
def test_loading_from_an_association_that_has_a_hash_of_conditions
assert_nothing_raised do
- Author.find(:all, :include => :hello_posts_with_hash_conditions)
+ Author.scoped(:includes => :hello_posts_with_hash_conditions).all
end
- assert !Author.find(authors(:david).id, :include => :hello_posts_with_hash_conditions).hello_posts.empty?
+ assert !Author.scoped(:includes => :hello_posts_with_hash_conditions).find(authors(:david).id).hello_posts.empty?
end
def test_loading_with_no_associations
- assert_nil Post.find(posts(:authorless).id, :include => :author).author
+ assert_nil Post.scoped(:includes => :author).find(posts(:authorless).id).author
end
def test_nested_loading_with_no_associations
assert_nothing_raised do
- Post.find(posts(:authorless).id, :include => {:author => :author_addresss})
+ Post.scoped(:includes => {:author => :author_addresss}).find(posts(:authorless).id)
end
end
def test_nested_loading_through_has_one_association
- aa = AuthorAddress.find(author_addresses(:david_address).id, :include => {:author => :posts})
+ aa = AuthorAddress.scoped(:includes => {:author => :posts}).find(author_addresses(:david_address).id)
assert_equal aa.author.posts.count, aa.author.posts.length
end
def test_nested_loading_through_has_one_association_with_order
- aa = AuthorAddress.find(author_addresses(:david_address).id, :include => {:author => :posts}, :order => 'author_addresses.id')
+ aa = AuthorAddress.scoped(:includes => {:author => :posts}, :order => 'author_addresses.id').find(author_addresses(:david_address).id)
assert_equal aa.author.posts.count, aa.author.posts.length
end
def test_nested_loading_through_has_one_association_with_order_on_association
- aa = AuthorAddress.find(author_addresses(:david_address).id, :include => {:author => :posts}, :order => 'authors.id')
+ aa = AuthorAddress.scoped(:includes => {:author => :posts}, :order => 'authors.id').find(author_addresses(:david_address).id)
assert_equal aa.author.posts.count, aa.author.posts.length
end
def test_nested_loading_through_has_one_association_with_order_on_nested_association
- aa = AuthorAddress.find(author_addresses(:david_address).id, :include => {:author => :posts}, :order => 'posts.id')
+ aa = AuthorAddress.scoped(:includes => {:author => :posts}, :order => 'posts.id').find(author_addresses(:david_address).id)
assert_equal aa.author.posts.count, aa.author.posts.length
end
def test_nested_loading_through_has_one_association_with_conditions
- aa = AuthorAddress.find(
- author_addresses(:david_address).id, :include => {:author => :posts},
- :conditions => "author_addresses.id > 0", :references => :author_addresses
- )
+ aa = AuthorAddress.references(:author_addresses).scoped(
+ :includes => {:author => :posts},
+ :where => "author_addresses.id > 0"
+ ).find author_addresses(:david_address).id
assert_equal aa.author.posts.count, aa.author.posts.length
end
def test_nested_loading_through_has_one_association_with_conditions_on_association
- aa = AuthorAddress.find(
- author_addresses(:david_address).id, :include => {:author => :posts},
- :conditions => "authors.id > 0", :references => :authors
- )
+ aa = AuthorAddress.references(:authors).scoped(
+ :includes => {:author => :posts},
+ :where => "authors.id > 0"
+ ).find author_addresses(:david_address).id
assert_equal aa.author.posts.count, aa.author.posts.length
end
def test_nested_loading_through_has_one_association_with_conditions_on_nested_association
- aa = AuthorAddress.find(
- author_addresses(:david_address).id, :include => {:author => :posts},
- :conditions => "posts.id > 0", :references => :posts
- )
+ aa = AuthorAddress.references(:posts).scoped(
+ :includes => {:author => :posts},
+ :where => "posts.id > 0"
+ ).find author_addresses(:david_address).id
assert_equal aa.author.posts.count, aa.author.posts.length
end
def test_eager_association_loading_with_belongs_to_and_foreign_keys
- pets = Pet.find(:all, :include => :owner)
+ pets = Pet.scoped(:includes => :owner).all
assert_equal 3, pets.length
end
def test_eager_association_loading_with_belongs_to
- comments = Comment.find(:all, :include => :post)
+ comments = Comment.scoped(:includes => :post).all
assert_equal 11, comments.length
titles = comments.map { |c| c.post.title }
assert titles.include?(posts(:welcome).title)
@@ -313,31 +313,31 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_association_loading_with_belongs_to_and_limit
- comments = Comment.find(:all, :include => :post, :limit => 5, :order => 'comments.id')
+ comments = Comment.scoped(:includes => :post, :limit => 5, :order => 'comments.id').all
assert_equal 5, comments.length
assert_equal [1,2,3,5,6], comments.collect { |c| c.id }
end
def test_eager_association_loading_with_belongs_to_and_limit_and_conditions
- comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :order => 'comments.id')
+ comments = Comment.scoped(:includes => :post, :where => 'post_id = 4', :limit => 3, :order => 'comments.id').all
assert_equal 3, comments.length
assert_equal [5,6,7], comments.collect { |c| c.id }
end
def test_eager_association_loading_with_belongs_to_and_limit_and_offset
- comments = Comment.find(:all, :include => :post, :limit => 3, :offset => 2, :order => 'comments.id')
+ comments = Comment.scoped(:includes => :post, :limit => 3, :offset => 2, :order => 'comments.id').all
assert_equal 3, comments.length
assert_equal [3,5,6], comments.collect { |c| c.id }
end
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions
- comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :offset => 1, :order => 'comments.id')
+ comments = Comment.scoped(:includes => :post, :where => 'post_id = 4', :limit => 3, :offset => 1, :order => 'comments.id').all
assert_equal 3, comments.length
assert_equal [6,7,8], comments.collect { |c| c.id }
end
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions_array
- comments = Comment.find(:all, :include => :post, :conditions => ['post_id = ?',4], :limit => 3, :offset => 1, :order => 'comments.id')
+ comments = Comment.scoped(:includes => :post, :where => ['post_id = ?',4], :limit => 3, :offset => 1, :order => 'comments.id').all
assert_equal 3, comments.length
assert_equal [6,7,8], comments.collect { |c| c.id }
end
@@ -345,7 +345,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_association_loading_with_belongs_to_and_conditions_string_with_unquoted_table_name
assert_nothing_raised do
ActiveSupport::Deprecation.silence do
- Comment.find(:all, :include => :post, :conditions => ['posts.id = ?',4])
+ Comment.scoped(:includes => :post, :where => ['posts.id = ?',4]).all
end
end
end
@@ -353,7 +353,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_association_loading_with_belongs_to_and_conditions_hash
comments = []
assert_nothing_raised do
- comments = Comment.find(:all, :include => :post, :conditions => {:posts => {:id => 4}}, :limit => 3, :order => 'comments.id')
+ comments = Comment.scoped(:includes => :post, :where => {:posts => {:id => 4}}, :limit => 3, :order => 'comments.id').all
end
assert_equal 3, comments.length
assert_equal [5,6,7], comments.collect { |c| c.id }
@@ -366,14 +366,14 @@ class EagerAssociationTest < ActiveRecord::TestCase
quoted_posts_id= Comment.connection.quote_table_name('posts') + '.' + Comment.connection.quote_column_name('id')
assert_nothing_raised do
ActiveSupport::Deprecation.silence do
- Comment.find(:all, :include => :post, :conditions => ["#{quoted_posts_id} = ?",4])
+ Comment.scoped(:includes => :post, :where => ["#{quoted_posts_id} = ?",4]).all
end
end
end
def test_eager_association_loading_with_belongs_to_and_order_string_with_unquoted_table_name
assert_nothing_raised do
- Comment.find(:all, :include => :post, :order => 'posts.id')
+ Comment.scoped(:includes => :post, :order => 'posts.id').all
end
end
@@ -381,55 +381,55 @@ class EagerAssociationTest < ActiveRecord::TestCase
quoted_posts_id= Comment.connection.quote_table_name('posts') + '.' + Comment.connection.quote_column_name('id')
assert_nothing_raised do
ActiveSupport::Deprecation.silence do
- Comment.find(:all, :include => :post, :order => quoted_posts_id)
+ Comment.scoped(:includes => :post, :order => quoted_posts_id).all
end
end
end
def test_eager_association_loading_with_belongs_to_and_limit_and_multiple_associations
- posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :order => 'posts.id')
+ posts = Post.scoped(:includes => [:author, :very_special_comment], :limit => 1, :order => 'posts.id').all
assert_equal 1, posts.length
assert_equal [1], posts.collect { |p| p.id }
end
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_multiple_associations
- posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :offset => 1, :order => 'posts.id')
+ posts = Post.scoped(:includes => [:author, :very_special_comment], :limit => 1, :offset => 1, :order => 'posts.id').all
assert_equal 1, posts.length
assert_equal [2], posts.collect { |p| p.id }
end
def test_eager_association_loading_with_belongs_to_inferred_foreign_key_from_association_name
- author_favorite = AuthorFavorite.find(:first, :include => :favorite_author)
+ author_favorite = AuthorFavorite.scoped(:includes => :favorite_author).first
assert_equal authors(:mary), assert_no_queries { author_favorite.favorite_author }
end
def test_eager_load_belongs_to_quotes_table_and_column_names
- job = Job.find jobs(:unicyclist).id, :include => :ideal_reference
+ job = Job.includes(:ideal_reference).find jobs(:unicyclist).id
references(:michael_unicyclist)
assert_no_queries{ assert_equal references(:michael_unicyclist), job.ideal_reference}
end
def test_eager_load_has_one_quotes_table_and_column_names
- michael = Person.find(people(:michael), :include => :favourite_reference)
+ michael = Person.scoped(:includes => :favourite_reference).find(people(:michael))
references(:michael_unicyclist)
assert_no_queries{ assert_equal references(:michael_unicyclist), michael.favourite_reference}
end
def test_eager_load_has_many_quotes_table_and_column_names
- michael = Person.find(people(:michael), :include => :references)
+ michael = Person.scoped(:includes => :references).find(people(:michael))
references(:michael_magician,:michael_unicyclist)
assert_no_queries{ assert_equal references(:michael_magician,:michael_unicyclist), michael.references.sort_by(&:id) }
end
def test_eager_load_has_many_through_quotes_table_and_column_names
- michael = Person.find(people(:michael), :include => :jobs)
+ michael = Person.scoped(:includes => :jobs).find(people(:michael))
jobs(:magician, :unicyclist)
assert_no_queries{ assert_equal jobs(:unicyclist, :magician), michael.jobs.sort_by(&:id) }
end
def test_eager_load_has_many_with_string_keys
subscriptions = subscriptions(:webster_awdr, :webster_rfr)
- subscriber =Subscriber.find(subscribers(:second).id, :include => :subscriptions)
+ subscriber =Subscriber.scoped(:includes => :subscriptions).find(subscribers(:second).id)
assert_equal subscriptions, subscriber.subscriptions.sort_by(&:id)
end
@@ -447,25 +447,25 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_load_has_many_through_with_string_keys
books = books(:awdr, :rfr)
- subscriber = Subscriber.find(subscribers(:second).id, :include => :books)
+ subscriber = Subscriber.scoped(:includes => :books).find(subscribers(:second).id)
assert_equal books, subscriber.books.sort_by(&:id)
end
def test_eager_load_belongs_to_with_string_keys
subscriber = subscribers(:second)
- subscription = Subscription.find(subscriptions(:webster_awdr).id, :include => :subscriber)
+ subscription = Subscription.scoped(:includes => :subscriber).find(subscriptions(:webster_awdr).id)
assert_equal subscriber, subscription.subscriber
end
def test_eager_association_loading_with_explicit_join
- posts = Post.find(:all, :include => :comments, :joins => "INNER JOIN authors ON posts.author_id = authors.id AND authors.name = 'Mary'", :limit => 1, :order => 'author_id')
+ posts = Post.scoped(:includes => :comments, :joins => "INNER JOIN authors ON posts.author_id = authors.id AND authors.name = 'Mary'", :limit => 1, :order => 'author_id').all
assert_equal 1, posts.length
end
def test_eager_with_has_many_through
- posts_with_comments = people(:michael).posts.find(:all, :include => :comments, :order => 'posts.id')
- posts_with_author = people(:michael).posts.find(:all, :include => :author, :order => 'posts.id')
- posts_with_comments_and_author = people(:michael).posts.find(:all, :include => [ :comments, :author ], :order => 'posts.id')
+ posts_with_comments = people(:michael).posts.scoped(:includes => :comments, :order => 'posts.id').all
+ posts_with_author = people(:michael).posts.scoped(:includes => :author, :order => 'posts.id').all
+ posts_with_comments_and_author = people(:michael).posts.scoped(:includes => [ :comments, :author ], :order => 'posts.id').all
assert_equal 2, posts_with_comments.inject(0) { |sum, post| sum += post.comments.size }
assert_equal authors(:david), assert_no_queries { posts_with_author.first.author }
assert_equal authors(:david), assert_no_queries { posts_with_comments_and_author.first.author }
@@ -476,32 +476,32 @@ class EagerAssociationTest < ActiveRecord::TestCase
Post.create!(:author => author, :title => "TITLE", :body => "BODY")
author.author_favorites.create(:favorite_author_id => 1)
author.author_favorites.create(:favorite_author_id => 2)
- posts_with_author_favorites = author.posts.find(:all, :include => :author_favorites)
+ posts_with_author_favorites = author.posts.scoped(:includes => :author_favorites).all
assert_no_queries { posts_with_author_favorites.first.author_favorites.first.author_id }
end
def test_eager_with_has_many_through_an_sti_join_model
- author = Author.find(:first, :include => :special_post_comments, :order => 'authors.id')
+ author = Author.scoped(:includes => :special_post_comments, :order => 'authors.id').first
assert_equal [comments(:does_it_hurt)], assert_no_queries { author.special_post_comments }
end
def test_eager_with_has_many_through_an_sti_join_model_with_conditions_on_both
- author = Author.find(:first, :include => :special_nonexistant_post_comments, :order => 'authors.id')
+ author = Author.scoped(:includes => :special_nonexistant_post_comments, :order => 'authors.id').first
assert_equal [], author.special_nonexistant_post_comments
end
def test_eager_with_has_many_through_join_model_with_conditions
- assert_equal Author.find(:first, :include => :hello_post_comments,
- :order => 'authors.id').hello_post_comments.sort_by(&:id),
- Author.find(:first, :order => 'authors.id').hello_post_comments.sort_by(&:id)
+ assert_equal Author.scoped(:includes => :hello_post_comments,
+ :order => 'authors.id').first.hello_post_comments.sort_by(&:id),
+ Author.scoped(:order => 'authors.id').first.hello_post_comments.sort_by(&:id)
end
def test_eager_with_has_many_through_join_model_with_conditions_on_top_level
- assert_equal comments(:more_greetings), Author.find(authors(:david).id, :include => :comments_with_order_and_conditions).comments_with_order_and_conditions.first
+ assert_equal comments(:more_greetings), Author.scoped(:includes => :comments_with_order_and_conditions).find(authors(:david).id).comments_with_order_and_conditions.first
end
def test_eager_with_has_many_through_join_model_with_include
- author_comments = Author.find(authors(:david).id, :include => :comments_with_include).comments_with_include.to_a
+ author_comments = Author.scoped(:includes => :comments_with_include).find(authors(:david).id).comments_with_include.to_a
assert_no_queries do
author_comments.first.post.title
end
@@ -509,7 +509,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_with_has_many_through_with_conditions_join_model_with_include
post_tags = Post.find(posts(:welcome).id).misc_tags
- eager_post_tags = Post.find(1, :include => :misc_tags).misc_tags
+ eager_post_tags = Post.scoped(:includes => :misc_tags).find(1).misc_tags
assert_equal post_tags, eager_post_tags
end
@@ -520,16 +520,16 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_has_many_and_limit
- posts = Post.find(:all, :order => 'posts.id asc', :include => [ :author, :comments ], :limit => 2)
+ posts = Post.scoped(:order => 'posts.id asc', :includes => [ :author, :comments ], :limit => 2).all
assert_equal 2, posts.size
assert_equal 3, posts.inject(0) { |sum, post| sum += post.comments.size }
end
def test_eager_with_has_many_and_limit_and_conditions
if current_adapter?(:OpenBaseAdapter)
- posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "FETCHBLOB(posts.body) = 'hello'", :order => "posts.id")
+ posts = Post.scoped(:includes => [ :author, :comments ], :limit => 2, :where => "FETCHBLOB(posts.body) = 'hello'", :order => "posts.id").all
else
- posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.body = 'hello'", :order => "posts.id")
+ posts = Post.scoped(:includes => [ :author, :comments ], :limit => 2, :where => "posts.body = 'hello'", :order => "posts.id").all
end
assert_equal 2, posts.size
assert_equal [4,5], posts.collect { |p| p.id }
@@ -537,9 +537,9 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_with_has_many_and_limit_and_conditions_array
if current_adapter?(:OpenBaseAdapter)
- posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "FETCHBLOB(posts.body) = ?", 'hello' ], :order => "posts.id")
+ posts = Post.scoped(:includes => [ :author, :comments ], :limit => 2, :where => [ "FETCHBLOB(posts.body) = ?", 'hello' ], :order => "posts.id").all
else
- posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "posts.body = ?", 'hello' ], :order => "posts.id")
+ posts = Post.scoped(:includes => [ :author, :comments ], :limit => 2, :where => [ "posts.body = ?", 'hello' ], :order => "posts.id").all
end
assert_equal 2, posts.size
assert_equal [4,5], posts.collect { |p| p.id }
@@ -547,7 +547,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_with_has_many_and_limit_and_conditions_array_on_the_eagers
posts = ActiveSupport::Deprecation.silence do
- Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
+ Post.scoped(:includes => [ :author, :comments ], :limit => 2, :where => [ "authors.name = ?", 'David' ]).all
end
assert_equal 2, posts.size
@@ -558,41 +558,41 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_has_many_and_limit_and_high_offset
- posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => { 'authors.name' => 'David' })
+ posts = Post.scoped(:includes => [ :author, :comments ], :limit => 2, :offset => 10, :where => { 'authors.name' => 'David' }).all
assert_equal 0, posts.size
end
def test_eager_with_has_many_and_limit_and_high_offset_and_multiple_array_conditions
assert_queries(1) do
- posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10,
- :conditions => [ "authors.name = ? and comments.body = ?", 'David', 'go crazy' ],
- :references => [:authors, :comments])
+ posts = Post.references(:authors, :comments).
+ scoped(:includes => [ :author, :comments ], :limit => 2, :offset => 10,
+ :where => [ "authors.name = ? and comments.body = ?", 'David', 'go crazy' ]).all
assert_equal 0, posts.size
end
end
def test_eager_with_has_many_and_limit_and_high_offset_and_multiple_hash_conditions
assert_queries(1) do
- posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10,
- :conditions => { 'authors.name' => 'David', 'comments.body' => 'go crazy' })
+ posts = Post.scoped(:includes => [ :author, :comments ], :limit => 2, :offset => 10,
+ :where => { 'authors.name' => 'David', 'comments.body' => 'go crazy' }).all
assert_equal 0, posts.size
end
end
def test_count_eager_with_has_many_and_limit_and_high_offset
- posts = Post.count(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => { 'authors.name' => 'David' })
+ posts = Post.scoped(:includes => [ :author, :comments ], :limit => 2, :offset => 10, :where => { 'authors.name' => 'David' }).count(:all)
assert_equal 0, posts
end
def test_eager_with_has_many_and_limit_with_no_results
- posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.title = 'magic forest'")
+ posts = Post.scoped(:includes => [ :author, :comments ], :limit => 2, :where => "posts.title = 'magic forest'").all
assert_equal 0, posts.size
end
def test_eager_count_performed_on_a_has_many_association_with_multi_table_conditional
author = authors(:david)
author_posts_without_comments = author.posts.select { |post| post.comments.blank? }
- assert_equal author_posts_without_comments.size, author.posts.count(:all, :include => :comments, :conditions => 'comments.id is null', :references => :comments)
+ assert_equal author_posts_without_comments.size, author.posts.includes(:comments).where('comments.id is null').references(:comments).count
end
def test_eager_count_performed_on_a_has_many_through_association_with_multi_table_conditional
@@ -602,7 +602,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_has_and_belongs_to_many_and_limit
- posts = Post.find(:all, :include => :categories, :order => "posts.id", :limit => 3)
+ posts = Post.scoped(:includes => :categories, :order => "posts.id", :limit => 3).all
assert_equal 3, posts.size
assert_equal 2, posts[0].categories.size
assert_equal 1, posts[1].categories.size
@@ -628,80 +628,47 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_has_many_and_limit_and_conditions_on_the_eagers
- posts = authors(:david).posts.find(:all,
- :include => :comments,
- :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
- :references => :comments,
- :limit => 2
- )
+ posts =
+ authors(:david).posts
+ .includes(:comments)
+ .where("comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'")
+ .references(:comments)
+ .limit(2)
+ .to_a
assert_equal 2, posts.size
- count = Post.count(
- :include => [ :comments, :author ],
- :conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
- :references => [:authors, :comments],
- :limit => 2
- )
+ count =
+ Post.includes(:comments, :author)
+ .where("authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')")
+ .references(:authors, :comments)
+ .limit(2)
+ .count
assert_equal count, posts.size
end
def test_eager_with_has_many_and_limit_and_scoped_conditions_on_the_eagers
posts = nil
- Post.send(:with_scope, :find => {
- :include => :comments,
- :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
- :references => :comments
- }) do
- posts = authors(:david).posts.find(:all, :limit => 2)
- assert_equal 2, posts.size
- end
+ Post.includes(:comments)
+ .where("comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'")
+ .references(:comments)
+ .scoping do
- Post.send(:with_scope, :find => {
- :include => [ :comments, :author ],
- :conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
- :references => [:authors, :comments]
- }) do
- count = Post.count(:limit => 2)
- assert_equal count, posts.size
+ posts = authors(:david).posts.limit(2).to_a
+ assert_equal 2, posts.size
end
- end
- def test_eager_with_has_many_and_limit_and_scoped_and_explicit_conditions_on_the_eagers
- Post.send(:with_scope, :find => { :conditions => "1=1" }) do
- posts = authors(:david).posts.find(:all,
- :include => :comments,
- :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
- :references => :comments,
- :limit => 2
- )
- assert_equal 2, posts.size
+ Post.includes(:comments, :author)
+ .where("authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')")
+ .references(:authors, :comments)
+ .scoping do
- count = Post.count(
- :include => [ :comments, :author ],
- :conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
- :references => [:authors, :comments],
- :limit => 2
- )
+ count = Post.limit(2).count
assert_equal count, posts.size
end
end
- def test_eager_with_scoped_order_using_association_limiting_without_explicit_scope
- posts_with_explicit_order = Post.find(
- :all, :conditions => 'comments.id is not null', :references => :comments,
- :include => :comments, :order => 'posts.id DESC', :limit => 2
- )
- posts_with_scoped_order = Post.send(:with_scope, :find => {:order => 'posts.id DESC'}) do
- Post.find(
- :all, :conditions => 'comments.id is not null',
- :references => :comments, :include => :comments, :limit => 2
- )
- end
- assert_equal posts_with_explicit_order, posts_with_scoped_order
- end
-
def test_eager_association_loading_with_habtm
- posts = Post.find(:all, :include => :categories, :order => "posts.id")
+ posts = Post.scoped(:includes => :categories, :order => "posts.id").all
assert_equal 2, posts[0].categories.size
assert_equal 1, posts[1].categories.size
assert_equal 0, posts[2].categories.size
@@ -710,23 +677,23 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_inheritance
- SpecialPost.find(:all, :include => [ :comments ])
+ SpecialPost.scoped(:includes => [ :comments ]).all
end
def test_eager_has_one_with_association_inheritance
- post = Post.find(4, :include => [ :very_special_comment ])
+ post = Post.scoped(:includes => [ :very_special_comment ]).find(4)
assert_equal "VerySpecialComment", post.very_special_comment.class.to_s
end
def test_eager_has_many_with_association_inheritance
- post = Post.find(4, :include => [ :special_comments ])
+ post = Post.scoped(:includes => [ :special_comments ]).find(4)
post.special_comments.each do |special_comment|
assert special_comment.is_a?(SpecialComment)
end
end
def test_eager_habtm_with_association_inheritance
- post = Post.find(6, :include => [ :special_categories ])
+ post = Post.scoped(:includes => [ :special_categories ]).find(6)
assert_equal 1, post.special_categories.size
post.special_categories.each do |special_category|
assert_equal "SpecialCategory", special_category.class.to_s
@@ -735,8 +702,8 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_with_has_one_dependent_does_not_destroy_dependent
assert_not_nil companies(:first_firm).account
- f = Firm.find(:first, :include => :account,
- :conditions => ["companies.name = ?", "37signals"])
+ f = Firm.scoped(:includes => :account,
+ :where => ["companies.name = ?", "37signals"]).first
assert_not_nil f.account
assert_equal companies(:first_firm, :reload).account, f.account
end
@@ -750,16 +717,16 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_with_invalid_association_reference
assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
- Post.find(6, :include=> :monkeys )
+ Post.scoped(:includes=> :monkeys ).find(6)
}
assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
- Post.find(6, :include=>[ :monkeys ])
+ Post.scoped(:includes=>[ :monkeys ]).find(6)
}
assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
- Post.find(6, :include=>[ 'monkeys' ])
+ Post.scoped(:includes=>[ 'monkeys' ]).find(6)
}
assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") {
- Post.find(6, :include=>[ :monkeys, :elephants ])
+ Post.scoped(:includes=>[ :monkeys, :elephants ]).find(6)
}
end
@@ -804,52 +771,51 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def find_all_ordered(className, include=nil)
- className.find(:all, :order=>"#{className.table_name}.#{className.primary_key}", :include=>include)
+ className.scoped(:order=>"#{className.table_name}.#{className.primary_key}", :includes=>include).all
end
def test_limited_eager_with_order
assert_equal(
posts(:thinking, :sti_comments),
- Post.find(
- :all, :include => [:author, :comments], :conditions => { 'authors.name' => 'David' },
+ Post.scoped(
+ :includes => [:author, :comments], :where => { 'authors.name' => 'David' },
:order => 'UPPER(posts.title)', :limit => 2, :offset => 1
- )
+ ).all
)
assert_equal(
posts(:sti_post_and_comments, :sti_comments),
- Post.find(
- :all, :include => [:author, :comments], :conditions => { 'authors.name' => 'David' },
+ Post.scoped(
+ :includes => [:author, :comments], :where => { 'authors.name' => 'David' },
:order => 'UPPER(posts.title) DESC', :limit => 2, :offset => 1
- )
+ ).all
)
end
def test_limited_eager_with_multiple_order_columns
assert_equal(
posts(:thinking, :sti_comments),
- Post.find(
- :all, :include => [:author, :comments], :conditions => { 'authors.name' => 'David' },
+ Post.scoped(
+ :includes => [:author, :comments], :where => { 'authors.name' => 'David' },
:order => ['UPPER(posts.title)', 'posts.id'], :limit => 2, :offset => 1
- )
+ ).all
)
assert_equal(
posts(:sti_post_and_comments, :sti_comments),
- Post.find(
- :all, :include => [:author, :comments], :conditions => { 'authors.name' => 'David' },
+ Post.scoped(
+ :includes => [:author, :comments], :where => { 'authors.name' => 'David' },
:order => ['UPPER(posts.title) DESC', 'posts.id'], :limit => 2, :offset => 1
- )
+ ).all
)
end
def test_limited_eager_with_numeric_in_association
assert_equal(
people(:david, :susan),
- Person.find(
- :all, :include => [:readers, :primary_contact, :number1_fan],
- :conditions => "number1_fans_people.first_name like 'M%'",
- :references => :number1_fans_people,
+ Person.references(:number1_fans_people).scoped(
+ :includes => [:readers, :primary_contact, :number1_fan],
+ :where => "number1_fans_people.first_name like 'M%'",
:order => 'people.id', :limit => 2, :offset => 0
- )
+ ).all
)
end
@@ -862,9 +828,9 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_polymorphic_type_condition
- post = Post.find(posts(:thinking).id, :include => :taggings)
+ post = Post.scoped(:includes => :taggings).find(posts(:thinking).id)
assert post.taggings.include?(taggings(:thinking_general))
- post = SpecialPost.find(posts(:thinking).id, :include => :taggings)
+ post = SpecialPost.scoped(:includes => :taggings).find(posts(:thinking).id)
assert post.taggings.include?(taggings(:thinking_general))
end
@@ -915,13 +881,13 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
end
def test_eager_with_valid_association_as_string_not_symbol
- assert_nothing_raised { Post.find(:all, :include => 'comments') }
+ assert_nothing_raised { Post.scoped(:includes => 'comments').all }
end
def test_eager_with_floating_point_numbers
assert_queries(2) do
# Before changes, the floating point numbers will be interpreted as table names and will cause this to run in one query
- Comment.find :all, :conditions => "123.456 = 123.456", :include => :post
+ Comment.scoped(:where => "123.456 = 123.456", :includes => :post).all
end
end
@@ -965,31 +931,31 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_count_with_include
if current_adapter?(:SybaseAdapter)
- assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "len(comments.body) > 15", :references => :comments)
+ assert_equal 3, authors(:david).posts_with_comments.where("len(comments.body) > 15").references(:comments).count
elsif current_adapter?(:OpenBaseAdapter)
- assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(FETCHBLOB(comments.body)) > 15", :references => :comments)
+ assert_equal 3, authors(:david).posts_with_comments.where("length(FETCHBLOB(comments.body)) > 15").references(:comments).count
else
- assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(comments.body) > 15", :references => :comments)
+ assert_equal 3, authors(:david).posts_with_comments.where("length(comments.body) > 15").references(:comments).count
end
end
def test_load_with_sti_sharing_association
assert_queries(2) do #should not do 1 query per subclass
- Comment.find :all, :include => :post
+ Comment.includes(:post).all
end
end
def test_conditions_on_join_table_with_include_and_limit
- assert_equal 3, Developer.find(:all, :include => 'projects', :conditions => { 'developers_projects.access_level' => 1 }, :limit => 5).size
+ assert_equal 3, Developer.scoped(:includes => 'projects', :where => { 'developers_projects.access_level' => 1 }, :limit => 5).all.size
end
def test_order_on_join_table_with_include_and_limit
- assert_equal 5, Developer.find(:all, :include => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).size
+ assert_equal 5, Developer.scoped(:includes => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).all.size
end
def test_eager_loading_with_order_on_joined_table_preloads
posts = assert_queries(2) do
- Post.find(:all, :joins => :comments, :include => :author, :order => 'comments.id DESC')
+ Post.scoped(:joins => :comments, :includes => :author, :order => 'comments.id DESC').all
end
assert_equal posts(:eager_other), posts[1]
assert_equal authors(:mary), assert_no_queries { posts[1].author}
@@ -997,24 +963,24 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_loading_with_conditions_on_joined_table_preloads
posts = assert_queries(2) do
- Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
+ Post.scoped(:select => 'distinct posts.*', :includes => :author, :joins => [:comments], :where => "comments.body like 'Thank you%'", :order => 'posts.id').all
end
assert_equal [posts(:welcome)], posts
assert_equal authors(:david), assert_no_queries { posts[0].author}
posts = assert_queries(2) do
- Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
+ Post.scoped(:select => 'distinct posts.*', :includes => :author, :joins => [:comments], :where => "comments.body like 'Thank you%'", :order => 'posts.id').all
end
assert_equal [posts(:welcome)], posts
assert_equal authors(:david), assert_no_queries { posts[0].author}
posts = assert_queries(2) do
- Post.find(:all, :include => :author, :joins => {:taggings => :tag}, :conditions => "tags.name = 'General'", :order => 'posts.id')
+ Post.scoped(:includes => :author, :joins => {:taggings => :tag}, :where => "tags.name = 'General'", :order => 'posts.id').all
end
assert_equal posts(:welcome, :thinking), posts
posts = assert_queries(2) do
- Post.find(:all, :include => :author, :joins => {:taggings => {:tag => :taggings}}, :conditions => "taggings_tags.super_tag_id=2", :order => 'posts.id')
+ Post.scoped(:includes => :author, :joins => {:taggings => {:tag => :taggings}}, :where => "taggings_tags.super_tag_id=2", :order => 'posts.id').all
end
assert_equal posts(:welcome, :thinking), posts
@@ -1022,13 +988,13 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_loading_with_conditions_on_string_joined_table_preloads
posts = assert_queries(2) do
- Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => "INNER JOIN comments on comments.post_id = posts.id", :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
+ Post.scoped(:select => 'distinct posts.*', :includes => :author, :joins => "INNER JOIN comments on comments.post_id = posts.id", :where => "comments.body like 'Thank you%'", :order => 'posts.id').all
end
assert_equal [posts(:welcome)], posts
assert_equal authors(:david), assert_no_queries { posts[0].author}
posts = assert_queries(2) do
- Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => ["INNER JOIN comments on comments.post_id = posts.id"], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
+ Post.scoped(:select => 'distinct posts.*', :includes => :author, :joins => ["INNER JOIN comments on comments.post_id = posts.id"], :where => "comments.body like 'Thank you%'", :order => 'posts.id').all
end
assert_equal [posts(:welcome)], posts
assert_equal authors(:david), assert_no_queries { posts[0].author}
@@ -1037,7 +1003,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_loading_with_select_on_joined_table_preloads
posts = assert_queries(2) do
- Post.find(:all, :select => 'posts.*, authors.name as author_name', :include => :comments, :joins => :author, :order => 'posts.id')
+ Post.scoped(:select => 'posts.*, authors.name as author_name', :includes => :comments, :joins => :author, :order => 'posts.id').all
end
assert_equal 'David', posts[0].author_name
assert_equal posts(:welcome).comments, assert_no_queries { posts[0].comments}
@@ -1047,14 +1013,14 @@ class EagerAssociationTest < ActiveRecord::TestCase
Author.columns
authors = assert_queries(2) do
- Author.find(:all, :include => :author_address, :joins => :comments, :conditions => "posts.title like 'Welcome%'")
+ Author.scoped(:includes => :author_address, :joins => :comments, :where => "posts.title like 'Welcome%'").all
end
assert_equal authors(:david), authors[0]
assert_equal author_addresses(:david_address), authors[0].author_address
end
def test_preload_belongs_to_uses_exclusive_scope
- people = Person.males.find(:all, :include => :primary_contact)
+ people = Person.males.scoped(:includes => :primary_contact).all
assert_not_equal people.length, 0
people.each do |person|
assert_no_queries {assert_not_nil person.primary_contact}
@@ -1063,15 +1029,15 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_preload_has_many_uses_exclusive_scope
- people = Person.males.find :all, :include => :agents
+ people = Person.males.includes(:agents).all
people.each do |person|
assert_equal Person.find(person.id).agents, person.agents
end
end
def test_preload_has_many_using_primary_key
- expected = Firm.find(:first).clients_using_primary_key.to_a
- firm = Firm.find :first, :include => :clients_using_primary_key
+ expected = Firm.first.clients_using_primary_key.to_a
+ firm = Firm.includes(:clients_using_primary_key).first
assert_no_queries do
assert_equal expected, firm.clients_using_primary_key
end
@@ -1081,9 +1047,9 @@ class EagerAssociationTest < ActiveRecord::TestCase
expected = Firm.find(1).clients_using_primary_key.sort_by(&:name)
# Oracle adapter truncates alias to 30 characters
if current_adapter?(:OracleAdapter)
- firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies'[0,30]+'.name'
+ firm = Firm.scoped(:includes => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies'[0,30]+'.name').find(1)
else
- firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies.name'
+ firm = Firm.scoped(:includes => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies.name').find(1)
end
assert_no_queries do
assert_equal expected, firm.clients_using_primary_key
@@ -1092,7 +1058,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_preload_has_one_using_primary_key
expected = accounts(:signals37)
- firm = Firm.find :first, :include => :account_using_primary_key, :order => 'companies.id'
+ firm = Firm.scoped(:includes => :account_using_primary_key, :order => 'companies.id').first
assert_no_queries do
assert_equal expected, firm.account_using_primary_key
end
@@ -1100,7 +1066,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_include_has_one_using_primary_key
expected = accounts(:signals37)
- firm = Firm.find(:all, :include => :account_using_primary_key, :order => 'accounts.id').detect {|f| f.id == 1}
+ firm = Firm.scoped(:includes => :account_using_primary_key, :order => 'accounts.id').all.detect {|f| f.id == 1}
assert_no_queries do
assert_equal expected, firm.account_using_primary_key
end
@@ -1164,7 +1130,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_deep_including_through_habtm
- posts = Post.find(:all, :include => {:categories => :categorizations}, :order => "posts.id")
+ posts = Post.scoped(:includes => {:categories => :categorizations}, :order => "posts.id").all
assert_no_queries { assert_equal 2, posts[0].categories[0].categorizations.length }
assert_no_queries { assert_equal 1, posts[0].categories[1].categorizations.length }
assert_no_queries { assert_equal 2, posts[1].categories[0].categorizations.length }
@@ -1174,6 +1140,12 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_equal Comment.find(1), Comment.preload(:post => :comments).scoping { Comment.find(1) }
end
+ test "circular preload does not modify unscoped" do
+ expected = FirstPost.unscoped.find(2)
+ FirstPost.preload(:comments => :first_post).find(1)
+ assert_equal expected, FirstPost.unscoped.find(2)
+ end
+
test "preload ignores the scoping" do
assert_equal(
Comment.find(1).post,
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index f457dfb9b3..22fd80df28 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -355,7 +355,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_deleting_array
david = Developer.find(1)
david.projects.reload
- david.projects.delete(Project.find(:all))
+ david.projects.delete(Project.all)
assert_equal 0, david.projects.size
assert_equal 0, david.projects(true).size
end
@@ -375,7 +375,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
active_record.developers.reload
assert_equal 3, active_record.developers_by_sql.size
- active_record.developers_by_sql.delete(Developer.find(:all))
+ active_record.developers_by_sql.delete(Developer.all)
assert_equal 0, active_record.developers_by_sql(true).size
end
@@ -548,15 +548,15 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_find_with_merged_options
assert_equal 1, projects(:active_record).limited_developers.size
- assert_equal 1, projects(:active_record).limited_developers.find(:all).size
- assert_equal 3, projects(:active_record).limited_developers.find(:all, :limit => nil).size
+ assert_equal 1, projects(:active_record).limited_developers.all.size
+ assert_equal 3, projects(:active_record).limited_developers.limit(nil).all.size
end
def test_dynamic_find_should_respect_association_order
# Developers are ordered 'name DESC, id DESC'
high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
- assert_equal high_id_jamis, projects(:active_record).developers.find(:first, :conditions => "name = 'Jamis'")
+ assert_equal high_id_jamis, projects(:active_record).developers.scoped(:where => "name = 'Jamis'").first
assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis')
end
@@ -566,7 +566,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
middle_id_jamis = developers(:poor_jamis)
high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
- assert_equal [high_id_jamis, middle_id_jamis, low_id_jamis], projects(:active_record).developers.find(:all, :conditions => "name = 'Jamis'")
+ assert_equal [high_id_jamis, middle_id_jamis, low_id_jamis], projects(:active_record).developers.scoped(:where => "name = 'Jamis'").all
assert_equal [high_id_jamis, middle_id_jamis, low_id_jamis], projects(:active_record).developers.find_all_by_name('Jamis')
end
@@ -576,12 +576,12 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
end
def test_dynamic_find_all_should_respect_association_limit
- assert_equal 1, projects(:active_record).limited_developers.find(:all, :conditions => "name = 'Jamis'").length
+ assert_equal 1, projects(:active_record).limited_developers.scoped(:where => "name = 'Jamis'").all.length
assert_equal 1, projects(:active_record).limited_developers.find_all_by_name('Jamis').length
end
def test_dynamic_find_all_order_should_override_association_limit
- assert_equal 2, projects(:active_record).limited_developers.find(:all, :conditions => "name = 'Jamis'", :limit => 9_000).length
+ assert_equal 2, projects(:active_record).limited_developers.scoped(:where => "name = 'Jamis'", :limit => 9_000).all.length
assert_equal 2, projects(:active_record).limited_developers.find_all_by_name('Jamis', :limit => 9_000).length
end
@@ -632,7 +632,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
end
def test_consider_type
- developer = Developer.find(:first)
+ developer = Developer.first
special_project = SpecialProject.create("name" => "Special Project")
other_project = developer.projects.first
@@ -667,7 +667,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
categories(:technology).select_testing_posts(true).each do |o|
assert_respond_to o, :correctness_marker
end
- assert_respond_to categories(:technology).select_testing_posts.find(:first), :correctness_marker
+ assert_respond_to categories(:technology).select_testing_posts.first, :correctness_marker
end
def test_habtm_selects_all_columns_by_default
@@ -681,10 +681,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_join_table_alias
assert_equal(
3,
- Developer.find(
- :all, :include => {:projects => :developers}, :references => :developers_projects_join,
- :conditions => 'developers_projects_join.joined_on IS NOT NULL'
- ).size
+ Developer.references(:developers_projects_join).scoped(
+ :includes => {:projects => :developers},
+ :where => 'developers_projects_join.joined_on IS NOT NULL'
+ ).to_a.size
)
end
@@ -697,16 +697,16 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal(
3,
- Developer.find(
- :all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL',
- :references => :developers_projects_join, :group => group.join(",")
- ).size
+ Developer.references(:developers_projects_join).scoped(
+ :includes => {:projects => :developers}, :where => 'developers_projects_join.joined_on IS NOT NULL',
+ :group => group.join(",")
+ ).to_a.size
)
end
def test_find_grouped
- all_posts_from_category1 = Post.find(:all, :conditions => "category_id = 1", :joins => :categories)
- grouped_posts_of_category1 = Post.find(:all, :conditions => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories)
+ all_posts_from_category1 = Post.scoped(:where => "category_id = 1", :joins => :categories).all
+ grouped_posts_of_category1 = Post.scoped(:where => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories).all
assert_equal 5, all_posts_from_category1.size
assert_equal 2, grouped_posts_of_category1.size
end
@@ -780,8 +780,8 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal 1, project.developers.size
assert_equal 1, developer.projects.size
- assert_equal developer, project.developers.find(:first)
- assert_equal project, developer.projects.find(:first)
+ assert_equal developer, project.developers.first
+ assert_equal project, developer.projects.first
end
def test_self_referential_habtm_without_foreign_key_set_should_raise_exception
@@ -798,13 +798,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog')
end
- def test_counting_on_habtm_association_and_not_array
- david = Developer.find(1)
- # Extra parameter just to make sure we aren't falling back to
- # Array#count in Ruby >=1.8.7, which would raise an ArgumentError
- assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') }
- end
-
def test_count
david = Developer.find(1)
assert_equal 2, david.projects.count
@@ -827,7 +820,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_association_proxy_transaction_method_starts_transaction_in_association_class
Post.expects(:transaction)
- Category.find(:first).posts.transaction do
+ Category.first.posts.transaction do
# nothing
end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 6a4f972356..a98e5b115c 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -242,27 +242,19 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
# sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
def test_counting_with_counter_sql
- assert_equal 2, Firm.find(:first, :order => "id").clients.count
+ assert_equal 2, Firm.scoped(:order => "id").first.clients.count
end
def test_counting
- assert_equal 2, Firm.find(:first, :order => "id").plain_clients.count
- end
-
- def test_counting_with_empty_hash_conditions
- assert_equal 2, Firm.find(:first, :order => "id").plain_clients.count(:conditions => {})
- end
-
- def test_counting_with_single_conditions
- assert_equal 1, Firm.find(:first, :order => "id").plain_clients.count(:conditions => ['name=?', "Microsoft"])
+ assert_equal 2, Firm.scoped(:order => "id").first.plain_clients.count
end
def test_counting_with_single_hash
- assert_equal 1, Firm.find(:first, :order => "id").plain_clients.count(:conditions => {:name => "Microsoft"})
+ assert_equal 1, Firm.scoped(:order => "id").first.plain_clients.where(:name => "Microsoft").count
end
def test_counting_with_column_name_and_hash
- assert_equal 2, Firm.find(:first, :order => "id").plain_clients.count(:name)
+ assert_equal 2, Firm.scoped(:order => "id").first.plain_clients.count(:name)
end
def test_counting_with_association_limit
@@ -272,7 +264,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_finding
- assert_equal 2, Firm.find(:first, :order => "id").clients.length
+ assert_equal 2, Firm.scoped(:order => "id").first.clients.length
end
def test_finding_array_compatibility
@@ -281,14 +273,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_find_with_blank_conditions
[[], {}, nil, ""].each do |blank|
- assert_equal 2, Firm.find(:first, :order => "id").clients.find(:all, :conditions => blank).size
+ assert_equal 2, Firm.scoped(:order => "id").first.clients.where(blank).all.size
end
end
def test_find_many_with_merged_options
assert_equal 1, companies(:first_firm).limited_clients.size
- assert_equal 1, companies(:first_firm).limited_clients.find(:all).size
- assert_equal 2, companies(:first_firm).limited_clients.find(:all, :limit => nil).size
+ assert_equal 1, companies(:first_firm).limited_clients.all.size
+ assert_equal 2, companies(:first_firm).limited_clients.limit(nil).all.size
end
def test_find_should_append_to_association_order
@@ -301,30 +293,25 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_dynamic_find_should_respect_association_order
- assert_equal companies(:second_client), companies(:first_firm).clients_sorted_desc.find(:first, :conditions => "type = 'Client'")
+ assert_equal companies(:second_client), companies(:first_firm).clients_sorted_desc.scoped(:where => "type = 'Client'").first
assert_equal companies(:second_client), companies(:first_firm).clients_sorted_desc.find_by_type('Client')
end
def test_dynamic_find_all_should_respect_association_order
- assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.find(:all, :conditions => "type = 'Client'")
+ assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.scoped(:where => "type = 'Client'").all
assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.find_all_by_type('Client')
end
def test_dynamic_find_all_should_respect_association_limit
- assert_equal 1, companies(:first_firm).limited_clients.find(:all, :conditions => "type = 'Client'").length
+ assert_equal 1, companies(:first_firm).limited_clients.scoped(:where => "type = 'Client'").all.length
assert_equal 1, companies(:first_firm).limited_clients.find_all_by_type('Client').length
end
def test_dynamic_find_all_limit_should_override_association_limit
- assert_equal 2, companies(:first_firm).limited_clients.find(:all, :conditions => "type = 'Client'", :limit => 9_000).length
+ assert_equal 2, companies(:first_firm).limited_clients.scoped(:where => "type = 'Client'", :limit => 9_000).all.length
assert_equal 2, companies(:first_firm).limited_clients.find_all_by_type('Client', :limit => 9_000).length
end
- def test_dynamic_find_all_should_respect_readonly_access
- companies(:first_firm).readonly_clients.find(:all).each { |c| assert_raise(ActiveRecord::ReadOnlyRecord) { c.save! } }
- companies(:first_firm).readonly_clients.find(:all).each { |c| assert c.readonly? }
- end
-
def test_dynamic_find_or_create_from_two_attributes_using_an_association
author = authors(:david)
number_of_posts = Post.count
@@ -341,59 +328,59 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_triple_equality
# sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
- assert !(Array === Firm.find(:first, :order => "id").clients)
- assert Firm.find(:first, :order => "id").clients === Array
+ assert !(Array === Firm.scoped(:order => "id").first.clients)
+ assert Firm.scoped(:order => "id").first.clients === Array
end
def test_finding_default_orders
- assert_equal "Summit", Firm.find(:first, :order => "id").clients.first.name
+ assert_equal "Summit", Firm.scoped(:order => "id").first.clients.first.name
end
def test_finding_with_different_class_name_and_order
- assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_sorted_desc.first.name
+ assert_equal "Microsoft", Firm.scoped(:order => "id").first.clients_sorted_desc.first.name
end
def test_finding_with_foreign_key
- assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_of_firm.first.name
+ assert_equal "Microsoft", Firm.scoped(:order => "id").first.clients_of_firm.first.name
end
def test_finding_with_condition
- assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_like_ms.first.name
+ assert_equal "Microsoft", Firm.scoped(:order => "id").first.clients_like_ms.first.name
end
def test_finding_with_condition_hash
- assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_like_ms_with_hash_conditions.first.name
+ assert_equal "Microsoft", Firm.scoped(:order => "id").first.clients_like_ms_with_hash_conditions.first.name
end
def test_finding_using_primary_key
- assert_equal "Summit", Firm.find(:first, :order => "id").clients_using_primary_key.first.name
+ assert_equal "Summit", Firm.scoped(:order => "id").first.clients_using_primary_key.first.name
end
def test_finding_using_sql
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
first_client = firm.clients_using_sql.first
assert_not_nil first_client
assert_equal "Microsoft", first_client.name
assert_equal 1, firm.clients_using_sql.size
- assert_equal 1, Firm.find(:first, :order => "id").clients_using_sql.size
+ assert_equal 1, Firm.scoped(:order => "id").first.clients_using_sql.size
end
def test_finding_using_sql_take_into_account_only_uniq_ids
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
client = firm.clients_using_sql.first
assert_equal client, firm.clients_using_sql.find(client.id, client.id)
assert_equal client, firm.clients_using_sql.find(client.id, client.id.to_s)
end
def test_counting_using_sql
- assert_equal 1, Firm.find(:first, :order => "id").clients_using_counter_sql.size
- assert Firm.find(:first, :order => "id").clients_using_counter_sql.any?
- assert_equal 0, Firm.find(:first, :order => "id").clients_using_zero_counter_sql.size
- assert !Firm.find(:first, :order => "id").clients_using_zero_counter_sql.any?
+ assert_equal 1, Firm.scoped(:order => "id").first.clients_using_counter_sql.size
+ assert Firm.scoped(:order => "id").first.clients_using_counter_sql.any?
+ assert_equal 0, Firm.scoped(:order => "id").first.clients_using_zero_counter_sql.size
+ assert !Firm.scoped(:order => "id").first.clients_using_zero_counter_sql.any?
end
def test_counting_non_existant_items_using_sql
- assert_equal 0, Firm.find(:first, :order => "id").no_clients_using_counter_sql.size
+ assert_equal 0, Firm.scoped(:order => "id").first.no_clients_using_counter_sql.size
end
def test_counting_using_finder_sql
@@ -408,7 +395,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_find_ids
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find }
@@ -428,7 +415,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_find_string_ids_when_using_finder_sql
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
client = firm.clients_using_finder_sql.find("2")
assert_kind_of Client, client
@@ -444,9 +431,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_find_all
- firm = Firm.find(:first, :order => "id")
- assert_equal 2, firm.clients.find(:all, :conditions => "#{QUOTED_TYPE} = 'Client'").length
- assert_equal 1, firm.clients.find(:all, :conditions => "name = 'Summit'").length
+ firm = Firm.scoped(:order => "id").first
+ assert_equal 2, firm.clients.scoped(:where => "#{QUOTED_TYPE} = 'Client'").all.length
+ assert_equal 1, firm.clients.scoped(:where => "name = 'Summit'").all.length
end
def test_find_each
@@ -465,7 +452,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
firm = companies(:first_firm)
assert_queries(2) do
- firm.clients.find_each(:batch_size => 1, :conditions => {:name => "Microsoft"}) do |c|
+ firm.clients.where(name: 'Microsoft').find_each(batch_size: 1) do |c|
assert_equal firm.id, c.firm_id
assert_equal "Microsoft", c.name
end
@@ -490,29 +477,29 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_find_all_sanitized
# sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
- firm = Firm.find(:first, :order => "id")
- summit = firm.clients.find(:all, :conditions => "name = 'Summit'")
- assert_equal summit, firm.clients.find(:all, :conditions => ["name = ?", "Summit"])
- assert_equal summit, firm.clients.find(:all, :conditions => ["name = :name", { :name => "Summit" }])
+ firm = Firm.scoped(:order => "id").first
+ summit = firm.clients.scoped(:where => "name = 'Summit'").all
+ assert_equal summit, firm.clients.scoped(:where => ["name = ?", "Summit"]).all
+ assert_equal summit, firm.clients.scoped(:where => ["name = :name", { :name => "Summit" }]).all
end
def test_find_first
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
client2 = Client.find(2)
- assert_equal firm.clients.first, firm.clients.find(:first, :order => "id")
- assert_equal client2, firm.clients.find(:first, :conditions => "#{QUOTED_TYPE} = 'Client'", :order => "id")
+ assert_equal firm.clients.first, firm.clients.scoped(:order => "id").first
+ assert_equal client2, firm.clients.scoped(:where => "#{QUOTED_TYPE} = 'Client'", :order => "id").first
end
def test_find_first_sanitized
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
client2 = Client.find(2)
- assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = ?", 'Client'], :order => "id")
- assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }], :order => "id")
+ assert_equal client2, firm.clients.scoped(:where => ["#{QUOTED_TYPE} = ?", 'Client'], :order => "id").first
+ assert_equal client2, firm.clients.scoped(:where => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }], :order => "id").first
end
def test_find_all_with_include_and_conditions
assert_nothing_raised do
- Developer.find(:all, :joins => :audit_logs, :conditions => {'audit_logs.message' => nil, :name => 'Smith'})
+ Developer.scoped(:joins => :audit_logs, :where => {'audit_logs.message' => nil, :name => 'Smith'}).all
end
end
@@ -522,8 +509,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_find_grouped
- all_clients_of_firm1 = Client.find(:all, :conditions => "firm_id = 1")
- grouped_clients_of_firm1 = Client.find(:all, :conditions => "firm_id = 1", :group => "firm_id", :select => 'firm_id, count(id) as clients_count')
+ all_clients_of_firm1 = Client.scoped(:where => "firm_id = 1").all
+ grouped_clients_of_firm1 = Client.scoped(:where => "firm_id = 1", :group => "firm_id", :select => 'firm_id, count(id) as clients_count').all
assert_equal 2, all_clients_of_firm1.size
assert_equal 1, grouped_clients_of_firm1.size
end
@@ -581,7 +568,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_create_with_bang_on_has_many_raises_when_record_not_saved
assert_raise(ActiveRecord::RecordInvalid) do
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
firm.plain_clients.create!
end
end
@@ -813,7 +800,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_deleting_updates_counter_cache
- topic = Topic.first(:order => "id ASC")
+ topic = Topic.order("id ASC").first
assert_equal topic.replies.to_a.size, topic.replies_count
topic.replies.delete(topic.replies.first)
@@ -1008,14 +995,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_delete_all_association_with_primary_key_deletes_correct_records
- firm = Firm.find(:first)
+ firm = Firm.first
# break the vanilla firm_id foreign key
assert_equal 2, firm.clients.count
firm.clients.first.update_column(:firm_id, nil)
assert_equal 1, firm.clients(true).count
assert_equal 1, firm.clients_using_primary_key_with_delete_all.count
old_record = firm.clients_using_primary_key_with_delete_all.first
- firm = Firm.find(:first)
+ firm = Firm.first
firm.destroy
assert_nil Client.find_by_id(old_record.id)
end
@@ -1123,7 +1110,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
firm = companies(:first_firm)
assert_equal 2, firm.clients.size
firm.destroy
- assert Client.find(:all, :conditions => "firm_id=#{firm.id}").empty?
+ assert Client.scoped(:where => "firm_id=#{firm.id}").all.empty?
end
def test_dependence_for_associations_with_hash_condition
@@ -1133,7 +1120,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_destroy_dependent_when_deleted_from_association
# sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
assert_equal 2, firm.clients.size
client = firm.clients.first
@@ -1161,7 +1148,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
firm.destroy rescue "do nothing"
- assert_equal 2, Client.find(:all, :conditions => "firm_id=#{firm.id}").size
+ assert_equal 2, Client.scoped(:where => "firm_id=#{firm.id}").all.size
end
def test_dependence_on_account
@@ -1224,16 +1211,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_adding_array_and_collection
- assert_nothing_raised { Firm.find(:first).clients + Firm.find(:all).last.clients }
- end
-
- def test_find_all_without_conditions
- firm = companies(:first_firm)
- assert_equal 2, firm.clients.find(:all).length
+ assert_nothing_raised { Firm.first.clients + Firm.all.last.clients }
end
def test_replace_with_less
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
firm.clients = [companies(:first_client)]
assert firm.save, "Could not save firm"
firm.reload
@@ -1247,7 +1229,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_replace_with_new
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
firm.clients = [companies(:second_client), Client.new("name" => "New Client")]
firm.save
firm.reload
@@ -1347,27 +1329,27 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_dynamic_find_should_respect_association_order_for_through
- assert_equal Comment.find(10), authors(:david).comments_desc.find(:first, :conditions => "comments.type = 'SpecialComment'")
+ assert_equal Comment.find(10), authors(:david).comments_desc.scoped(:where => "comments.type = 'SpecialComment'").first
assert_equal Comment.find(10), authors(:david).comments_desc.find_by_type('SpecialComment')
end
def test_dynamic_find_all_should_respect_association_order_for_through
- assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.find(:all, :conditions => "comments.type = 'SpecialComment'")
+ assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.scoped(:where => "comments.type = 'SpecialComment'").all
assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.find_all_by_type('SpecialComment')
end
def test_dynamic_find_all_should_respect_association_limit_for_through
- assert_equal 1, authors(:david).limited_comments.find(:all, :conditions => "comments.type = 'SpecialComment'").length
+ assert_equal 1, authors(:david).limited_comments.scoped(:where => "comments.type = 'SpecialComment'").all.length
assert_equal 1, authors(:david).limited_comments.find_all_by_type('SpecialComment').length
end
def test_dynamic_find_all_order_should_override_association_limit_for_through
- assert_equal 4, authors(:david).limited_comments.find(:all, :conditions => "comments.type = 'SpecialComment'", :limit => 9_000).length
+ assert_equal 4, authors(:david).limited_comments.scoped(:where => "comments.type = 'SpecialComment'", :limit => 9_000).all.length
assert_equal 4, authors(:david).limited_comments.find_all_by_type('SpecialComment', :limit => 9_000).length
end
def test_find_all_include_over_the_same_table_for_through
- assert_equal 2, people(:michael).posts.find(:all, :include => :people).length
+ assert_equal 2, people(:michael).posts.scoped(:includes => :people).all.length
end
def test_has_many_through_respects_hash_conditions
@@ -1499,17 +1481,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
end
- def test_calling_first_or_last_with_find_options_on_loaded_association_should_fetch_with_query
- firm = companies(:first_firm)
- firm.clients.class # force load target
-
- assert_queries 2 do
- assert firm.clients.loaded?
- firm.clients.first(:order => 'name')
- firm.clients.last(:order => 'name')
- end
- end
-
def test_calling_first_or_last_with_integer_on_association_should_load_association
firm = companies(:first_firm)
@@ -1567,11 +1538,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
firm = Namespaced::Firm.create({ :name => 'Some Company' })
firm.clients.create({ :name => 'Some Client' })
- stats = Namespaced::Firm.find(firm.id, {
+ stats = Namespaced::Firm.scoped(
:select => "#{Namespaced::Firm.table_name}.id, COUNT(#{Namespaced::Client.table_name}.id) AS num_clients",
:joins => :clients,
:group => "#{Namespaced::Firm.table_name}.id"
- })
+ ).find firm.id
assert_equal 1, stats.num_clients.to_i
ensure
@@ -1580,7 +1551,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_association_proxy_transaction_method_starts_transaction_in_association_class
Comment.expects(:transaction)
- Post.find(:first).comments.transaction do
+ Post.first.comments.transaction do
# nothing
end
end
@@ -1597,7 +1568,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_creating_using_primary_key
- firm = Firm.find(:first, :order => "id")
+ firm = Firm.scoped(:order => "id").first
client = firm.clients_using_primary_key.create!(:name => 'test')
assert_equal firm.name, client.firm_name
end
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index e9b930204f..1c06007d86 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -533,7 +533,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
end
def test_count_with_include_should_alias_join_table
- assert_equal 2, people(:michael).posts.count(:include => :readers)
+ assert_equal 2, people(:michael).posts.includes(:readers).count
end
def test_inner_join_with_quoted_table_name
@@ -568,7 +568,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
def test_association_proxy_transaction_method_starts_transaction_in_association_class
Tag.expects(:transaction)
- Post.find(:first).tags.transaction do
+ Post.first.tags.transaction do
# nothing
end
end
@@ -651,7 +651,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
def test_collection_singular_ids_setter
company = companies(:rails_core)
- dev = Developer.find(:first)
+ dev = Developer.first
company.developer_ids = [dev.id]
assert_equal [dev], company.developers
@@ -671,7 +671,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
def test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set
company = companies(:rails_core)
- ids = [Developer.find(:first).id, -9999]
+ ids = [Developer.first.id, -9999]
assert_raises(ActiveRecord::RecordNotFound) {company.developer_ids= ids}
end
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index 9c05b36426..88ec65706c 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -25,13 +25,13 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_queries(1) { assert_nil firm.account }
assert_queries(0) { assert_nil firm.account }
- firms = Firm.find(:all, :include => :account)
+ firms = Firm.scoped(:includes => :account).all
assert_queries(0) { firms.each(&:account) }
end
def test_with_select
assert_equal Firm.find(1).account_with_select.attributes.size, 2
- assert_equal Firm.find(1, :include => :account_with_select).account_with_select.attributes.size, 2
+ assert_equal Firm.scoped(:includes => :account_with_select).find(1).account_with_select.attributes.size, 2
end
def test_finding_using_primary_key
@@ -294,13 +294,13 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
def test_dependence_with_missing_association_and_nullify
Account.destroy_all
- firm = DependentFirm.find(:first)
+ firm = DependentFirm.first
assert_nil firm.account
firm.destroy
end
def test_finding_with_interpolated_condition
- firm = Firm.find(:first)
+ firm = Firm.first
superior = firm.clients.create(:name => 'SuperiorCo')
superior.rating = 10
superior.save
@@ -346,14 +346,14 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_nothing_raised do
Firm.find(@firm.id).save!
- Firm.find(@firm.id, :include => :account).save!
+ Firm.scoped(:includes => :account).find(@firm.id).save!
end
@firm.account.destroy
assert_nothing_raised do
Firm.find(@firm.id).save!
- Firm.find(@firm.id, :include => :account).save!
+ Firm.scoped(:includes => :account).find(@firm.id).save!
end
end
diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb
index 2503349c08..94b9639e57 100644
--- a/activerecord/test/cases/associations/has_one_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb
@@ -73,7 +73,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
def test_has_one_through_eager_loading
members = assert_queries(3) do #base table, through table, clubs table
- Member.find(:all, :include => :club, :conditions => ["name = ?", "Groucho Marx"])
+ Member.scoped(:includes => :club, :where => ["name = ?", "Groucho Marx"]).all
end
assert_equal 1, members.size
assert_not_nil assert_no_queries {members[0].club}
@@ -81,7 +81,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
def test_has_one_through_eager_loading_through_polymorphic
members = assert_queries(3) do #base table, through table, clubs table
- Member.find(:all, :include => :sponsor_club, :conditions => ["name = ?", "Groucho Marx"])
+ Member.scoped(:includes => :sponsor_club, :where => ["name = ?", "Groucho Marx"]).all
end
assert_equal 1, members.size
assert_not_nil assert_no_queries {members[0].sponsor_club}
@@ -89,14 +89,14 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
def test_has_one_through_with_conditions_eager_loading
# conditions on the through table
- assert_equal clubs(:moustache_club), Member.find(@member.id, :include => :favourite_club).favourite_club
+ assert_equal clubs(:moustache_club), Member.scoped(:includes => :favourite_club).find(@member.id).favourite_club
memberships(:membership_of_favourite_club).update_column(:favourite, false)
- assert_equal nil, Member.find(@member.id, :include => :favourite_club).reload.favourite_club
+ assert_equal nil, Member.scoped(:includes => :favourite_club).find(@member.id).reload.favourite_club
# conditions on the source table
- assert_equal clubs(:moustache_club), Member.find(@member.id, :include => :hairy_club).hairy_club
+ assert_equal clubs(:moustache_club), Member.scoped(:includes => :hairy_club).find(@member.id).hairy_club
clubs(:moustache_club).update_column(:name, "Association of Clean-Shaven Persons")
- assert_equal nil, Member.find(@member.id, :include => :hairy_club).reload.hairy_club
+ assert_equal nil, Member.scoped(:includes => :hairy_club).find(@member.id).reload.hairy_club
end
def test_has_one_through_polymorphic_with_source_type
@@ -104,14 +104,14 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
end
def test_eager_has_one_through_polymorphic_with_source_type
- clubs = Club.find(:all, :include => :sponsored_member, :conditions => ["name = ?","Moustache and Eyebrow Fancier Club"])
+ clubs = Club.scoped(:includes => :sponsored_member, :where => ["name = ?","Moustache and Eyebrow Fancier Club"]).all
# Only the eyebrow fanciers club has a sponsored_member
assert_not_nil assert_no_queries {clubs[0].sponsored_member}
end
def test_has_one_through_nonpreload_eagerloading
members = assert_queries(1) do
- Member.find(:all, :include => :club, :conditions => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name') #force fallback
+ Member.scoped(:includes => :club, :where => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name').all #force fallback
end
assert_equal 1, members.size
assert_not_nil assert_no_queries {members[0].club}
@@ -119,7 +119,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
def test_has_one_through_nonpreload_eager_loading_through_polymorphic
members = assert_queries(1) do
- Member.find(:all, :include => :sponsor_club, :conditions => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name') #force fallback
+ Member.scoped(:includes => :sponsor_club, :where => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name').all #force fallback
end
assert_equal 1, members.size
assert_not_nil assert_no_queries {members[0].sponsor_club}
@@ -128,7 +128,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
def test_has_one_through_nonpreload_eager_loading_through_polymorphic_with_more_than_one_through_record
Sponsor.new(:sponsor_club => clubs(:crazy_club), :sponsorable => members(:groucho)).save!
members = assert_queries(1) do
- Member.find(:all, :include => :sponsor_club, :conditions => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name DESC') #force fallback
+ Member.scoped(:includes => :sponsor_club, :where => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name DESC').all #force fallback
end
assert_equal 1, members.size
assert_not_nil assert_no_queries { members[0].sponsor_club }
@@ -197,7 +197,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
@member.member_detail = @member_detail
@member.organization = @organization
@member_details = assert_queries(3) do
- MemberDetail.find(:all, :include => :member_type)
+ MemberDetail.scoped(:includes => :member_type).all
end
@new_detail = @member_details[0]
assert @new_detail.send(:association, :member_type).loaded?
@@ -210,14 +210,14 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
assert_nothing_raised do
Club.find(@club.id).save!
- Club.find(@club.id, :include => :sponsored_member).save!
+ Club.scoped(:includes => :sponsored_member).find(@club.id).save!
end
@club.sponsor.destroy
assert_nothing_raised do
Club.find(@club.id).save!
- Club.find(@club.id, :include => :sponsored_member).save!
+ Club.scoped(:includes => :sponsored_member).find(@club.id).save!
end
end
diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb
index 68a1e62328..1d61d5c474 100644
--- a/activerecord/test/cases/associations/inner_join_association_test.rb
+++ b/activerecord/test/cases/associations/inner_join_association_test.rb
@@ -72,17 +72,17 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase
def test_count_honors_implicit_inner_joins
real_count = Author.scoped.to_a.sum{|a| a.posts.count }
- assert_equal real_count, Author.count(:joins => :posts), "plain inner join count should match the number of referenced posts records"
+ assert_equal real_count, Author.joins(:posts).count, "plain inner join count should match the number of referenced posts records"
end
def test_calculate_honors_implicit_inner_joins
real_count = Author.scoped.to_a.sum{|a| a.posts.count }
- assert_equal real_count, Author.calculate(:count, 'authors.id', :joins => :posts), "plain inner join count should match the number of referenced posts records"
+ assert_equal real_count, Author.joins(:posts).calculate(:count, 'authors.id'), "plain inner join count should match the number of referenced posts records"
end
def test_calculate_honors_implicit_inner_joins_and_distinct_and_conditions
real_count = Author.scoped.to_a.select {|a| a.posts.any? {|p| p.title =~ /^Welcome/} }.length
- authors_with_welcoming_post_titles = Author.calculate(:count, 'authors.id', :joins => :posts, :distinct => true, :conditions => "posts.title like 'Welcome%'")
+ authors_with_welcoming_post_titles = Author.scoped(:joins => :posts, :where => "posts.title like 'Welcome%'").calculate(:count, 'authors.id', :distinct => true)
assert_equal real_count, authors_with_welcoming_post_titles, "inner join and conditions should have only returned authors posting titles starting with 'Welcome'"
end
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index 76282213d8..f35ffb2994 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -96,7 +96,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
def test_parent_instance_should_be_shared_with_eager_loaded_child_on_find
- m = Man.find(:first, :conditions => {:name => 'Gordon'}, :include => :face)
+ m = Man.scoped(:where => {:name => 'Gordon'}, :includes => :face).first
f = m.face
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
m.name = 'Bongo'
@@ -104,7 +104,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
f.man.name = 'Mungo'
assert_equal m.name, f.man.name, "Name of man should be the same after changes to child-owned instance"
- m = Man.find(:first, :conditions => {:name => 'Gordon'}, :include => :face, :order => 'faces.id')
+ m = Man.scoped(:where => {:name => 'Gordon'}, :includes => :face, :order => 'faces.id').first
f = m.face
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
m.name = 'Bongo'
@@ -114,7 +114,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_newly_built_child
- m = Man.find(:first)
+ m = Man.first
f = m.build_face(:description => 'haunted')
assert_not_nil f.man
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
@@ -125,7 +125,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_newly_created_child
- m = Man.find(:first)
+ m = Man.first
f = m.create_face(:description => 'haunted')
assert_not_nil f.man
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
@@ -136,7 +136,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_newly_created_child_via_bang_method
- m = Man.find(:first)
+ m = Man.first
f = m.create_face!(:description => 'haunted')
assert_not_nil f.man
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
@@ -147,7 +147,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_replaced_via_accessor_child
- m = Man.find(:first)
+ m = Man.first
f = Face.new(:description => 'haunted')
m.face = f
assert_not_nil f.man
@@ -159,7 +159,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
end
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
- assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Man.find(:first).dirty_face }
+ assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Man.first.dirty_face }
end
end
@@ -179,7 +179,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_eager_loaded_children
- m = Man.find(:first, :conditions => {:name => 'Gordon'}, :include => :interests)
+ m = Man.scoped(:where => {:name => 'Gordon'}, :includes => :interests).first
is = m.interests
is.each do |i|
assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
@@ -189,7 +189,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert_equal m.name, i.man.name, "Name of man should be the same after changes to child-owned instance"
end
- m = Man.find(:first, :conditions => {:name => 'Gordon'}, :include => :interests, :order => 'interests.id')
+ m = Man.scoped(:where => {:name => 'Gordon'}, :includes => :interests, :order => 'interests.id').first
is = m.interests
is.each do |i|
assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
@@ -201,7 +201,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_newly_block_style_built_child
- m = Man.find(:first)
+ m = Man.first
i = m.interests.build {|ii| ii.topic = 'Industrial Revolution Re-enactment'}
assert_not_nil i.topic, "Child attributes supplied to build via blocks should be populated"
assert_not_nil i.man
@@ -213,7 +213,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_newly_created_via_bang_method_child
- m = Man.find(:first)
+ m = Man.first
i = m.interests.create!(:topic => 'Industrial Revolution Re-enactment')
assert_not_nil i.man
assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
@@ -224,7 +224,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_newly_block_style_created_child
- m = Man.find(:first)
+ m = Man.first
i = m.interests.create {|ii| ii.topic = 'Industrial Revolution Re-enactment'}
assert_not_nil i.topic, "Child attributes supplied to create via blocks should be populated"
assert_not_nil i.man
@@ -248,7 +248,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_replaced_via_accessor_children
- m = Man.find(:first)
+ m = Man.first
i = Interest.new(:topic => 'Industrial Revolution Re-enactment')
m.interests = [i]
assert_not_nil i.man
@@ -260,7 +260,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
end
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
- assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Man.find(:first).secret_interests }
+ assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Man.first.secret_interests }
end
end
@@ -278,7 +278,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
end
def test_eager_loaded_child_instance_should_be_shared_with_parent_on_find
- f = Face.find(:first, :include => :man, :conditions => {:description => 'trusting'})
+ f = Face.scoped(:includes => :man, :where => {:description => 'trusting'}).first
m = f.man
assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance"
f.description = 'gormless'
@@ -286,7 +286,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
m.face.description = 'pleasing'
assert_equal f.description, m.face.description, "Description of face should be the same after changes to parent-owned instance"
- f = Face.find(:first, :include => :man, :order => 'men.id', :conditions => {:description => 'trusting'})
+ f = Face.scoped(:includes => :man, :order => 'men.id', :where => {:description => 'trusting'}).first
m = f.man
assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance"
f.description = 'gormless'
@@ -331,7 +331,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
end
def test_child_instance_should_be_shared_with_replaced_via_accessor_parent
- f = Face.find(:first)
+ f = Face.first
m = Man.new(:name => 'Charles')
f.man = m
assert_not_nil m.face
@@ -343,7 +343,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
end
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
- assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).horrible_man }
+ assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.first.horrible_man }
end
end
@@ -351,7 +351,7 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase
fixtures :men, :faces, :interests
def test_child_instance_should_be_shared_with_parent_on_find
- f = Face.find(:first, :conditions => {:description => 'confused'})
+ f = Face.scoped(:where => {:description => 'confused'}).first
m = f.polymorphic_man
assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance"
f.description = 'gormless'
@@ -361,7 +361,7 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase
end
def test_eager_loaded_child_instance_should_be_shared_with_parent_on_find
- f = Face.find(:first, :conditions => {:description => 'confused'}, :include => :man)
+ f = Face.scoped(:where => {:description => 'confused'}, :includes => :man).first
m = f.polymorphic_man
assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance"
f.description = 'gormless'
@@ -369,7 +369,7 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase
m.polymorphic_face.description = 'pleasing'
assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to parent-owned instance"
- f = Face.find(:first, :conditions => {:description => 'confused'}, :include => :man, :order => 'men.id')
+ f = Face.scoped(:where => {:description => 'confused'}, :includes => :man, :order => 'men.id').first
m = f.polymorphic_man
assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance"
f.description = 'gormless'
@@ -421,19 +421,19 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase
def test_trying_to_access_inverses_that_dont_exist_shouldnt_raise_an_error
# Ideally this would, if only for symmetry's sake with other association types
- assert_nothing_raised(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).horrible_polymorphic_man }
+ assert_nothing_raised(ActiveRecord::InverseOfAssociationNotFoundError) { Face.first.horrible_polymorphic_man }
end
def test_trying_to_set_polymorphic_inverses_that_dont_exist_at_all_should_raise_an_error
# fails because no class has the correct inverse_of for horrible_polymorphic_man
- assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).horrible_polymorphic_man = Man.first }
+ assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.first.horrible_polymorphic_man = Man.first }
end
def test_trying_to_set_polymorphic_inverses_that_dont_exist_on_the_instance_being_set_should_raise_an_error
# passes because Man does have the correct inverse_of
- assert_nothing_raised(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).polymorphic_man = Man.first }
+ assert_nothing_raised(ActiveRecord::InverseOfAssociationNotFoundError) { Face.first.polymorphic_man = Man.first }
# fails because Interest does have the correct inverse_of
- assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).polymorphic_man = Interest.first }
+ assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.first.polymorphic_man = Interest.first }
end
end
@@ -444,7 +444,7 @@ class InverseMultipleHasManyInversesForSameModel < ActiveRecord::TestCase
def test_that_we_can_load_associations_that_have_the_same_reciprocal_name_from_different_models
assert_nothing_raised(ActiveRecord::AssociationTypeMismatch) do
- i = Interest.find(:first)
+ i = Interest.first
i.zine
i.man
end
@@ -452,7 +452,7 @@ class InverseMultipleHasManyInversesForSameModel < ActiveRecord::TestCase
def test_that_we_can_create_associations_that_have_the_same_reciprocal_name_from_different_models
assert_nothing_raised(ActiveRecord::AssociationTypeMismatch) do
- i = Interest.find(:first)
+ i = Interest.first
i.build_zine(:title => 'Get Some in Winter! 2008')
i.build_man(:name => 'Gordon')
i.save!
diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb
index 301755249c..3606ce691c 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -46,12 +46,12 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
assert !authors(:mary).unique_categorized_posts.loaded?
assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count }
assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title) }
- assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, :conditions => "title is NULL") }
+ assert_queries(1) { assert_equal 0, author.unique_categorized_posts.where(title: nil).count(:title) }
assert !authors(:mary).unique_categorized_posts.loaded?
end
def test_has_many_uniq_through_find
- assert_equal 1, authors(:mary).unique_categorized_posts.find(:all).size
+ assert_equal 1, authors(:mary).unique_categorized_posts.all.size
end
def test_has_many_uniq_through_dynamic_find
@@ -71,7 +71,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_polymorphic_has_many_going_through_join_model_with_find
- assert_equal tags(:general), tag = posts(:welcome).tags.find(:first)
+ assert_equal tags(:general), tag = posts(:welcome).tags.first
assert_no_queries do
tag.tagging
end
@@ -85,7 +85,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection_with_find
- assert_equal tags(:general), tag = posts(:welcome).funky_tags.find(:first)
+ assert_equal tags(:general), tag = posts(:welcome).funky_tags.first
assert_no_queries do
tag.tagging
end
@@ -237,8 +237,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_include_has_many_through
- posts = Post.find(:all, :order => 'posts.id')
- posts_with_authors = Post.find(:all, :include => :authors, :order => 'posts.id')
+ posts = Post.scoped(:order => 'posts.id').all
+ posts_with_authors = Post.scoped(:includes => :authors, :order => 'posts.id').all
assert_equal posts.length, posts_with_authors.length
posts.length.times do |i|
assert_equal posts[i].authors.length, assert_no_queries { posts_with_authors[i].authors.length }
@@ -246,7 +246,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_include_polymorphic_has_one
- post = Post.find_by_id(posts(:welcome).id, :include => :tagging)
+ post = Post.includes(:tagging).find posts(:welcome).id
tagging = taggings(:welcome_general)
assert_no_queries do
assert_equal tagging, post.tagging
@@ -254,7 +254,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_include_polymorphic_has_one_defined_in_abstract_parent
- item = Item.find_by_id(items(:dvd).id, :include => :tagging)
+ item = Item.includes(:tagging).find items(:dvd).id
tagging = taggings(:godfather)
assert_no_queries do
assert_equal tagging, item.tagging
@@ -262,8 +262,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_include_polymorphic_has_many_through
- posts = Post.find(:all, :order => 'posts.id')
- posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
+ posts = Post.scoped(:order => 'posts.id').all
+ posts_with_tags = Post.scoped(:includes => :tags, :order => 'posts.id').all
assert_equal posts.length, posts_with_tags.length
posts.length.times do |i|
assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
@@ -271,8 +271,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_include_polymorphic_has_many
- posts = Post.find(:all, :order => 'posts.id')
- posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
+ posts = Post.scoped(:order => 'posts.id').all
+ posts_with_taggings = Post.scoped(:includes => :taggings, :order => 'posts.id').all
assert_equal posts.length, posts_with_taggings.length
posts.length.times do |i|
assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
@@ -280,20 +280,20 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_has_many_find_all
- assert_equal [categories(:general)], authors(:david).categories.find(:all)
+ assert_equal [categories(:general)], authors(:david).categories.all
end
def test_has_many_find_first
- assert_equal categories(:general), authors(:david).categories.find(:first)
+ assert_equal categories(:general), authors(:david).categories.first
end
def test_has_many_with_hash_conditions
- assert_equal categories(:general), authors(:david).categories_like_general.find(:first)
+ assert_equal categories(:general), authors(:david).categories_like_general.first
end
def test_has_many_find_conditions
- assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
- assert_nil authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
+ assert_equal categories(:general), authors(:david).categories.scoped(:where => "categories.name = 'General'").first
+ assert_nil authors(:david).categories.scoped(:where => "categories.name = 'Technology'").first
end
def test_has_many_class_methods_called_by_method_missing
@@ -327,14 +327,6 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
assert_equal [authors(:david), authors(:bob)], posts(:thinking).authors_using_custom_pk.order('authors.id')
end
- def test_both_scoped_and_explicit_joins_should_be_respected
- assert_nothing_raised do
- Post.send(:with_scope, :find => {:joins => "left outer join comments on comments.id = posts.id"}) do
- Post.find :all, :select => "comments.id, authors.id", :joins => "left outer join authors on authors.id = posts.author_id"
- end
- end
- end
-
def test_belongs_to_polymorphic_with_counter_cache
assert_equal 1, posts(:welcome)[:taggings_count]
tagging = posts(:welcome).taggings.create(:tag => tags(:general))
@@ -362,7 +354,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
assert_raise ActiveRecord::EagerLoadPolymorphicError do
- tags(:general).taggings.find(:all, :include => :taggable, :references => :bogus_table, :conditions => 'bogus_table.column = 1')
+ tags(:general).taggings.includes(:taggable).where('bogus_table.column = 1').references(:bogus_table).to_a
end
end
@@ -372,7 +364,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_eager_has_many_polymorphic_with_source_type
- tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
+ tag_with_include = Tag.scoped(:includes => :tagged_posts).find(tags(:general).id)
desired = posts(:welcome, :thinking)
assert_no_queries do
# added sort by ID as otherwise test using JRuby was failing as array elements were in different order
@@ -382,20 +374,20 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_has_many_through_has_many_find_all
- assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
+ assert_equal comments(:greetings), authors(:david).comments.scoped(:order => 'comments.id').all.first
end
def test_has_many_through_has_many_find_all_with_custom_class
- assert_equal comments(:greetings), authors(:david).funky_comments.find(:all, :order => 'comments.id').first
+ assert_equal comments(:greetings), authors(:david).funky_comments.scoped(:order => 'comments.id').all.first
end
def test_has_many_through_has_many_find_first
- assert_equal comments(:greetings), authors(:david).comments.find(:first, :order => 'comments.id')
+ assert_equal comments(:greetings), authors(:david).comments.scoped(:order => 'comments.id').first
end
def test_has_many_through_has_many_find_conditions
- options = { :conditions => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
- assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, options)
+ options = { :where => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
+ assert_equal comments(:does_it_hurt), authors(:david).comments.scoped(options).first
end
def test_has_many_through_has_many_find_by_id
@@ -411,7 +403,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_include_has_many_through_polymorphic_has_many
- author = Author.find_by_id(authors(:david).id, :include => :taggings)
+ author = Author.includes(:taggings).find authors(:david).id
expected_taggings = taggings(:welcome_general, :thinking_general)
assert_no_queries do
assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
@@ -419,7 +411,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_eager_load_has_many_through_has_many
- author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id'
+ author = Author.scoped(:where => ['name = ?', 'David'], :includes => :comments, :order => 'comments.id').first
SpecialComment.new; VerySpecialComment.new
assert_no_queries do
assert_equal [1,2,3,5,6,7,8,9,10,12], author.comments.collect(&:id)
@@ -427,7 +419,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_eager_load_has_many_through_has_many_with_conditions
- post = Post.find(:first, :include => :invalid_tags)
+ post = Post.scoped(:includes => :invalid_tags).first
assert_no_queries do
post.invalid_tags
end
@@ -435,8 +427,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
def test_eager_belongs_to_and_has_one_not_singularized
assert_nothing_raised do
- Author.find(:first, :include => :author_address)
- AuthorAddress.find(:first, :include => :author)
+ Author.scoped(:includes => :author_address).first
+ AuthorAddress.scoped(:includes => :author).first
end
end
@@ -452,7 +444,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_has_many_through_uses_conditions_specified_on_the_has_many_association
- author = Author.find(:first)
+ author = Author.first
assert_present author.comments
assert_blank author.nonexistant_comments
end
@@ -622,7 +614,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
def test_polymorphic_has_many
expected = taggings(:welcome_general)
- p = Post.find(posts(:welcome).id, :include => :taggings)
+ p = Post.scoped(:includes => :taggings).find(posts(:welcome).id)
assert_no_queries {assert p.taggings.include?(expected)}
assert posts(:welcome).taggings.include?(taggings(:welcome_general))
end
@@ -630,18 +622,18 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
def test_polymorphic_has_one
expected = posts(:welcome)
- tagging = Tagging.find(taggings(:welcome_general).id, :include => :taggable)
+ tagging = Tagging.scoped(:includes => :taggable).find(taggings(:welcome_general).id)
assert_no_queries { assert_equal expected, tagging.taggable}
end
def test_polymorphic_belongs_to
- p = Post.find(posts(:welcome).id, :include => {:taggings => :taggable})
+ p = Post.scoped(:includes => {:taggings => :taggable}).find(posts(:welcome).id)
assert_no_queries {assert_equal posts(:welcome), p.taggings.first.taggable}
end
def test_preload_polymorphic_has_many_through
- posts = Post.find(:all, :order => 'posts.id')
- posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
+ posts = Post.scoped(:order => 'posts.id').all
+ posts_with_tags = Post.scoped(:includes => :tags, :order => 'posts.id').all
assert_equal posts.length, posts_with_tags.length
posts.length.times do |i|
assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
@@ -649,7 +641,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_preload_polymorph_many_types
- taggings = Tagging.find :all, :include => :taggable, :conditions => ['taggable_type != ?', 'FakeModel']
+ taggings = Tagging.scoped(:includes => :taggable, :where => ['taggable_type != ?', 'FakeModel']).all
assert_no_queries do
taggings.first.taggable.id
taggings[1].taggable.id
@@ -662,13 +654,13 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
def test_preload_nil_polymorphic_belongs_to
assert_nothing_raised do
- Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL'])
+ Tagging.scoped(:includes => :taggable, :where => ['taggable_type IS NULL']).all
end
end
def test_preload_polymorphic_has_many
- posts = Post.find(:all, :order => 'posts.id')
- posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
+ posts = Post.scoped(:order => 'posts.id').all
+ posts_with_taggings = Post.scoped(:includes => :taggings, :order => 'posts.id').all
assert_equal posts.length, posts_with_taggings.length
posts.length.times do |i|
assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
@@ -676,7 +668,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_belongs_to_shared_parent
- comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 1')
+ comments = Comment.scoped(:includes => :post, :where => 'post_id = 1').all
assert_no_queries do
assert_equal comments.first.post, comments[1].post
end
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index 017905e0ac..1d0550afaf 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -74,8 +74,8 @@ class AssociationsTest < ActiveRecord::TestCase
def test_include_with_order_works
- assert_nothing_raised {Account.find(:first, :order => 'id', :include => :firm)}
- assert_nothing_raised {Account.find(:first, :order => :id, :include => :firm)}
+ assert_nothing_raised {Account.scoped(:order => 'id', :includes => :firm).first}
+ assert_nothing_raised {Account.scoped(:order => :id, :includes => :firm).first}
end
def test_bad_collection_keys
@@ -214,6 +214,10 @@ class AssociationProxyTest < ActiveRecord::TestCase
david = developers(:david)
assert_equal david.association(:projects), david.projects.proxy_association
end
+
+ def test_scoped_allows_conditions
+ assert developers(:david).projects.scoped(where: 'foo').where_values.include?('foo')
+ end
end
class OverridingAssociationsTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index ef01476ae4..ab44dc8811 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -244,7 +244,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
# DB2 is not case-sensitive
return true if current_adapter?(:DB2Adapter)
- assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.find(:first).attributes
+ assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.first.attributes
end
def test_hashes_not_mangled
@@ -484,9 +484,9 @@ class AttributeMethodsTest < ActiveRecord::TestCase
topic = Topic.create(:title => 'Budget')
# Oracle does not support boolean expressions in SELECT
if current_adapter?(:OracleAdapter)
- topic = Topic.find(:first, :select => "topics.*, 0 as is_test")
+ topic = Topic.scoped(:select => "topics.*, 0 as is_test").first
else
- topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test")
+ topic = Topic.scoped(:select => "topics.*, 1=2 as is_test").first
end
assert !topic.is_test?
end
@@ -495,9 +495,9 @@ class AttributeMethodsTest < ActiveRecord::TestCase
topic = Topic.create(:title => 'Budget')
# Oracle does not support boolean expressions in SELECT
if current_adapter?(:OracleAdapter)
- topic = Topic.find(:first, :select => "topics.*, 1 as is_test")
+ topic = Topic.scoped(:select => "topics.*, 1 as is_test").first
else
- topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test")
+ topic = Topic.scoped(:select => "topics.*, 2=2 as is_test").first
end
assert topic.is_test?
end
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index d15487ab11..c93c91803e 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -87,7 +87,7 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas
end
def test_save_fails_for_invalid_has_one
- firm = Firm.find(:first)
+ firm = Firm.first
assert firm.valid?
firm.build_account
@@ -99,7 +99,7 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas
end
def test_save_succeeds_for_invalid_has_one_with_validate_false
- firm = Firm.find(:first)
+ firm = Firm.first
assert firm.valid?
firm.build_unvalidated_account
@@ -155,20 +155,20 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas
end
def test_not_resaved_when_unchanged
- firm = Firm.find(:first, :include => :account)
+ firm = Firm.scoped(:includes => :account).first
firm.name += '-changed'
assert_queries(1) { firm.save! }
- firm = Firm.find(:first)
- firm.account = Account.find(:first)
+ firm = Firm.first
+ firm.account = Account.first
assert_queries(Firm.partial_updates? ? 0 : 1) { firm.save! }
- firm = Firm.find(:first).dup
- firm.account = Account.find(:first)
+ firm = Firm.first.dup
+ firm.account = Account.first
assert_queries(2) { firm.save! }
- firm = Firm.find(:first).dup
- firm.account = Account.find(:first).dup
+ firm = Firm.first.dup
+ firm.account = Account.first.dup
assert_queries(2) { firm.save! }
end
@@ -228,7 +228,7 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test
end
def test_assignment_before_parent_saved
- client = Client.find(:first)
+ client = Client.first
apple = Firm.new("name" => "Apple")
client.firm = apple
assert_equal apple, client.firm
@@ -342,7 +342,7 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test
end
def test_build_and_then_save_parent_should_not_reload_target
- client = Client.find(:first)
+ client = Client.first
apple = client.build_firm(:name => "Apple")
client.save!
assert_no_queries { assert_equal apple, client.firm }
@@ -384,7 +384,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa
end
def test_invalid_adding_with_validate_false
- firm = Firm.find(:first)
+ firm = Firm.first
client = Client.new
firm.unvalidated_clients_of_firm << client
@@ -397,7 +397,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa
def test_valid_adding_with_validate_false
no_of_clients = Client.count
- firm = Firm.find(:first)
+ firm = Firm.first
client = Client.new("name" => "Apple")
assert firm.valid?
@@ -627,7 +627,9 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
def test_a_child_marked_for_destruction_should_not_be_destroyed_twice
@pirate.ship.mark_for_destruction
assert @pirate.save
- @pirate.ship.expects(:destroy).never
+ class << @pirate.ship
+ def destroy; raise "Should not be called" end
+ end
assert @pirate.save
end
@@ -672,7 +674,9 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
def test_a_parent_marked_for_destruction_should_not_be_destroyed_twice
@ship.pirate.mark_for_destruction
assert @ship.save
- @ship.pirate.expects(:destroy).never
+ class << @ship.pirate
+ def destroy; raise "Should not be called" end
+ end
assert @ship.save
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 5fb49d540f..5887782cad 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -192,7 +192,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_previously_changed
- topic = Topic.find :first
+ topic = Topic.first
topic.title = '<3<3<3'
assert_equal({}, topic.previous_changes)
@@ -202,7 +202,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_previously_changed_dup
- topic = Topic.find :first
+ topic = Topic.first
topic.title = '<3<3<3'
topic.save!
@@ -228,7 +228,7 @@ class BasicsTest < ActiveRecord::TestCase
)
# For adapters which support microsecond resolution.
- if current_adapter?(:PostgreSQLAdapter) || current_adapter?(:SQLiteAdapter)
+ if current_adapter?(:PostgreSQLAdapter) || current_adapter?(:SQLite3Adapter)
assert_equal 11, Topic.find(1).written_on.sec
assert_equal 223300, Topic.find(1).written_on.usec
assert_equal 9900, Topic.find(2).written_on.usec
@@ -350,13 +350,13 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_load
- topics = Topic.find(:all, :order => 'id')
+ topics = Topic.scoped(:order => 'id').all
assert_equal(4, topics.size)
assert_equal(topics(:first).title, topics.first.title)
end
def test_load_with_condition
- topics = Topic.find(:all, :conditions => "author_name = 'Mary'")
+ topics = Topic.scoped(:where => "author_name = 'Mary'").all
assert_equal(1, topics.size)
assert_equal(topics(:second).title, topics.first.title)
@@ -1264,10 +1264,10 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_quoting_arrays
- replies = Reply.find(:all, :conditions => [ "id IN (?)", topics(:first).replies.collect(&:id) ])
+ replies = Reply.scoped(:where => [ "id IN (?)", topics(:first).replies.collect(&:id) ]).all
assert_equal topics(:first).replies.size, replies.size
- replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
+ replies = Reply.scoped(:where => [ "id IN (?)", [] ]).all
assert_equal 0, replies.size
end
@@ -1503,7 +1503,11 @@ class BasicsTest < ActiveRecord::TestCase
after_seq = Joke.sequence_name
assert_not_equal before_columns, after_columns
- assert_not_equal before_seq, after_seq unless before_seq.blank? && after_seq.blank?
+ unless before_seq.nil? && after_seq.nil?
+ assert_not_equal before_seq, after_seq
+ assert_equal "cold_jokes_id_seq", before_seq
+ assert_equal "funny_jokes_id_seq", after_seq
+ end
end
def test_dont_clear_sequence_name_when_setting_explicitly
@@ -1514,7 +1518,7 @@ class BasicsTest < ActiveRecord::TestCase
Joke.table_name = "funny_jokes"
after_seq = Joke.sequence_name
- assert_equal before_seq, after_seq unless before_seq.blank? && after_seq.blank?
+ assert_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
end
def test_dont_clear_inheritnce_column_when_setting_explicitly
@@ -1564,22 +1568,19 @@ class BasicsTest < ActiveRecord::TestCase
def test_count_with_join
res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
- res2 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'", :joins => "LEFT JOIN comments ON posts.id=comments.post_id")
+ res2 = Post.where("posts.#{QUOTED_TYPE} = 'Post'").joins("LEFT JOIN comments ON posts.id=comments.post_id").count
assert_equal res, res2
res3 = nil
assert_nothing_raised do
- res3 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'",
- :joins => "LEFT JOIN comments ON posts.id=comments.post_id")
+ res3 = Post.where("posts.#{QUOTED_TYPE} = 'Post'").joins("LEFT JOIN comments ON posts.id=comments.post_id").count
end
assert_equal res, res3
res4 = Post.count_by_sql "SELECT COUNT(p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
res5 = nil
assert_nothing_raised do
- res5 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
- :joins => "p, comments co",
- :select => "p.id")
+ res5 = Post.where("p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id").joins("p, comments co").select("p.id").count
end
assert_equal res4, res5
@@ -1587,145 +1588,64 @@ class BasicsTest < ActiveRecord::TestCase
res6 = Post.count_by_sql "SELECT COUNT(DISTINCT p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
res7 = nil
assert_nothing_raised do
- res7 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
- :joins => "p, comments co",
- :select => "p.id",
- :distinct => true)
+ res7 = Post.where("p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id").joins("p, comments co").select("p.id").count(distinct: true)
end
assert_equal res6, res7
end
- def test_scoped_find_conditions
- scoped_developers = Developer.send(:with_scope, :find => { :conditions => 'salary > 90000' }) do
- Developer.find(:all, :conditions => 'id < 5')
- end
- assert !scoped_developers.include?(developers(:david)) # David's salary is less than 90,000
- assert_equal 3, scoped_developers.size
- end
-
def test_no_limit_offset
assert_nothing_raised do
- Developer.find(:all, :offset => 2)
- end
- end
-
- def test_scoped_find_limit_offset
- scoped_developers = Developer.send(:with_scope, :find => { :limit => 3, :offset => 2 }) do
- Developer.find(:all, :order => 'id')
- end
- assert !scoped_developers.include?(developers(:david))
- assert !scoped_developers.include?(developers(:jamis))
- assert_equal 3, scoped_developers.size
-
- # Test without scoped find conditions to ensure we get the whole thing
- developers = Developer.find(:all, :order => 'id')
- assert_equal Developer.count, developers.size
- end
-
- def test_scoped_find_order
- # Test order in scope
- scoped_developers = Developer.send(:with_scope, :find => { :limit => 1, :order => 'salary DESC' }) do
- Developer.find(:all)
- end
- assert_equal 'Jamis', scoped_developers.first.name
- assert scoped_developers.include?(developers(:jamis))
- # Test scope without order and order in find
- scoped_developers = Developer.send(:with_scope, :find => { :limit => 1 }) do
- Developer.find(:all, :order => 'salary DESC')
- end
- # Test scope order + find order, order has priority
- scoped_developers = Developer.send(:with_scope, :find => { :limit => 3, :order => 'id DESC' }) do
- Developer.find(:all, :order => 'salary ASC')
- end
- assert scoped_developers.include?(developers(:poor_jamis))
- assert ! scoped_developers.include?(developers(:david))
- assert ! scoped_developers.include?(developers(:jamis))
- assert_equal 3, scoped_developers.size
-
- # Test without scoped find conditions to ensure we get the right thing
- assert ! scoped_developers.include?(Developer.find(1))
- assert scoped_developers.include?(Developer.find(11))
- end
-
- def test_scoped_find_limit_offset_including_has_many_association
- topics = Topic.send(:with_scope, :find => {:limit => 1, :offset => 1, :include => :replies}) do
- Topic.find(:all, :order => "topics.id")
- end
- assert_equal 1, topics.size
- assert_equal 2, topics.first.id
- end
-
- def test_scoped_find_order_including_has_many_association
- developers = Developer.send(:with_scope, :find => { :order => 'developers.salary DESC', :include => :projects }) do
- Developer.find(:all)
- end
- assert developers.size >= 2
- (1...developers.size).each do |i|
- assert developers[i-1].salary >= developers[i].salary
- end
- end
-
- def test_scoped_find_with_group_and_having
- developers = Developer.send(:with_scope, :find => { :group => 'developers.salary', :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" }) do
- Developer.find(:all)
+ Developer.scoped(:offset => 2).all
end
- assert_equal 3, developers.size
end
def test_find_last
- last = Developer.find :last
- assert_equal last, Developer.find(:first, :order => 'id desc')
+ last = Developer.last
+ assert_equal last, Developer.scoped(:order => 'id desc').first
end
def test_last
- assert_equal Developer.find(:first, :order => 'id desc'), Developer.last
+ assert_equal Developer.scoped(:order => 'id desc').first, Developer.last
end
def test_all
developers = Developer.all
assert_kind_of Array, developers
- assert_equal Developer.find(:all), developers
+ assert_equal Developer.all, developers
end
def test_all_with_conditions
- assert_equal Developer.find(:all, :order => 'id desc'), Developer.order('id desc').all
+ assert_equal Developer.scoped(:order => 'id desc').all, Developer.order('id desc').all
end
def test_find_ordered_last
- last = Developer.find :last, :order => 'developers.salary ASC'
- assert_equal last, Developer.find(:all, :order => 'developers.salary ASC').last
+ last = Developer.scoped(:order => 'developers.salary ASC').last
+ assert_equal last, Developer.scoped(:order => 'developers.salary ASC').all.last
end
def test_find_reverse_ordered_last
- last = Developer.find :last, :order => 'developers.salary DESC'
- assert_equal last, Developer.find(:all, :order => 'developers.salary DESC').last
+ last = Developer.scoped(:order => 'developers.salary DESC').last
+ assert_equal last, Developer.scoped(:order => 'developers.salary DESC').all.last
end
def test_find_multiple_ordered_last
- last = Developer.find :last, :order => 'developers.name, developers.salary DESC'
- assert_equal last, Developer.find(:all, :order => 'developers.name, developers.salary DESC').last
+ last = Developer.scoped(:order => 'developers.name, developers.salary DESC').last
+ assert_equal last, Developer.scoped(:order => 'developers.name, developers.salary DESC').all.last
end
def test_find_keeps_multiple_order_values
- combined = Developer.find(:all, :order => 'developers.name, developers.salary')
- assert_equal combined, Developer.find(:all, :order => ['developers.name', 'developers.salary'])
+ combined = Developer.scoped(:order => 'developers.name, developers.salary').all
+ assert_equal combined, Developer.scoped(:order => ['developers.name', 'developers.salary']).all
end
def test_find_keeps_multiple_group_values
- combined = Developer.find(:all, :group => 'developers.name, developers.salary, developers.id, developers.created_at, developers.updated_at')
- assert_equal combined, Developer.find(:all, :group => ['developers.name', 'developers.salary', 'developers.id', 'developers.created_at', 'developers.updated_at'])
+ combined = Developer.scoped(:group => 'developers.name, developers.salary, developers.id, developers.created_at, developers.updated_at').all
+ assert_equal combined, Developer.scoped(:group => ['developers.name', 'developers.salary', 'developers.id', 'developers.created_at', 'developers.updated_at']).all
end
def test_find_symbol_ordered_last
- last = Developer.find :last, :order => :salary
- assert_equal last, Developer.find(:all, :order => :salary).last
- end
-
- def test_find_scoped_ordered_last
- last_developer = Developer.send(:with_scope, :find => { :order => 'developers.salary ASC' }) do
- Developer.find(:last)
- end
- assert_equal last_developer, Developer.find(:all, :order => 'developers.salary ASC').last
+ last = Developer.scoped(:order => :salary).last
+ assert_equal last, Developer.scoped(:order => :salary).all.last
end
def test_abstract_class
@@ -1800,7 +1720,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_to_param_should_return_string
- assert_kind_of String, Client.find(:first).to_param
+ assert_kind_of String, Client.first.to_param
end
def test_inspect_class
@@ -1819,8 +1739,8 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_inspect_limited_select_instance
- assert_equal %(#<Topic id: 1>), Topic.find(:first, :select => 'id', :conditions => 'id = 1').inspect
- assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.find(:first, :select => 'id, title', :conditions => 'id = 1').inspect
+ assert_equal %(#<Topic id: 1>), Topic.scoped(:select => 'id', :where => 'id = 1').first.inspect
+ assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.scoped(:select => 'id, title', :where => 'id = 1').first.inspect
end
def test_inspect_class_without_table
@@ -2083,4 +2003,9 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal record, klass.public_send(meth, :foo, :bar)
end
end
+
+ test "scoped can take a values hash" do
+ klass = Class.new(ActiveRecord::Base)
+ assert_equal ['foo'], klass.scoped(select: 'foo').select_values
+ end
end
diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb
index 660098b9ad..cdd4b49042 100644
--- a/activerecord/test/cases/batches_test.rb
+++ b/activerecord/test/cases/batches_test.rb
@@ -27,30 +27,18 @@ class EachTest < ActiveRecord::TestCase
def test_each_should_raise_if_select_is_set_without_id
assert_raise(RuntimeError) do
- Post.find_each(:select => :title, :batch_size => 1) { |post| post }
+ Post.select(:title).find_each(:batch_size => 1) { |post| post }
end
end
def test_each_should_execute_if_id_is_in_select
assert_queries(6) do
- Post.find_each(:select => "id, title, type", :batch_size => 2) do |post|
+ Post.select("id, title, type").find_each(:batch_size => 2) do |post|
assert_kind_of Post, post
end
end
end
- def test_each_should_raise_if_the_order_is_set
- assert_raise(RuntimeError) do
- Post.find_each(:order => "title") { |post| post }
- end
- end
-
- def test_each_should_raise_if_the_limit_is_set
- assert_raise(RuntimeError) do
- Post.find_each(:limit => 1) { |post| post }
- end
- end
-
def test_warn_if_limit_scope_is_set
ActiveRecord::Base.logger.expects(:warn)
Post.limit(1).find_each { |post| post }
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 0391319a00..2e566ff873 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -49,13 +49,7 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_get_maximum_of_field_with_include
- assert_equal 55, Account.maximum(:credit_limit, :include => :firm, :references => :companies, :conditions => "companies.name != 'Summit'")
- end
-
- def test_should_get_maximum_of_field_with_scoped_include
- Account.send :with_scope, :find => { :include => :firm, :references => :companies, :conditions => "companies.name != 'Summit'" } do
- assert_equal 55, Account.maximum(:credit_limit)
- end
+ assert_equal 55, Account.where("companies.name != 'Summit'").references(:companies).includes(:firm).maximum(:credit_limit)
end
def test_should_get_minimum_of_field
@@ -63,12 +57,12 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_group_by_field
- c = Account.sum(:credit_limit, :group => :firm_id)
+ c = Account.group(:firm_id).sum(:credit_limit)
[1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
end
def test_should_group_by_multiple_fields
- c = Account.count(:all, :group => ['firm_id', :credit_limit])
+ c = Account.group('firm_id', :credit_limit).count(:all)
[ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert c.keys.include?(firm_and_limit) }
end
@@ -81,32 +75,32 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_group_by_summed_field
- c = Account.sum(:credit_limit, :group => :firm_id)
+ c = Account.group(:firm_id).sum(:credit_limit)
assert_equal 50, c[1]
assert_equal 105, c[6]
assert_equal 60, c[2]
end
def test_should_order_by_grouped_field
- c = Account.sum(:credit_limit, :group => :firm_id, :order => "firm_id")
+ c = Account.scoped(:group => :firm_id, :order => "firm_id").sum(:credit_limit)
assert_equal [1, 2, 6, 9], c.keys.compact
end
def test_should_order_by_calculation
- c = Account.sum(:credit_limit, :group => :firm_id, :order => "sum_credit_limit desc, firm_id")
+ c = Account.scoped(:group => :firm_id, :order => "sum_credit_limit desc, firm_id").sum(:credit_limit)
assert_equal [105, 60, 53, 50, 50], c.keys.collect { |k| c[k] }
assert_equal [6, 2, 9, 1], c.keys.compact
end
def test_should_limit_calculation
- c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
- :group => :firm_id, :order => "firm_id", :limit => 2)
+ c = Account.scoped(:where => "firm_id IS NOT NULL",
+ :group => :firm_id, :order => "firm_id", :limit => 2).sum(:credit_limit)
assert_equal [1, 2], c.keys.compact
end
def test_should_limit_calculation_with_offset
- c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
- :group => :firm_id, :order => "firm_id", :limit => 2, :offset => 1)
+ c = Account.scoped(:where => "firm_id IS NOT NULL", :group => :firm_id,
+ :order => "firm_id", :limit => 2, :offset => 1).sum(:credit_limit)
assert_equal [2, 6], c.keys.compact
end
@@ -156,16 +150,8 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_group_by_summed_field_having_condition
- c = Account.sum(:credit_limit, :group => :firm_id,
- :having => 'sum(credit_limit) > 50')
- assert_nil c[1]
- assert_equal 105, c[6]
- assert_equal 60, c[2]
- end
-
- def test_should_group_by_summed_field_having_sanitized_condition
- c = Account.sum(:credit_limit, :group => :firm_id,
- :having => ['sum(credit_limit) > ?', 50])
+ c = Account.scoped(:group => :firm_id,
+ :having => 'sum(credit_limit) > 50').sum(:credit_limit)
assert_nil c[1]
assert_equal 105, c[6]
assert_equal 60, c[2]
@@ -179,19 +165,19 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_group_by_summed_association
- c = Account.sum(:credit_limit, :group => :firm)
+ c = Account.group(:firm).sum(:credit_limit)
assert_equal 50, c[companies(:first_firm)]
assert_equal 105, c[companies(:rails_core)]
assert_equal 60, c[companies(:first_client)]
end
def test_should_sum_field_with_conditions
- assert_equal 105, Account.sum(:credit_limit, :conditions => 'firm_id = 6')
+ assert_equal 105, Account.where('firm_id = 6').sum(:credit_limit)
end
def test_should_return_zero_if_sum_conditions_return_nothing
- assert_equal 0, Account.sum(:credit_limit, :conditions => '1 = 2')
- assert_equal 0, companies(:rails_core).companies.sum(:id, :conditions => '1 = 2')
+ assert_equal 0, Account.where('1 = 2').sum(:credit_limit)
+ assert_equal 0, companies(:rails_core).companies.where('1 = 2').sum(:id)
end
def test_sum_should_return_valid_values_for_decimals
@@ -200,24 +186,24 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_group_by_summed_field_with_conditions
- c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
- :group => :firm_id)
+ c = Account.scoped(:where => 'firm_id > 1',
+ :group => :firm_id).sum(:credit_limit)
assert_nil c[1]
assert_equal 105, c[6]
assert_equal 60, c[2]
end
def test_should_group_by_summed_field_with_conditions_and_having
- c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
- :group => :firm_id,
- :having => 'sum(credit_limit) > 60')
+ c = Account.scoped(:where => 'firm_id > 1',
+ :group => :firm_id,
+ :having => 'sum(credit_limit) > 60').sum(:credit_limit)
assert_nil c[1]
assert_equal 105, c[6]
assert_nil c[2]
end
def test_should_group_by_fields_with_table_alias
- c = Account.sum(:credit_limit, :group => 'accounts.firm_id')
+ c = Account.group('accounts.firm_id').sum(:credit_limit)
assert_equal 50, c[1]
assert_equal 105, c[6]
assert_equal 60, c[2]
@@ -229,14 +215,14 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_calculate_grouped_with_invalid_field
- c = Account.count(:all, :group => 'accounts.firm_id')
+ c = Account.group('accounts.firm_id').count(:all)
assert_equal 1, c[1]
assert_equal 2, c[6]
assert_equal 1, c[2]
end
def test_should_calculate_grouped_association_with_invalid_field
- c = Account.count(:all, :group => :firm)
+ c = Account.group(:firm).count(:all)
assert_equal 1, c[companies(:first_firm)]
assert_equal 2, c[companies(:rails_core)]
assert_equal 1, c[companies(:first_client)]
@@ -255,7 +241,7 @@ class CalculationsTest < ActiveRecord::TestCase
column.expects(:type_cast).with("ABC").returns("ABC")
Account.expects(:columns).at_least_once.returns([column])
- c = Account.count(:all, :group => :firm)
+ c = Account.group(:firm).count(:all)
first_key = c.keys.first
assert_equal Firm, first_key.class
assert_equal 1, c[first_key]
@@ -263,22 +249,14 @@ class CalculationsTest < ActiveRecord::TestCase
def test_should_calculate_grouped_association_with_foreign_key_option
Account.belongs_to :another_firm, :class_name => 'Firm', :foreign_key => 'firm_id'
- c = Account.count(:all, :group => :another_firm)
+ c = Account.group(:another_firm).count(:all)
assert_equal 1, c[companies(:first_firm)]
assert_equal 2, c[companies(:rails_core)]
assert_equal 1, c[companies(:first_client)]
end
- def test_should_not_modify_options_when_using_includes
- options = {:conditions => 'companies.id > 1', :include => :firm, :references => :companies}
- options_copy = options.dup
-
- Account.count(:all, options)
- assert_equal options_copy, options
- end
-
def test_should_calculate_grouped_by_function
- c = Company.count(:all, :group => "UPPER(#{QUOTED_TYPE})")
+ c = Company.group("UPPER(#{QUOTED_TYPE})").count(:all)
assert_equal 2, c[nil]
assert_equal 1, c['DEPENDENTFIRM']
assert_equal 4, c['CLIENT']
@@ -286,7 +264,7 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_calculate_grouped_by_function_with_table_alias
- c = Company.count(:all, :group => "UPPER(companies.#{QUOTED_TYPE})")
+ c = Company.group("UPPER(companies.#{QUOTED_TYPE})").count(:all)
assert_equal 2, c[nil]
assert_equal 1, c['DEPENDENTFIRM']
assert_equal 4, c['CLIENT']
@@ -306,25 +284,24 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_sum_scoped_field_with_conditions
- assert_equal 8, companies(:rails_core).companies.sum(:id, :conditions => 'id > 7')
+ assert_equal 8, companies(:rails_core).companies.where('id > 7').sum(:id)
end
def test_should_group_by_scoped_field
- c = companies(:rails_core).companies.sum(:id, :group => :name)
+ c = companies(:rails_core).companies.group(:name).sum(:id)
assert_equal 7, c['Leetsoft']
assert_equal 8, c['Jadedpixel']
end
def test_should_group_by_summed_field_through_association_and_having
- c = companies(:rails_core).companies.sum(:id, :group => :name,
- :having => 'sum(id) > 7')
+ c = companies(:rails_core).companies.group(:name).having('sum(id) > 7').sum(:id)
assert_nil c['Leetsoft']
assert_equal 8, c['Jadedpixel']
end
def test_should_count_selected_field_with_include
- assert_equal 6, Account.count(:distinct => true, :include => :firm)
- assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
+ assert_equal 6, Account.includes(:firm).count(:distinct => true)
+ assert_equal 4, Account.includes(:firm).select(:credit_limit).count(:distinct => true)
end
def test_should_not_perform_joined_include_by_default
@@ -348,11 +325,11 @@ class CalculationsTest < ActiveRecord::TestCase
Account.last.update_column('credit_limit', 49)
Account.first.update_column('credit_limit', 51)
- assert_equal 1, Account.scoped(:select => "credit_limit").count(:conditions => ['credit_limit >= 50'])
+ assert_equal 1, Account.scoped(:select => "credit_limit").where('credit_limit >= 50').count
end
def test_should_count_manual_select_with_include
- assert_equal 6, Account.count(:select => "DISTINCT accounts.id", :include => :firm)
+ assert_equal 6, Account.scoped(:select => "DISTINCT accounts.id", :includes => :firm).count
end
def test_count_with_column_parameter
@@ -360,16 +337,16 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_count_with_column_and_options_parameter
- assert_equal 2, Account.count(:firm_id, :conditions => "credit_limit = 50 AND firm_id IS NOT NULL")
+ assert_equal 2, Account.where("credit_limit = 50 AND firm_id IS NOT NULL").count(:firm_id)
end
def test_should_count_field_in_joined_table
- assert_equal 5, Account.count('companies.id', :joins => :firm)
- assert_equal 4, Account.count('companies.id', :joins => :firm, :distinct => true)
+ assert_equal 5, Account.joins(:firm).count('companies.id')
+ assert_equal 4, Account.joins(:firm).count('companies.id', :distinct => true)
end
def test_should_count_field_in_joined_table_with_group_by
- c = Account.count('companies.id', :group => 'accounts.firm_id', :joins => :firm)
+ c = Account.scoped(:group => 'accounts.firm_id', :joins => :firm).count('companies.id')
[1,6,2,9].each { |firm_id| assert c.keys.include?(firm_id) }
end
@@ -392,17 +369,17 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_count_with_from_option
- assert_equal Company.count(:all), Company.count(:all, :from => 'companies')
- assert_equal Account.count(:all, :conditions => "credit_limit = 50"),
- Account.count(:all, :from => 'accounts', :conditions => "credit_limit = 50")
- assert_equal Company.count(:type, :conditions => {:type => "Firm"}),
- Company.count(:type, :conditions => {:type => "Firm"}, :from => 'companies')
+ assert_equal Company.count(:all), Company.from('companies').count(:all)
+ assert_equal Account.where("credit_limit = 50").count(:all),
+ Account.from('accounts').where("credit_limit = 50").count(:all)
+ assert_equal Company.where(:type => "Firm").count(:type),
+ Company.where(:type => "Firm").from('companies').count(:type)
end
def test_sum_with_from_option
- assert_equal Account.sum(:credit_limit), Account.sum(:credit_limit, :from => 'accounts')
- assert_equal Account.sum(:credit_limit, :conditions => "credit_limit > 50"),
- Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ assert_equal Account.sum(:credit_limit), Account.from('accounts').sum(:credit_limit)
+ assert_equal Account.where("credit_limit > 50").sum(:credit_limit),
+ Account.where("credit_limit > 50").from('accounts').sum(:credit_limit)
end
def test_sum_array_compatibility
@@ -410,33 +387,33 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_average_with_from_option
- assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts')
- assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"),
- Account.average(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ assert_equal Account.average(:credit_limit), Account.from('accounts').average(:credit_limit)
+ assert_equal Account.where("credit_limit > 50").average(:credit_limit),
+ Account.where("credit_limit > 50").from('accounts').average(:credit_limit)
end
def test_minimum_with_from_option
- assert_equal Account.minimum(:credit_limit), Account.minimum(:credit_limit, :from => 'accounts')
- assert_equal Account.minimum(:credit_limit, :conditions => "credit_limit > 50"),
- Account.minimum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ assert_equal Account.minimum(:credit_limit), Account.from('accounts').minimum(:credit_limit)
+ assert_equal Account.where("credit_limit > 50").minimum(:credit_limit),
+ Account.where("credit_limit > 50").from('accounts').minimum(:credit_limit)
end
def test_maximum_with_from_option
- assert_equal Account.maximum(:credit_limit), Account.maximum(:credit_limit, :from => 'accounts')
- assert_equal Account.maximum(:credit_limit, :conditions => "credit_limit > 50"),
- Account.maximum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ assert_equal Account.maximum(:credit_limit), Account.from('accounts').maximum(:credit_limit)
+ assert_equal Account.where("credit_limit > 50").maximum(:credit_limit),
+ Account.where("credit_limit > 50").from('accounts').maximum(:credit_limit)
end
def test_from_option_with_specified_index
if Edge.connection.adapter_name == 'MySQL' or Edge.connection.adapter_name == 'Mysql2'
- assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
- assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
- Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
+ assert_equal Edge.count(:all), Edge.from('edges USE INDEX(unique_edge_index)').count(:all)
+ assert_equal Edge.where('sink_id < 5').count(:all),
+ Edge.from('edges USE INDEX(unique_edge_index)').where('sink_id < 5').count(:all)
end
end
def test_from_option_with_table_different_than_class
- assert_equal Account.count(:all), Company.count(:all, :from => 'accounts')
+ assert_equal Account.count(:all), Company.from('accounts').count(:all)
end
def test_distinct_is_honored_when_used_with_count_operation_after_group
diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb
index da93500ce3..8dc9f761c2 100644
--- a/activerecord/test/cases/connection_pool_test.rb
+++ b/activerecord/test/cases/connection_pool_test.rb
@@ -96,6 +96,30 @@ module ActiveRecord
end
end
+ def test_full_pool_blocks
+ cs = @pool.size.times.map { @pool.checkout }
+ t = Thread.new { @pool.checkout }
+
+ # make sure our thread is in the timeout section
+ Thread.pass until t.status == "sleep"
+
+ connection = cs.first
+ connection.close
+ assert_equal connection, t.join.value
+ end
+
+ def test_removing_releases_latch
+ cs = @pool.size.times.map { @pool.checkout }
+ t = Thread.new { @pool.checkout }
+
+ # make sure our thread is in the timeout section
+ Thread.pass until t.status == "sleep"
+
+ connection = cs.first
+ @pool.remove connection
+ assert_respond_to t.join.value, :execute
+ end
+
def test_reap_and_active
@pool.checkout
@pool.checkout
diff --git a/activerecord/test/cases/custom_locking_test.rb b/activerecord/test/cases/custom_locking_test.rb
index d63ecdbcc5..42ef51ef3e 100644
--- a/activerecord/test/cases/custom_locking_test.rb
+++ b/activerecord/test/cases/custom_locking_test.rb
@@ -9,7 +9,7 @@ module ActiveRecord
if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
assert_match 'SHARE MODE', Person.lock('LOCK IN SHARE MODE').to_sql
assert_sql(/LOCK IN SHARE MODE/) do
- Person.find(1, :lock => 'LOCK IN SHARE MODE')
+ Person.scoped(:lock => 'LOCK IN SHARE MODE').find(1)
end
end
end
diff --git a/activerecord/test/cases/deprecated_finder_test.rb b/activerecord/test/cases/deprecated_finder_test.rb
deleted file mode 100644
index 2afc91b769..0000000000
--- a/activerecord/test/cases/deprecated_finder_test.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require "cases/helper"
-require 'models/entrant'
-
-class DeprecatedFinderTest < ActiveRecord::TestCase
- fixtures :entrants
-
- def test_deprecated_find_all_was_removed
- assert_raise(NoMethodError) { Entrant.find_all }
- end
-
- def test_deprecated_find_first_was_removed
- assert_raise(NoMethodError) { Entrant.find_first }
- end
-
- def test_deprecated_find_on_conditions_was_removed
- assert_raise(NoMethodError) { Entrant.find_on_conditions }
- end
-
- def test_count
- assert_equal(0, Entrant.count(:conditions => "id > 3"))
- assert_equal(1, Entrant.count(:conditions => ["id > ?", 2]))
- assert_equal(2, Entrant.count(:conditions => ["id > ?", 1]))
- end
-
- def test_count_by_sql
- assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
- assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
- assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
- end
-end
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index 54e0b40b4f..2650040a80 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -288,7 +288,7 @@ class DirtyTest < ActiveRecord::TestCase
with_partial_updates Pirate, false do
assert_queries(2) { 2.times { pirate.save! } }
- Pirate.update_all({ :updated_on => old_updated_on }, :id => pirate.id)
+ Pirate.where(id: pirate.id).update_all(:updated_on => old_updated_on)
end
with_partial_updates Pirate, true do
@@ -306,7 +306,7 @@ class DirtyTest < ActiveRecord::TestCase
with_partial_updates Person, false do
assert_queries(2) { 2.times { person.save! } }
- Person.update_all({ :first_name => 'baz' }, :id => person.id)
+ Person.where(id: person.id).update_all(:first_name => 'baz')
end
with_partial_updates Person, true do
diff --git a/activerecord/test/cases/explain_test.rb b/activerecord/test/cases/explain_test.rb
index 83c9b6e107..cb7781f8e7 100644
--- a/activerecord/test/cases/explain_test.rb
+++ b/activerecord/test/cases/explain_test.rb
@@ -28,7 +28,9 @@ if ActiveRecord::Base.connection.supports_explain?
original = base.logger
base.logger = nil
- base.logger.expects(:warn).never
+ class << base.logger
+ def warn; raise "Should not be called" end
+ end
with_threshold(0) do
car = Car.where(:name => 'honda').first
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 96c8eb6417..29469c42ed 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -82,12 +82,6 @@ class FinderTest < ActiveRecord::TestCase
Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
end
- def test_exists_with_scoped_include
- Developer.send(:with_scope, :find => { :include => :projects, :order => "projects.name" }) do
- assert Developer.exists?
- end
- end
-
def test_exists_does_not_instantiate_records
Developer.expects(:instantiate).never
Developer.exists?
@@ -104,14 +98,14 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_by_ids_with_limit_and_offset
- assert_equal 2, Entrant.find([1,3,2], :limit => 2).size
- assert_equal 1, Entrant.find([1,3,2], :limit => 3, :offset => 2).size
+ assert_equal 2, Entrant.scoped(:limit => 2).find([1,3,2]).size
+ assert_equal 1, Entrant.scoped(:limit => 3, :offset => 2).find([1,3,2]).size
# Also test an edge case: If you have 11 results, and you set a
# limit of 3 and offset of 9, then you should find that there
# will be only 2 results, regardless of the limit.
- devs = Developer.find :all
- last_devs = Developer.find devs.map(&:id), :limit => 3, :offset => 9
+ devs = Developer.all
+ last_devs = Developer.scoped(:limit => 3, :offset => 9).find devs.map(&:id)
assert_equal 2, last_devs.size
end
@@ -123,56 +117,6 @@ class FinderTest < ActiveRecord::TestCase
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
end
- def test_find_all_with_limit
- assert_equal(2, Entrant.find(:all, :limit => 2).size)
- assert_equal(0, Entrant.find(:all, :limit => 0).size)
- end
-
- def test_find_all_with_prepared_limit_and_offset
- entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 1)
-
- assert_equal(2, entrants.size)
- assert_equal(entrants(:second).name, entrants.first.name)
-
- assert_equal 3, Entrant.count
- entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 2)
- assert_equal(1, entrants.size)
- assert_equal(entrants(:third).name, entrants.first.name)
- end
-
- def test_find_all_with_limit_and_offset_and_multiple_order_clauses
- first_three_posts = Post.find :all, :order => 'author_id, id', :limit => 3, :offset => 0
- second_three_posts = Post.find :all, :order => ' author_id,id ', :limit => 3, :offset => 3
- third_three_posts = Post.find :all, :order => ' author_id, id ', :limit => 3, :offset => 6
- last_posts = Post.find :all, :order => ' author_id, id ', :limit => 3, :offset => 9
-
- assert_equal [[0,3],[1,1],[1,2]], first_three_posts.map { |p| [p.author_id, p.id] }
- assert_equal [[1,4],[1,5],[1,6]], second_three_posts.map { |p| [p.author_id, p.id] }
- assert_equal [[2,7],[2,9],[2,11]], third_three_posts.map { |p| [p.author_id, p.id] }
- assert_equal [[3,8],[3,10]], last_posts.map { |p| [p.author_id, p.id] }
- end
-
-
- def test_find_with_group
- developers = Developer.find(:all, :group => "salary", :select => "salary")
- assert_equal 4, developers.size
- assert_equal 4, developers.map(&:salary).uniq.size
- end
-
- def test_find_with_group_and_having
- developers = Developer.find(:all, :group => "salary", :having => "sum(salary) > 10000", :select => "salary")
- assert_equal 3, developers.size
- assert_equal 3, developers.map(&:salary).uniq.size
- assert developers.all? { |developer| developer.salary > 10000 }
- end
-
- def test_find_with_group_and_sanitized_having
- developers = Developer.find(:all, :group => "salary", :having => ["sum(salary) > ?", 10000], :select => "salary")
- assert_equal 3, developers.size
- assert_equal 3, developers.map(&:salary).uniq.size
- assert developers.all? { |developer| developer.salary > 10000 }
- end
-
def test_find_with_group_and_sanitized_having_method
developers = Developer.group(:salary).having("sum(salary) > ?", 10000).select('salary').all
assert_equal 3, developers.size
@@ -199,16 +143,6 @@ class FinderTest < ActiveRecord::TestCase
assert_equal [Account], accounts.collect(&:class).uniq
end
- def test_find_first
- first = Topic.find(:first, :conditions => "title = 'The First Topic'")
- assert_equal(topics(:first).title, first.title)
- end
-
- def test_find_first_failing
- first = Topic.find(:first, :conditions => "title = 'The First Topic!'")
- assert_nil(first)
- end
-
def test_first
assert_equal topics(:second).title, Topic.where("title = 'The Second Topic of the day'").first.title
end
@@ -292,7 +226,7 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_only_some_columns
- topic = Topic.find(1, :select => "author_name")
+ topic = Topic.scoped(:select => "author_name").find(1)
assert_raise(ActiveModel::MissingAttributeError) {topic.title}
assert_nil topic.read_attribute("title")
assert_equal "David", topic.author_name
@@ -302,36 +236,24 @@ class FinderTest < ActiveRecord::TestCase
assert_respond_to topic, "author_name"
end
- def test_find_on_blank_conditions
- [nil, " ", [], {}].each do |blank|
- assert_nothing_raised { Topic.find(:first, :conditions => blank) }
- end
- end
-
- def test_find_on_blank_bind_conditions
- [ [""], ["",{}] ].each do |blank|
- assert_nothing_raised { Topic.find(:first, :conditions => blank) }
- end
- end
-
def test_find_on_array_conditions
- assert Topic.find(1, :conditions => ["approved = ?", false])
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => ["approved = ?", true]) }
+ assert Topic.scoped(:where => ["approved = ?", false]).find(1)
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => ["approved = ?", true]).find(1) }
end
def test_find_on_hash_conditions
- assert Topic.find(1, :conditions => { :approved => false })
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :approved => true }) }
+ assert Topic.scoped(:where => { :approved => false }).find(1)
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :approved => true }).find(1) }
end
def test_find_on_hash_conditions_with_explicit_table_name
- assert Topic.find(1, :conditions => { 'topics.approved' => false })
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { 'topics.approved' => true }) }
+ assert Topic.scoped(:where => { 'topics.approved' => false }).find(1)
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { 'topics.approved' => true }).find(1) }
end
def test_find_on_hash_conditions_with_hashed_table_name
- assert Topic.find(1, :conditions => {:topics => { :approved => false }})
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => {:topics => { :approved => true }}) }
+ assert Topic.scoped(:where => {:topics => { :approved => false }}).find(1)
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => {:topics => { :approved => true }}).find(1) }
end
def test_find_with_hash_conditions_on_joined_table
@@ -341,16 +263,16 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_with_hash_conditions_on_joined_table_and_with_range
- firms = DependentFirm.all :joins => :account, :conditions => {:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}
+ firms = DependentFirm.scoped :joins => :account, :where => {:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}
assert_equal 1, firms.size
assert_equal companies(:rails_core), firms.first
end
def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
david = customers(:david)
- assert Customer.find(david.id, :conditions => { 'customers.name' => david.name, :address => david.address })
+ assert Customer.scoped(:where => { 'customers.name' => david.name, :address => david.address }).find(david.id)
assert_raise(ActiveRecord::RecordNotFound) {
- Customer.find(david.id, :conditions => { 'customers.name' => david.name + "1", :address => david.address })
+ Customer.scoped(:where => { 'customers.name' => david.name + "1", :address => david.address }).find(david.id)
}
end
@@ -359,71 +281,71 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_on_hash_conditions_with_range
- assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1..2 }).map(&:id).sort
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :id => 2..3 }) }
+ assert_equal [1,2], Topic.scoped(:where => { :id => 1..2 }).all.map(&:id).sort
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :id => 2..3 }).find(1) }
end
def test_find_on_hash_conditions_with_end_exclusive_range
- assert_equal [1,2,3], Topic.find(:all, :conditions => { :id => 1..3 }).map(&:id).sort
- assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1...3 }).map(&:id).sort
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(3, :conditions => { :id => 2...3 }) }
+ assert_equal [1,2,3], Topic.scoped(:where => { :id => 1..3 }).all.map(&:id).sort
+ assert_equal [1,2], Topic.scoped(:where => { :id => 1...3 }).all.map(&:id).sort
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :id => 2...3 }).find(3) }
end
def test_find_on_hash_conditions_with_multiple_ranges
- assert_equal [1,2,3], Comment.find(:all, :conditions => { :id => 1..3, :post_id => 1..2 }).map(&:id).sort
- assert_equal [1], Comment.find(:all, :conditions => { :id => 1..1, :post_id => 1..10 }).map(&:id).sort
+ assert_equal [1,2,3], Comment.scoped(:where => { :id => 1..3, :post_id => 1..2 }).all.map(&:id).sort
+ assert_equal [1], Comment.scoped(:where => { :id => 1..1, :post_id => 1..10 }).all.map(&:id).sort
end
def test_find_on_hash_conditions_with_array_of_integers_and_ranges
- assert_equal [1,2,3,5,6,7,8,9], Comment.find(:all, :conditions => {:id => [1..2, 3, 5, 6..8, 9]}).map(&:id).sort
+ assert_equal [1,2,3,5,6,7,8,9], Comment.scoped(:where => {:id => [1..2, 3, 5, 6..8, 9]}).all.map(&:id).sort
end
def test_find_on_multiple_hash_conditions
- assert Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false })
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }) }
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
+ assert Topic.scoped(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false }).find(1)
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }).find(1) }
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }).find(1) }
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }).find(1) }
end
def test_condition_interpolation
- assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
- assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
- assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
- assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
+ assert_kind_of Firm, Company.where("name = '%s'", "37signals").first
+ assert_nil Company.scoped(:where => ["name = '%s'", "37signals!"]).first
+ assert_nil Company.scoped(:where => ["name = '%s'", "37signals!' OR 1=1"]).first
+ assert_kind_of Time, Topic.scoped(:where => ["id = %d", 1]).first.written_on
end
def test_condition_array_interpolation
- assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
- assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
- assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
- assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
+ assert_kind_of Firm, Company.scoped(:where => ["name = '%s'", "37signals"]).first
+ assert_nil Company.scoped(:where => ["name = '%s'", "37signals!"]).first
+ assert_nil Company.scoped(:where => ["name = '%s'", "37signals!' OR 1=1"]).first
+ assert_kind_of Time, Topic.scoped(:where => ["id = %d", 1]).first.written_on
end
def test_condition_hash_interpolation
- assert_kind_of Firm, Company.find(:first, :conditions => { :name => "37signals"})
- assert_nil Company.find(:first, :conditions => { :name => "37signals!"})
- assert_kind_of Time, Topic.find(:first, :conditions => {:id => 1}).written_on
+ assert_kind_of Firm, Company.scoped(:where => { :name => "37signals"}).first
+ assert_nil Company.scoped(:where => { :name => "37signals!"}).first
+ assert_kind_of Time, Topic.scoped(:where => {:id => 1}).first.written_on
end
def test_hash_condition_find_malformed
assert_raise(ActiveRecord::StatementInvalid) {
- Company.find(:first, :conditions => { :id => 2, :dhh => true })
+ Company.scoped(:where => { :id => 2, :dhh => true }).first
}
end
def test_hash_condition_find_with_escaped_characters
Company.create("name" => "Ain't noth'n like' \#stuff")
- assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff" })
+ assert Company.scoped(:where => { :name => "Ain't noth'n like' \#stuff" }).first
end
def test_hash_condition_find_with_array
- p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
- assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2] }, :order => 'id asc')
- assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2.id] }, :order => 'id asc')
+ p1, p2 = Post.scoped(:limit => 2, :order => 'id asc').all
+ assert_equal [p1, p2], Post.scoped(:where => { :id => [p1, p2] }, :order => 'id asc').all
+ assert_equal [p1, p2], Post.scoped(:where => { :id => [p1, p2.id] }, :order => 'id asc').all
end
def test_hash_condition_find_with_nil
- topic = Topic.find(:first, :conditions => { :last_read => nil } )
+ topic = Topic.scoped(:where => { :last_read => nil } ).first
assert_not_nil topic
assert_nil topic.last_read
end
@@ -431,42 +353,42 @@ class FinderTest < ActiveRecord::TestCase
def test_hash_condition_find_with_aggregate_having_one_mapping
balance = customers(:david).balance
assert_kind_of Money, balance
- found_customer = Customer.find(:first, :conditions => {:balance => balance})
+ found_customer = Customer.scoped(:where => {:balance => balance}).first
assert_equal customers(:david), found_customer
end
def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_aggregate
gps_location = customers(:david).gps_location
assert_kind_of GpsLocation, gps_location
- found_customer = Customer.find(:first, :conditions => {:gps_location => gps_location})
+ found_customer = Customer.scoped(:where => {:gps_location => gps_location}).first
assert_equal customers(:david), found_customer
end
def test_hash_condition_find_with_aggregate_having_one_mapping_and_key_value_being_attribute_value
balance = customers(:david).balance
assert_kind_of Money, balance
- found_customer = Customer.find(:first, :conditions => {:balance => balance.amount})
+ found_customer = Customer.scoped(:where => {:balance => balance.amount}).first
assert_equal customers(:david), found_customer
end
def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_attribute_value
gps_location = customers(:david).gps_location
assert_kind_of GpsLocation, gps_location
- found_customer = Customer.find(:first, :conditions => {:gps_location => gps_location.gps_location})
+ found_customer = Customer.scoped(:where => {:gps_location => gps_location.gps_location}).first
assert_equal customers(:david), found_customer
end
def test_hash_condition_find_with_aggregate_having_three_mappings
address = customers(:david).address
assert_kind_of Address, address
- found_customer = Customer.find(:first, :conditions => {:address => address})
+ found_customer = Customer.scoped(:where => {:address => address}).first
assert_equal customers(:david), found_customer
end
def test_hash_condition_find_with_one_condition_being_aggregate_and_another_not
address = customers(:david).address
assert_kind_of Address, address
- found_customer = Customer.find(:first, :conditions => {:address => address, :name => customers(:david).name})
+ found_customer = Customer.scoped(:where => {:address => address, :name => customers(:david).name}).first
assert_equal customers(:david), found_customer
end
@@ -474,7 +396,7 @@ class FinderTest < ActiveRecord::TestCase
with_env_tz 'America/New_York' do
with_active_record_default_timezone :local do
topic = Topic.first
- assert_equal topic, Topic.find(:first, :conditions => ['written_on = ?', topic.written_on.getutc])
+ assert_equal topic, Topic.scoped(:where => ['written_on = ?', topic.written_on.getutc]).first
end
end
end
@@ -483,7 +405,7 @@ class FinderTest < ActiveRecord::TestCase
with_env_tz 'America/New_York' do
with_active_record_default_timezone :local do
topic = Topic.first
- assert_equal topic, Topic.find(:first, :conditions => {:written_on => topic.written_on.getutc})
+ assert_equal topic, Topic.scoped(:where => {:written_on => topic.written_on.getutc}).first
end
end
end
@@ -492,7 +414,7 @@ class FinderTest < ActiveRecord::TestCase
with_env_tz 'America/New_York' do
with_active_record_default_timezone :utc do
topic = Topic.first
- assert_equal topic, Topic.find(:first, :conditions => ['written_on = ?', topic.written_on.getlocal])
+ assert_equal topic, Topic.scoped(:where => ['written_on = ?', topic.written_on.getlocal]).first
end
end
end
@@ -501,32 +423,32 @@ class FinderTest < ActiveRecord::TestCase
with_env_tz 'America/New_York' do
with_active_record_default_timezone :utc do
topic = Topic.first
- assert_equal topic, Topic.find(:first, :conditions => {:written_on => topic.written_on.getlocal})
+ assert_equal topic, Topic.scoped(:where => {:written_on => topic.written_on.getlocal}).first
end
end
end
def test_bind_variables
- assert_kind_of Firm, Company.find(:first, :conditions => ["name = ?", "37signals"])
- assert_nil Company.find(:first, :conditions => ["name = ?", "37signals!"])
- assert_nil Company.find(:first, :conditions => ["name = ?", "37signals!' OR 1=1"])
- assert_kind_of Time, Topic.find(:first, :conditions => ["id = ?", 1]).written_on
+ assert_kind_of Firm, Company.scoped(:where => ["name = ?", "37signals"]).first
+ assert_nil Company.scoped(:where => ["name = ?", "37signals!"]).first
+ assert_nil Company.scoped(:where => ["name = ?", "37signals!' OR 1=1"]).first
+ assert_kind_of Time, Topic.scoped(:where => ["id = ?", 1]).first.written_on
assert_raise(ActiveRecord::PreparedStatementInvalid) {
- Company.find(:first, :conditions => ["id=? AND name = ?", 2])
+ Company.scoped(:where => ["id=? AND name = ?", 2]).first
}
assert_raise(ActiveRecord::PreparedStatementInvalid) {
- Company.find(:first, :conditions => ["id=?", 2, 3, 4])
+ Company.scoped(:where => ["id=?", 2, 3, 4]).first
}
end
def test_bind_variables_with_quotes
Company.create("name" => "37signals' go'es agains")
- assert Company.find(:first, :conditions => ["name = ?", "37signals' go'es agains"])
+ assert Company.scoped(:where => ["name = ?", "37signals' go'es agains"]).first
end
def test_named_bind_variables_with_quotes
Company.create("name" => "37signals' go'es agains")
- assert Company.find(:first, :conditions => ["name = :name", {:name => "37signals' go'es agains"}])
+ assert Company.scoped(:where => ["name = :name", {:name => "37signals' go'es agains"}]).first
end
def test_bind_arity
@@ -544,10 +466,10 @@ class FinderTest < ActiveRecord::TestCase
assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
- assert_kind_of Firm, Company.find(:first, :conditions => ["name = :name", { :name => "37signals" }])
- assert_nil Company.find(:first, :conditions => ["name = :name", { :name => "37signals!" }])
- assert_nil Company.find(:first, :conditions => ["name = :name", { :name => "37signals!' OR 1=1" }])
- assert_kind_of Time, Topic.find(:first, :conditions => ["id = :id", { :id => 1 }]).written_on
+ assert_kind_of Firm, Company.scoped(:where => ["name = :name", { :name => "37signals" }]).first
+ assert_nil Company.scoped(:where => ["name = :name", { :name => "37signals!" }]).first
+ assert_nil Company.scoped(:where => ["name = :name", { :name => "37signals!' OR 1=1" }]).first
+ assert_kind_of Time, Topic.scoped(:where => ["id = :id", { :id => 1 }]).first.written_on
end
class SimpleEnumerable
@@ -618,12 +540,6 @@ class FinderTest < ActiveRecord::TestCase
assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
end
- def test_count
- assert_equal(0, Entrant.count(:conditions => "id > 3"))
- assert_equal(1, Entrant.count(:conditions => ["id > ?", 2]))
- assert_equal(2, Entrant.count(:conditions => ["id > ?", 1]))
- end
-
def test_count_by_sql
assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
@@ -646,7 +562,7 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_by_one_attribute_with_conditions
- assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
+ assert_equal accounts(:rails_core_account), Account.where('firm_id = ?', 6).find_by_credit_limit(50)
end
def test_find_by_one_attribute_that_is_an_aggregate
@@ -686,12 +602,12 @@ class FinderTest < ActiveRecord::TestCase
def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
# ensure this test can run independently of order
class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
- a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
- assert_equal a, Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6]) # find_by_credit_limit has been cached
+ a = Account.where('firm_id = ?', 6).find_by_credit_limit(50)
+ assert_equal a, Account.where('firm_id = ?', 6).find_by_credit_limit(50) # find_by_credit_limit has been cached
end
def test_find_by_one_attribute_with_several_options
- assert_equal accounts(:unknown), Account.find_by_credit_limit(50, :order => 'id DESC', :conditions => ['id != ?', 3])
+ assert_equal accounts(:unknown), Account.order('id DESC').where('id != ?', 3).find_by_credit_limit(50)
end
def test_find_by_one_missing_attribute
@@ -725,7 +641,7 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_last_by_one_attribute_with_several_options
- assert_equal accounts(:signals37), Account.find_last_by_credit_limit(50, :order => 'id DESC', :conditions => ['id != ?', 3])
+ assert_equal accounts(:signals37), Account.order('id DESC').where('id != ?', 3).find_last_by_credit_limit(50)
end
def test_find_last_by_one_missing_attribute
@@ -1060,21 +976,15 @@ class FinderTest < ActiveRecord::TestCase
assert_raise(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
end
- def test_find_with_invalid_params
- assert_raise(ArgumentError) { Topic.find :first, :join => "It should be `joins'" }
- assert_raise(ArgumentError) { Topic.find :first, :conditions => '1 = 1', :join => "It should be `joins'" }
- end
-
def test_dynamic_finder_with_invalid_params
assert_raise(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" }
end
def test_find_all_with_join
- developers_on_project_one = Developer.find(
- :all,
+ developers_on_project_one = Developer.scoped(
:joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',
- :conditions => 'project_id=1'
- )
+ :where => 'project_id=1'
+ ).all
assert_equal 3, developers_on_project_one.length
developer_names = developers_on_project_one.map { |d| d.name }
assert developer_names.include?('David')
@@ -1082,17 +992,15 @@ class FinderTest < ActiveRecord::TestCase
end
def test_joins_dont_clobber_id
- first = Firm.find(
- :first,
+ first = Firm.scoped(
:joins => 'INNER JOIN companies clients ON clients.firm_id = companies.id',
- :conditions => 'companies.id = 1'
- )
+ :where => 'companies.id = 1'
+ ).first
assert_equal 1, first.id
end
def test_joins_with_string_array
- person_with_reader_and_post = Post.find(
- :all,
+ person_with_reader_and_post = Post.scoped(
:joins => [
"INNER JOIN categorizations ON categorizations.post_id = posts.id",
"INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
@@ -1103,8 +1011,7 @@ class FinderTest < ActiveRecord::TestCase
def test_find_by_id_with_conditions_with_or
assert_nothing_raised do
- Post.find([1,2,3],
- :conditions => "posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'")
+ Post.where("posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'").find([1,2,3])
end
end
@@ -1119,13 +1026,13 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_by_empty_in_condition
- assert_equal [], Post.find(:all, :conditions => ['id in (?)', []])
+ assert_equal [], Post.where('id in (?)', [])
end
def test_find_by_records
- p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
- assert_equal [p1, p2], Post.find(:all, :conditions => ['id in (?)', [p1, p2]], :order => 'id asc')
- assert_equal [p1, p2], Post.find(:all, :conditions => ['id in (?)', [p1, p2.id]], :order => 'id asc')
+ p1, p2 = Post.scoped(:limit => 2, :order => 'id asc').all
+ assert_equal [p1, p2], Post.scoped(:where => ['id in (?)', [p1, p2]], :order => 'id asc')
+ assert_equal [p1, p2], Post.scoped(:where => ['id in (?)', [p1, p2.id]], :order => 'id asc')
end
def test_select_value
@@ -1152,16 +1059,15 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
- assert_equal 2, Post.find(:all, :include => { :authors => :author_address }, :order => 'author_addresses.id DESC ', :limit => 2).size
+ assert_equal 2, Post.scoped(:includes => { :authors => :author_address }, :order => 'author_addresses.id DESC ', :limit => 2).all.size
- assert_equal 3, Post.find(:all, :include => { :author => :author_address, :authors => :author_address},
- :order => 'author_addresses_authors.id DESC ', :limit => 3).size
+ assert_equal 3, Post.scoped(:includes => { :author => :author_address, :authors => :author_address},
+ :order => 'author_addresses_authors.id DESC ', :limit => 3).all.size
end
def test_find_with_nil_inside_set_passed_for_one_attribute
- client_of = Company.find(
- :all,
- :conditions => {
+ client_of = Company.scoped(
+ :where => {
:client_of => [2, 1, nil],
:name => ['37signals', 'Summit', 'Microsoft'] },
:order => 'client_of DESC'
@@ -1172,9 +1078,8 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_with_nil_inside_set_passed_for_attribute
- client_of = Company.find(
- :all,
- :conditions => { :client_of => [nil] },
+ client_of = Company.scoped(
+ :where => { :client_of => [nil] },
:order => 'client_of DESC'
).map { |x| x.client_of }
@@ -1182,22 +1087,14 @@ class FinderTest < ActiveRecord::TestCase
end
def test_with_limiting_with_custom_select
- posts = Post.find(
- :all, :include => :author, :select => ' posts.*, authors.id as "author_id"',
- :references => :authors, :limit => 3, :order => 'posts.id'
- )
+ posts = Post.references(:authors).scoped(
+ :includes => :author, :select => ' posts.*, authors.id as "author_id"',
+ :limit => 3, :order => 'posts.id'
+ ).all
assert_equal 3, posts.size
assert_equal [0, 1, 1], posts.map(&:author_id).sort
end
- def test_finder_with_scoped_from
- all_topics = Topic.find(:all)
-
- Topic.send(:with_scope, :find => { :from => 'fake_topics' }) do
- assert_equal all_topics, Topic.from('topics').to_a
- end
- end
-
def test_find_one_message_with_custom_primary_key
Toy.primary_key = :name
begin
@@ -1208,7 +1105,7 @@ class FinderTest < ActiveRecord::TestCase
end
def test_finder_with_offset_string
- assert_nothing_raised(ActiveRecord::StatementInvalid) { Topic.find(:all, :offset => "3") }
+ assert_nothing_raised(ActiveRecord::StatementInvalid) { Topic.scoped(:offset => "3").all }
end
protected
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index e660b2ca35..c28f8de682 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -716,7 +716,7 @@ class FoxyFixturesTest < ActiveRecord::TestCase
end
def test_only_generates_a_pk_if_necessary
- m = Matey.find(:first)
+ m = Matey.first
m.pirate = pirates(:blackbeard)
m.target = pirates(:redbeard)
end
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index 5c3560a33b..345ae0b582 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -36,7 +36,7 @@ def current_adapter?(*types)
end
def in_memory_db?
- current_adapter?(:SQLiteAdapter) &&
+ current_adapter?(:SQLite3Adapter) &&
ActiveRecord::Base.connection_pool.spec.config[:database] == ":memory:"
end
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index 02df464469..06de51f5cd 100644
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
@@ -15,7 +15,7 @@ class InheritanceTest < ActiveRecord::TestCase
end
def test_class_with_blank_sti_name
- company = Company.find(:first)
+ company = Company.first
company = company.dup
company.extend(Module.new {
def read_attribute(name)
@@ -24,7 +24,7 @@ class InheritanceTest < ActiveRecord::TestCase
end
})
company.save!
- company = Company.find(:all).find { |x| x.id == company.id }
+ company = Company.all.find { |x| x.id == company.id }
assert_equal ' ', company.type
end
@@ -98,7 +98,7 @@ class InheritanceTest < ActiveRecord::TestCase
end
def test_inheritance_find_all
- companies = Company.find(:all, :order => 'id')
+ companies = Company.scoped(:order => 'id').all
assert_kind_of Firm, companies[0], "37signals should be a firm"
assert_kind_of Client, companies[1], "Summit should be a client"
end
@@ -149,9 +149,9 @@ class InheritanceTest < ActiveRecord::TestCase
def test_update_all_within_inheritance
Client.update_all "name = 'I am a client'"
- assert_equal "I am a client", Client.find(:all).first.name
+ assert_equal "I am a client", Client.all.first.name
# Order by added as otherwise Oracle tests were failing because of different order of results
- assert_equal "37signals", Firm.find(:all, :order => "id").first.name
+ assert_equal "37signals", Firm.scoped(:order => "id").all.first.name
end
def test_alt_update_all_within_inheritance
@@ -173,9 +173,9 @@ class InheritanceTest < ActiveRecord::TestCase
end
def test_find_first_within_inheritance
- assert_kind_of Firm, Company.find(:first, :conditions => "name = '37signals'")
- assert_kind_of Firm, Firm.find(:first, :conditions => "name = '37signals'")
- assert_nil Client.find(:first, :conditions => "name = '37signals'")
+ assert_kind_of Firm, Company.scoped(:where => "name = '37signals'").first
+ assert_kind_of Firm, Firm.scoped(:where => "name = '37signals'").first
+ assert_nil Client.scoped(:where => "name = '37signals'").first
end
def test_alt_find_first_within_inheritance
@@ -187,10 +187,10 @@ class InheritanceTest < ActiveRecord::TestCase
def test_complex_inheritance
very_special_client = VerySpecialClient.create("name" => "veryspecial")
assert_equal very_special_client, VerySpecialClient.where("name = 'veryspecial'").first
- assert_equal very_special_client, SpecialClient.find(:first, :conditions => "name = 'veryspecial'")
- assert_equal very_special_client, Company.find(:first, :conditions => "name = 'veryspecial'")
- assert_equal very_special_client, Client.find(:first, :conditions => "name = 'veryspecial'")
- assert_equal 1, Client.find(:all, :conditions => "name = 'Summit'").size
+ assert_equal very_special_client, SpecialClient.scoped(:where => "name = 'veryspecial'").first
+ assert_equal very_special_client, Company.scoped(:where => "name = 'veryspecial'").first
+ assert_equal very_special_client, Client.scoped(:where => "name = 'veryspecial'").first
+ assert_equal 1, Client.scoped(:where => "name = 'Summit'").all.size
assert_equal very_special_client, Client.find(very_special_client.id)
end
@@ -201,14 +201,14 @@ class InheritanceTest < ActiveRecord::TestCase
end
def test_eager_load_belongs_to_something_inherited
- account = Account.find(1, :include => :firm)
+ account = Account.scoped(:includes => :firm).find(1)
assert account.association_cache.key?(:firm), "nil proves eager load failed"
end
def test_eager_load_belongs_to_primary_key_quoting
con = Account.connection
assert_sql(/#{con.quote_table_name('companies')}.#{con.quote_column_name('id')} IN \(1\)/) do
- Account.find(1, :include => :firm)
+ Account.scoped(:includes => :firm).find(1)
end
end
@@ -230,7 +230,7 @@ class InheritanceTest < ActiveRecord::TestCase
private
def switch_to_alt_inheritance_column
# we don't want misleading test results, so get rid of the values in the type column
- Company.find(:all, :order => 'id').each do |c|
+ Company.scoped(:order => 'id').all.each do |c|
c['type'] = nil
c.save
end
@@ -259,7 +259,7 @@ class InheritanceComputeTypeTest < ActiveRecord::TestCase
def test_instantiation_doesnt_try_to_require_corresponding_file
ActiveRecord::Base.store_full_sti_class = false
- foo = Firm.find(:first).clone
+ foo = Firm.first.clone
foo.ruby_type = foo.type = 'FirmOnTheFly'
foo.save!
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index cc6baa6153..ee180e4154 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -323,7 +323,7 @@ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase
def counter_test(model, expected_count)
add_counter_column_to(model)
- object = model.find(:first)
+ object = model.first
assert_equal 0, object.test_count
assert_equal 0, object.send(model.locking_column)
yield object.id
@@ -363,17 +363,6 @@ unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter) || in_memory_db?
end
end
- # Test scoped lock.
- def test_sane_find_with_scoped_lock
- assert_nothing_raised do
- Person.transaction do
- Person.send(:with_scope, :find => { :lock => true }) do
- Person.find 1
- end
- end
- end
- end
-
# PostgreSQL protests SELECT ... FOR UPDATE on an outer join.
unless current_adapter?(:PostgreSQLAdapter)
# Test locked eager find.
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
deleted file mode 100644
index ebf6e26385..0000000000
--- a/activerecord/test/cases/method_scoping_test.rb
+++ /dev/null
@@ -1,558 +0,0 @@
-# This file can be removed once with_exclusive_scope and with_scope are removed.
-# All the tests were already ported to relation_scoping_test.rb when the new
-# relation scoping API was added.
-
-require "cases/helper"
-require 'models/post'
-require 'models/author'
-require 'models/developer'
-require 'models/project'
-require 'models/comment'
-
-class MethodScopingTest < ActiveRecord::TestCase
- fixtures :authors, :developers, :projects, :comments, :posts, :developers_projects
-
- def test_set_conditions
- Developer.send(:with_scope, :find => { :conditions => 'just a test...' }) do
- assert_match '(just a test...)', Developer.scoped.to_sql
- end
- end
-
- def test_scoped_find
- Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
- assert_nothing_raised { Developer.find(1) }
- end
- end
-
- def test_scoped_find_first
- Developer.send(:with_scope, :find => { :conditions => "salary = 100000" }) do
- assert_equal Developer.find(10), Developer.find(:first, :order => 'name')
- end
- end
-
- def test_scoped_find_last
- highest_salary = Developer.find(:first, :order => "salary DESC")
-
- Developer.send(:with_scope, :find => { :order => "salary" }) do
- assert_equal highest_salary, Developer.last
- end
- end
-
- def test_scoped_find_last_preserves_scope
- lowest_salary = Developer.find(:first, :order => "salary ASC")
- highest_salary = Developer.find(:first, :order => "salary DESC")
-
- Developer.send(:with_scope, :find => { :order => "salary" }) do
- assert_equal highest_salary, Developer.last
- assert_equal lowest_salary, Developer.first
- end
- end
-
- def test_scoped_find_combines_conditions
- Developer.send(:with_scope, :find => { :conditions => "salary = 9000" }) do
- assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => "name = 'Jamis'")
- end
- end
-
- def test_scoped_find_sanitizes_conditions
- Developer.send(:with_scope, :find => { :conditions => ['salary = ?', 9000] }) do
- assert_equal developers(:poor_jamis), Developer.find(:first)
- end
- end
-
- def test_scoped_find_combines_and_sanitizes_conditions
- Developer.send(:with_scope, :find => { :conditions => ['salary = ?', 9000] }) do
- assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => ['name = ?', 'Jamis'])
- end
- end
-
- def test_scoped_find_all
- Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
- assert_equal [developers(:david)], Developer.all
- end
- end
-
- def test_scoped_find_select
- Developer.send(:with_scope, :find => { :select => "id, name" }) do
- developer = Developer.find(:first, :conditions => "name = 'David'")
- assert_equal "David", developer.name
- assert !developer.has_attribute?(:salary)
- end
- end
-
- def test_scope_select_concatenates
- Developer.send(:with_scope, :find => { :select => "name" }) do
- developer = Developer.find(:first, :select => 'id, salary', :conditions => "name = 'David'")
- assert_equal 80000, developer.salary
- assert developer.has_attribute?(:id)
- assert developer.has_attribute?(:name)
- assert developer.has_attribute?(:salary)
- end
- end
-
- def test_scoped_count
- Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
- assert_equal 1, Developer.count
- end
-
- Developer.send(:with_scope, :find => { :conditions => 'salary = 100000' }) do
- assert_equal 8, Developer.count
- assert_equal 1, Developer.count(:conditions => "name LIKE 'fixture_1%'")
- end
- end
-
- def test_scoped_find_include
- # with the include, will retrieve only developers for the given project
- scoped_developers = Developer.send(:with_scope, :find => { :include => :projects }) do
- Developer.find(:all, :conditions => { 'projects.id' => 2 })
- end
- assert scoped_developers.include?(developers(:david))
- assert !scoped_developers.include?(developers(:jamis))
- assert_equal 1, scoped_developers.size
- end
-
- def test_scoped_find_joins
- scoped_developers = Developer.send(:with_scope, :find => { :joins => 'JOIN developers_projects ON id = developer_id' } ) do
- Developer.find(:all, :conditions => 'developers_projects.project_id = 2')
- end
- assert scoped_developers.include?(developers(:david))
- assert !scoped_developers.include?(developers(:jamis))
- assert_equal 1, scoped_developers.size
- assert_equal developers(:david).attributes, scoped_developers.first.attributes
- end
-
- def test_scoped_find_using_new_style_joins
- scoped_developers = Developer.send(:with_scope, :find => { :joins => :projects }) do
- Developer.find(:all, :conditions => 'projects.id = 2')
- end
- assert scoped_developers.include?(developers(:david))
- assert !scoped_developers.include?(developers(:jamis))
- assert_equal 1, scoped_developers.size
- assert_equal developers(:david).attributes, scoped_developers.first.attributes
- end
-
- def test_scoped_find_merges_old_style_joins
- scoped_authors = Author.send(:with_scope, :find => { :joins => 'INNER JOIN posts ON authors.id = posts.author_id ' }) do
- Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'INNER JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1')
- end
- assert scoped_authors.include?(authors(:david))
- assert !scoped_authors.include?(authors(:mary))
- assert_equal 1, scoped_authors.size
- assert_equal authors(:david).attributes, scoped_authors.first.attributes
- end
-
- def test_scoped_find_merges_new_style_joins
- scoped_authors = Author.send(:with_scope, :find => { :joins => :posts }) do
- Author.find(:all, :select => 'DISTINCT authors.*', :joins => :comments, :conditions => 'comments.id = 1')
- end
- assert scoped_authors.include?(authors(:david))
- assert !scoped_authors.include?(authors(:mary))
- assert_equal 1, scoped_authors.size
- assert_equal authors(:david).attributes, scoped_authors.first.attributes
- end
-
- def test_scoped_find_merges_new_and_old_style_joins
- scoped_authors = Author.send(:with_scope, :find => { :joins => :posts }) do
- Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1')
- end
- assert scoped_authors.include?(authors(:david))
- assert !scoped_authors.include?(authors(:mary))
- assert_equal 1, scoped_authors.size
- assert_equal authors(:david).attributes, scoped_authors.first.attributes
- end
-
- def test_scoped_find_merges_string_array_style_and_string_style_joins
- scoped_authors = Author.send(:with_scope, :find => { :joins => ["INNER JOIN posts ON posts.author_id = authors.id"]}) do
- Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'INNER JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1')
- end
- assert scoped_authors.include?(authors(:david))
- assert !scoped_authors.include?(authors(:mary))
- assert_equal 1, scoped_authors.size
- assert_equal authors(:david).attributes, scoped_authors.first.attributes
- end
-
- def test_scoped_find_merges_string_array_style_and_hash_style_joins
- scoped_authors = Author.send(:with_scope, :find => { :joins => :posts}) do
- Author.find(:all, :select => 'DISTINCT authors.*', :joins => ['INNER JOIN comments ON posts.id = comments.post_id'], :conditions => 'comments.id = 1')
- end
- assert scoped_authors.include?(authors(:david))
- assert !scoped_authors.include?(authors(:mary))
- assert_equal 1, scoped_authors.size
- assert_equal authors(:david).attributes, scoped_authors.first.attributes
- end
-
- def test_scoped_find_merges_joins_and_eliminates_duplicate_string_joins
- scoped_authors = Author.send(:with_scope, :find => { :joins => 'INNER JOIN posts ON posts.author_id = authors.id'}) do
- Author.find(:all, :select => 'DISTINCT authors.*', :joins => ["INNER JOIN posts ON posts.author_id = authors.id", "INNER JOIN comments ON posts.id = comments.post_id"], :conditions => 'comments.id = 1')
- end
- assert scoped_authors.include?(authors(:david))
- assert !scoped_authors.include?(authors(:mary))
- assert_equal 1, scoped_authors.size
- assert_equal authors(:david).attributes, scoped_authors.first.attributes
- end
-
- def test_scoped_find_strips_spaces_from_string_joins_and_eliminates_duplicate_string_joins
- scoped_authors = Author.send(:with_scope, :find => { :joins => ' INNER JOIN posts ON posts.author_id = authors.id '}) do
- Author.find(:all, :select => 'DISTINCT authors.*', :joins => ['INNER JOIN posts ON posts.author_id = authors.id'], :conditions => 'posts.id = 1')
- end
- assert scoped_authors.include?(authors(:david))
- assert !scoped_authors.include?(authors(:mary))
- assert_equal 1, scoped_authors.size
- assert_equal authors(:david).attributes, scoped_authors.first.attributes
- end
-
- def test_scoped_count_include
- # with the include, will retrieve only developers for the given project
- Developer.send(:with_scope, :find => { :include => :projects }) do
- assert_equal 1, Developer.count(:conditions => { 'projects.id' => 2 })
- end
- end
-
- def test_scope_for_create_only_uses_equal
- table = VerySpecialComment.arel_table
- relation = VerySpecialComment.scoped
- relation.where_values << table[:id].not_eq(1)
- assert_equal({:type => "VerySpecialComment"}, relation.send(:scope_for_create))
- end
-
- def test_scoped_create
- new_comment = nil
-
- VerySpecialComment.send(:with_scope, :create => { :post_id => 1 }) do
- assert_equal({:post_id => 1, :type => 'VerySpecialComment' }, VerySpecialComment.scoped.send(:scope_for_create))
- new_comment = VerySpecialComment.create :body => "Wonderful world"
- end
-
- assert Post.find(1).comments.include?(new_comment)
- end
-
- def test_scoped_create_with_join_and_merge
- Comment.where(:body => "but Who's Buying?").joins(:post).merge(Post.where(:body => 'Peace Sells...')).with_scope do
- assert_equal({:body => "but Who's Buying?"}, Comment.scoped.scope_for_create)
- end
- end
-
- def test_immutable_scope
- options = { :conditions => "name = 'David'" }
- Developer.send(:with_scope, :find => options) do
- assert_equal %w(David), Developer.all.map(&:name)
- options[:conditions] = "name != 'David'"
- assert_equal %w(David), Developer.all.map(&:name)
- end
-
- scope = { :find => { :conditions => "name = 'David'" }}
- Developer.send(:with_scope, scope) do
- assert_equal %w(David), Developer.all.map(&:name)
- scope[:find][:conditions] = "name != 'David'"
- assert_equal %w(David), Developer.all.map(&:name)
- end
- end
-
- def test_scoped_with_duck_typing
- scoping = Struct.new(:current_scope).new(:find => { :conditions => ["name = ?", 'David'] })
- Developer.send(:with_scope, scoping) do
- assert_equal %w(David), Developer.all.map(&:name)
- end
- end
-
- def test_ensure_that_method_scoping_is_correctly_restored
- begin
- Developer.send(:with_scope, :find => { :conditions => "name = 'Jamis'" }) do
- raise "an exception"
- end
- rescue
- end
-
- assert !Developer.scoped.where_values.include?("name = 'Jamis'")
- end
-end
-
-class NestedScopingTest < ActiveRecord::TestCase
- fixtures :authors, :developers, :projects, :comments, :posts
-
- def test_merge_options
- Developer.send(:with_scope, :find => { :conditions => 'salary = 80000' }) do
- Developer.send(:with_scope, :find => { :limit => 10 }) do
- devs = Developer.scoped
- assert_match '(salary = 80000)', devs.to_sql
- assert_equal 10, devs.taken
- end
- end
- end
-
- def test_merge_inner_scope_has_priority
- Developer.send(:with_scope, :find => { :limit => 5 }) do
- Developer.send(:with_scope, :find => { :limit => 10 }) do
- assert_equal 10, Developer.scoped.taken
- end
- end
- end
-
- def test_replace_options
- Developer.send(:with_scope, :find => { :conditions => {:name => 'David'} }) do
- Developer.send(:with_exclusive_scope, :find => { :conditions => {:name => 'Jamis'} }) do
- assert_equal 'Jamis', Developer.scoped.send(:scope_for_create)[:name]
- end
-
- assert_equal 'David', Developer.scoped.send(:scope_for_create)[:name]
- end
- end
-
- def test_with_exclusive_scope_with_relation
- assert_raise(ArgumentError) do
- Developer.all_johns
- end
- end
-
- def test_append_conditions
- Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
- Developer.send(:with_scope, :find => { :conditions => 'salary = 80000' }) do
- devs = Developer.scoped
- assert_match "(name = 'David') AND (salary = 80000)", devs.to_sql
- assert_equal(1, Developer.count)
- end
- Developer.send(:with_scope, :find => { :conditions => "name = 'Maiha'" }) do
- assert_equal(0, Developer.count)
- end
- end
- end
-
- def test_merge_and_append_options
- Developer.send(:with_scope, :find => { :conditions => 'salary = 80000', :limit => 10 }) do
- Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
- devs = Developer.scoped
- assert_match "(salary = 80000) AND (name = 'David')", devs.to_sql
- assert_equal 10, devs.taken
- end
- end
- end
-
- def test_nested_scoped_find
- Developer.send(:with_scope, :find => { :conditions => "name = 'Jamis'" }) do
- Developer.send(:with_exclusive_scope, :find => { :conditions => "name = 'David'" }) do
- assert_nothing_raised { Developer.find(1) }
- assert_equal('David', Developer.find(:first).name)
- end
- assert_equal('Jamis', Developer.find(:first).name)
- end
- end
-
- def test_nested_scoped_find_include
- Developer.send(:with_scope, :find => { :include => :projects }) do
- Developer.send(:with_scope, :find => { :conditions => { 'projects.id' => 2 } }) do
- assert_nothing_raised { Developer.find(1) }
- assert_equal('David', Developer.find(:first).name)
- end
- end
- end
-
- def test_nested_scoped_find_merged_include
- # :include's remain unique and don't "double up" when merging
- Developer.send(:with_scope, :find => { :include => :projects, :conditions => { 'projects.id' => 2 } }) do
- Developer.send(:with_scope, :find => { :include => :projects }) do
- assert_equal 1, Developer.scoped.includes_values.uniq.length
- assert_equal 'David', Developer.find(:first).name
- end
- end
-
- # the nested scope doesn't remove the first :include
- Developer.send(:with_scope, :find => { :include => :projects, :conditions => { 'projects.id' => 2 } }) do
- Developer.send(:with_scope, :find => { :include => [] }) do
- assert_equal 1, Developer.scoped.includes_values.uniq.length
- assert_equal('David', Developer.find(:first).name)
- end
- end
-
- # mixing array and symbol include's will merge correctly
- Developer.send(:with_scope, :find => { :include => [:projects], :conditions => { 'projects.id' => 2 } }) do
- Developer.send(:with_scope, :find => { :include => :projects }) do
- assert_equal 1, Developer.scoped.includes_values.uniq.length
- assert_equal('David', Developer.find(:first).name)
- end
- end
- end
-
- def test_nested_scoped_find_replace_include
- Developer.send(:with_scope, :find => { :include => :projects }) do
- Developer.send(:with_exclusive_scope, :find => { :include => [] }) do
- assert_equal 0, Developer.scoped.includes_values.length
- end
- end
- end
-
- def test_three_level_nested_exclusive_scoped_find
- Developer.send(:with_scope, :find => { :conditions => "name = 'Jamis'" }) do
- assert_equal('Jamis', Developer.find(:first).name)
-
- Developer.send(:with_exclusive_scope, :find => { :conditions => "name = 'David'" }) do
- assert_equal('David', Developer.find(:first).name)
-
- Developer.send(:with_exclusive_scope, :find => { :conditions => "name = 'Maiha'" }) do
- assert_equal(nil, Developer.find(:first))
- end
-
- # ensure that scoping is restored
- assert_equal('David', Developer.find(:first).name)
- end
-
- # ensure that scoping is restored
- assert_equal('Jamis', Developer.find(:first).name)
- end
- end
-
- def test_merged_scoped_find
- poor_jamis = developers(:poor_jamis)
- Developer.send(:with_scope, :find => { :conditions => "salary < 100000" }) do
- Developer.send(:with_scope, :find => { :offset => 1, :order => 'id asc' }) do
- # Oracle adapter does not generated space after asc therefore trailing space removed from regex
- assert_sql(/ORDER BY\s+id asc/) do
- assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc'))
- end
- end
- end
- end
-
- def test_merged_scoped_find_sanitizes_conditions
- Developer.send(:with_scope, :find => { :conditions => ["name = ?", 'David'] }) do
- Developer.send(:with_scope, :find => { :conditions => ['salary = ?', 9000] }) do
- assert_raise(ActiveRecord::RecordNotFound) { developers(:poor_jamis) }
- end
- end
- end
-
- def test_nested_scoped_find_combines_and_sanitizes_conditions
- Developer.send(:with_scope, :find => { :conditions => ["name = ?", 'David'] }) do
- Developer.send(:with_exclusive_scope, :find => { :conditions => ['salary = ?', 9000] }) do
- assert_equal developers(:poor_jamis), Developer.find(:first)
- assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => ['name = ?', 'Jamis'])
- end
- end
- end
-
- def test_merged_scoped_find_combines_and_sanitizes_conditions
- Developer.send(:with_scope, :find => { :conditions => ["name = ?", 'David'] }) do
- Developer.send(:with_scope, :find => { :conditions => ['salary > ?', 9000] }) do
- assert_equal %w(David), Developer.all.map(&:name)
- end
- end
- end
-
- def test_nested_scoped_create
- comment = nil
- Comment.send(:with_scope, :create => { :post_id => 1}) do
- Comment.send(:with_scope, :create => { :post_id => 2}) do
- assert_equal({:post_id => 2}, Comment.scoped.send(:scope_for_create))
- comment = Comment.create :body => "Hey guys, nested scopes are broken. Please fix!"
- end
- end
- assert_equal 2, comment.post_id
- end
-
- def test_nested_exclusive_scope_for_create
- comment = nil
-
- Comment.send(:with_scope, :create => { :body => "Hey guys, nested scopes are broken. Please fix!" }) do
- Comment.send(:with_exclusive_scope, :create => { :post_id => 1 }) do
- assert_equal({:post_id => 1}, Comment.scoped.send(:scope_for_create))
- assert_blank Comment.new.body
- comment = Comment.create :body => "Hey guys"
- end
- end
- assert_equal 1, comment.post_id
- assert_equal 'Hey guys', comment.body
- end
-
- def test_merged_scoped_find_on_blank_conditions
- [nil, " ", [], {}].each do |blank|
- Developer.send(:with_scope, :find => {:conditions => blank}) do
- Developer.send(:with_scope, :find => {:conditions => blank}) do
- assert_nothing_raised { Developer.find(:first) }
- end
- end
- end
- end
-
- def test_merged_scoped_find_on_blank_bind_conditions
- [ [""], ["",{}] ].each do |blank|
- Developer.send(:with_scope, :find => {:conditions => blank}) do
- Developer.send(:with_scope, :find => {:conditions => blank}) do
- assert_nothing_raised { Developer.find(:first) }
- end
- end
- end
- end
-
- def test_immutable_nested_scope
- options1 = { :conditions => "name = 'Jamis'" }
- options2 = { :conditions => "name = 'David'" }
- Developer.send(:with_scope, :find => options1) do
- Developer.send(:with_exclusive_scope, :find => options2) do
- assert_equal %w(David), Developer.all.map(&:name)
- options1[:conditions] = options2[:conditions] = nil
- assert_equal %w(David), Developer.all.map(&:name)
- end
- end
- end
-
- def test_immutable_merged_scope
- options1 = { :conditions => "name = 'Jamis'" }
- options2 = { :conditions => "salary > 10000" }
- Developer.send(:with_scope, :find => options1) do
- Developer.send(:with_scope, :find => options2) do
- assert_equal %w(Jamis), Developer.all.map(&:name)
- options1[:conditions] = options2[:conditions] = nil
- assert_equal %w(Jamis), Developer.all.map(&:name)
- end
- end
- end
-
- def test_ensure_that_method_scoping_is_correctly_restored
- Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
- begin
- Developer.send(:with_scope, :find => { :conditions => "name = 'Maiha'" }) do
- raise "an exception"
- end
- rescue
- end
-
- assert Developer.scoped.where_values.include?("name = 'David'")
- assert !Developer.scoped.where_values.include?("name = 'Maiha'")
- end
- end
-
- def test_nested_scoped_find_merges_old_style_joins
- scoped_authors = Author.send(:with_scope, :find => { :joins => 'INNER JOIN posts ON authors.id = posts.author_id' }) do
- Author.send(:with_scope, :find => { :joins => 'INNER JOIN comments ON posts.id = comments.post_id' }) do
- Author.find(:all, :select => 'DISTINCT authors.*', :conditions => 'comments.id = 1')
- end
- end
- assert scoped_authors.include?(authors(:david))
- assert !scoped_authors.include?(authors(:mary))
- assert_equal 1, scoped_authors.size
- assert_equal authors(:david).attributes, scoped_authors.first.attributes
- end
-
- def test_nested_scoped_find_merges_new_style_joins
- scoped_authors = Author.send(:with_scope, :find => { :joins => :posts }) do
- Author.send(:with_scope, :find => { :joins => :comments }) do
- Author.find(:all, :select => 'DISTINCT authors.*', :conditions => 'comments.id = 1')
- end
- end
- assert scoped_authors.include?(authors(:david))
- assert !scoped_authors.include?(authors(:mary))
- assert_equal 1, scoped_authors.size
- assert_equal authors(:david).attributes, scoped_authors.first.attributes
- end
-
- def test_nested_scoped_find_merges_new_and_old_style_joins
- scoped_authors = Author.send(:with_scope, :find => { :joins => :posts }) do
- Author.send(:with_scope, :find => { :joins => 'INNER JOIN comments ON posts.id = comments.post_id' }) do
- Author.find(:all, :select => 'DISTINCT authors.*', :joins => '', :conditions => 'comments.id = 1')
- end
- end
- assert scoped_authors.include?(authors(:david))
- assert !scoped_authors.include?(authors(:mary))
- assert_equal 1, scoped_authors.size
- assert_equal authors(:david).attributes, scoped_authors.first.attributes
- end
-end
diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb
index 040445ef12..409a558f5c 100644
--- a/activerecord/test/cases/migration/column_attributes_test.rb
+++ b/activerecord/test/cases/migration/column_attributes_test.rb
@@ -64,7 +64,7 @@ module ActiveRecord
end
# SELECT
- row = TestModel.find(:first)
+ row = TestModel.first
assert_kind_of BigDecimal, row.wealth
# If this assert fails, that means the SELECT is broken!
@@ -79,7 +79,7 @@ module ActiveRecord
TestModel.create :wealth => BigDecimal.new("12345678901234567890.0123456789")
# SELECT
- row = TestModel.find(:first)
+ row = TestModel.first
assert_kind_of BigDecimal, row.wealth
# If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken!
@@ -132,7 +132,7 @@ module ActiveRecord
:birthday => 18.years.ago, :favorite_day => 10.days.ago,
:moment_of_truth => "1782-10-10 21:40:18", :male => true
- bob = TestModel.find(:first)
+ bob = TestModel.first
assert_equal 'bob', bob.first_name
assert_equal 'bobsen', bob.last_name
assert_equal "I was born ....", bob.bio
diff --git a/activerecord/test/cases/migration/references_index_test.rb b/activerecord/test/cases/migration/references_index_test.rb
new file mode 100644
index 0000000000..8ab1c59724
--- /dev/null
+++ b/activerecord/test/cases/migration/references_index_test.rb
@@ -0,0 +1,99 @@
+require 'cases/helper'
+
+module ActiveRecord
+ class Migration
+ class ReferencesIndexTest < ActiveRecord::TestCase
+ attr_reader :connection, :table_name
+
+ def setup
+ super
+ @connection = ActiveRecord::Base.connection
+ @table_name = :testings
+ end
+
+ def teardown
+ super
+ connection.drop_table :testings rescue nil
+ end
+
+ def test_creates_index
+ connection.create_table table_name do |t|
+ t.references :foo, :index => true
+ end
+
+ assert connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id)
+ end
+
+ def test_does_not_create_index
+ connection.create_table table_name do |t|
+ t.references :foo
+ end
+
+ refute connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id)
+ end
+
+ def test_does_not_create_index_explicit
+ connection.create_table table_name do |t|
+ t.references :foo, :index => false
+ end
+
+ refute connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id)
+ end
+
+ def test_creates_index_with_options
+ connection.create_table table_name do |t|
+ t.references :foo, :index => {:name => :index_testings_on_yo_momma}
+ t.references :bar, :index => {:unique => true}
+ end
+
+ assert connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_yo_momma)
+ assert connection.index_exists?(table_name, :bar_id, :name => :index_testings_on_bar_id, :unique => true)
+ end
+
+ def test_creates_polymorphic_index
+ connection.create_table table_name do |t|
+ t.references :foo, :polymorphic => true, :index => true
+ end
+
+ assert connection.index_exists?(table_name, [:foo_id, :foo_type], :name => :index_testings_on_foo_id_and_foo_type)
+ end
+
+ def test_creates_index_for_existing_table
+ connection.create_table table_name
+ connection.change_table table_name do |t|
+ t.references :foo, :index => true
+ end
+
+ assert connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id)
+ end
+
+ def test_does_not_create_index_for_existing_table
+ connection.create_table table_name
+ connection.change_table table_name do |t|
+ t.references :foo
+ end
+
+ refute connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id)
+ end
+
+ def test_does_not_create_index_for_existing_table_explicit
+ connection.create_table table_name
+ connection.change_table table_name do |t|
+ t.references :foo, :index => false
+ end
+
+ refute connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id)
+ end
+
+ def test_creates_polymorphic_index_for_existing_table
+ connection.create_table table_name
+ connection.change_table table_name do |t|
+ t.references :foo, :polymorphic => true, :index => true
+ end
+
+ assert connection.index_exists?(table_name, [:foo_id, :foo_type], :name => :index_testings_on_foo_id_and_foo_type)
+ end
+
+ end
+ end
+end
diff --git a/activerecord/test/cases/migration/rename_column_test.rb b/activerecord/test/cases/migration/rename_column_test.rb
index 16e09fd80e..d1a85ee5e4 100644
--- a/activerecord/test/cases/migration/rename_column_test.rb
+++ b/activerecord/test/cases/migration/rename_column_test.rb
@@ -18,7 +18,7 @@ module ActiveRecord
rename_column "test_models", "girlfriend", "exgirlfriend"
TestModel.reset_column_information
- bob = TestModel.find(:first)
+ bob = TestModel.first
assert_equal "bobette", bob.exgirlfriend
end
@@ -33,7 +33,7 @@ module ActiveRecord
rename_column :test_models, :first_name, :nick_name
TestModel.reset_column_information
assert TestModel.column_names.include?("nick_name")
- assert_equal ['foo'], TestModel.find(:all).map(&:nick_name)
+ assert_equal ['foo'], TestModel.all.map(&:nick_name)
end
# FIXME: another integration test. We should decouple this from the
@@ -46,7 +46,7 @@ module ActiveRecord
rename_column "test_models", "first_name", "nick_name"
TestModel.reset_column_information
assert TestModel.column_names.include?("nick_name")
- assert_equal ['foo'], TestModel.find(:all).map(&:nick_name)
+ assert_equal ['foo'], TestModel.all.map(&:nick_name)
end
def test_rename_column_preserves_default_value_not_null
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 92dc150104..e71b84a3a5 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -36,7 +36,7 @@ class MigrationTest < ActiveRecord::TestCase
ActiveRecord::Base.connection.initialize_schema_migrations_table
ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}"
- %w(things awesome_things prefix_things_suffix prefix_awesome_things_suffix).each do |table|
+ %w(things awesome_things prefix_things_suffix p_awesome_things_s ).each do |table|
Thing.connection.drop_table(table) rescue nil
end
Thing.reset_column_information
@@ -109,7 +109,7 @@ class MigrationTest < ActiveRecord::TestCase
:value_of_e => BigDecimal("2.7182818284590452353602875")
)
- b = BigNumber.find(:first)
+ b = BigNumber.first
assert_not_nil b
assert_not_nil b.bank_balance
@@ -153,7 +153,7 @@ class MigrationTest < ActiveRecord::TestCase
end
GiveMeBigNumbers.down
- assert_raise(ActiveRecord::StatementInvalid) { BigNumber.find(:first) }
+ assert_raise(ActiveRecord::StatementInvalid) { BigNumber.first }
end
def test_filtering_migrations
@@ -165,13 +165,13 @@ class MigrationTest < ActiveRecord::TestCase
Person.reset_column_information
assert Person.column_methods_hash.include?(:last_name)
- assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", &name_filter)
Person.reset_column_information
assert !Person.column_methods_hash.include?(:last_name)
- assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
end
class MockMigration < ActiveRecord::Migration
@@ -278,19 +278,19 @@ class MigrationTest < ActiveRecord::TestCase
def test_rename_table_with_prefix_and_suffix
assert !Thing.table_exists?
- ActiveRecord::Base.table_name_prefix = 'prefix_'
- ActiveRecord::Base.table_name_suffix = '_suffix'
+ ActiveRecord::Base.table_name_prefix = 'p_'
+ ActiveRecord::Base.table_name_suffix = '_s'
Thing.reset_table_name
Thing.reset_sequence_name
WeNeedThings.up
assert Thing.create("content" => "hello world")
- assert_equal "hello world", Thing.find(:first).content
+ assert_equal "hello world", Thing.first.content
RenameThings.up
- Thing.table_name = "prefix_awesome_things_suffix"
+ Thing.table_name = "p_awesome_things_s"
- assert_equal "hello world", Thing.find(:first).content
+ assert_equal "hello world", Thing.first.content
ensure
ActiveRecord::Base.table_name_prefix = ''
ActiveRecord::Base.table_name_suffix = ''
@@ -306,10 +306,10 @@ class MigrationTest < ActiveRecord::TestCase
Reminder.reset_sequence_name
WeNeedReminders.up
assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
- assert_equal "hello world", Reminder.find(:first).content
+ assert_equal "hello world", Reminder.first.content
WeNeedReminders.down
- assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
ensure
ActiveRecord::Base.table_name_prefix = ''
ActiveRecord::Base.table_name_suffix = ''
@@ -404,6 +404,7 @@ end
class ChangeTableMigrationsTest < ActiveRecord::TestCase
def setup
@connection = Person.connection
+ @connection.stubs(:add_index)
@connection.create_table :delete_me, :force => true do |t|
end
end
diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb
index f7a5d05582..a03c4f552e 100644
--- a/activerecord/test/cases/modules_test.rb
+++ b/activerecord/test/cases/modules_test.rb
@@ -27,19 +27,19 @@ class ModulesTest < ActiveRecord::TestCase
end
def test_module_spanning_associations
- firm = MyApplication::Business::Firm.find(:first)
+ firm = MyApplication::Business::Firm.first
assert !firm.clients.empty?, "Firm should have clients"
assert_nil firm.class.table_name.match('::'), "Firm shouldn't have the module appear in its table name"
end
def test_module_spanning_has_and_belongs_to_many_associations
- project = MyApplication::Business::Project.find(:first)
+ project = MyApplication::Business::Project.first
project.developers << MyApplication::Business::Developer.create("name" => "John")
assert_equal "John", project.developers.last.name
end
def test_associations_spanning_cross_modules
- account = MyApplication::Billing::Account.find(:first, :order => 'id')
+ account = MyApplication::Billing::Account.scoped(:order => 'id').first
assert_kind_of MyApplication::Business::Firm, account.firm
assert_kind_of MyApplication::Billing::Firm, account.qualified_billing_firm
assert_kind_of MyApplication::Billing::Firm, account.unqualified_billing_firm
@@ -48,7 +48,7 @@ class ModulesTest < ActiveRecord::TestCase
end
def test_find_account_and_include_company
- account = MyApplication::Billing::Account.find(1, :include => :firm)
+ account = MyApplication::Billing::Account.scoped(:includes => :firm).find(1)
assert_kind_of MyApplication::Business::Firm, account.firm
end
@@ -72,8 +72,8 @@ class ModulesTest < ActiveRecord::TestCase
clients = []
assert_nothing_raised NameError, "Should be able to resolve all class constants via reflection" do
- clients << MyApplication::Business::Client.find(3, :include => {:firm => :account}, :conditions => 'accounts.id IS NOT NULL', :references => :accounts)
- clients << MyApplication::Business::Client.find(3, :include => {:firm => :account})
+ clients << MyApplication::Business::Client.references(:accounts).scoped(:includes => {:firm => :account}, :where => 'accounts.id IS NOT NULL').find(3)
+ clients << MyApplication::Business::Client.scoped(:includes => {:firm => :account}).find(3)
end
clients.each do |client|
@@ -123,7 +123,7 @@ class ModulesTest < ActiveRecord::TestCase
old = ActiveRecord::Base.store_full_sti_class
ActiveRecord::Base.store_full_sti_class = true
- collection = Shop::Collection.find(:first)
+ collection = Shop::Collection.first
assert !collection.products.empty?, "Collection should have products"
assert_nothing_raised { collection.destroy }
ensure
@@ -134,7 +134,7 @@ class ModulesTest < ActiveRecord::TestCase
old = ActiveRecord::Base.store_full_sti_class
ActiveRecord::Base.store_full_sti_class = true
- product = Shop::Product.find(:first)
+ product = Shop::Product.first
assert !product.variants.empty?, "Product should have variants"
assert_nothing_raised { product.destroy }
ensure
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index 0d3c0b20a4..f8557259fb 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -10,12 +10,12 @@ class NamedScopeTest < ActiveRecord::TestCase
fixtures :posts, :authors, :topics, :comments, :author_addresses
def test_implements_enumerable
- assert !Topic.find(:all).empty?
+ assert !Topic.all.empty?
- assert_equal Topic.find(:all), Topic.base
- assert_equal Topic.find(:all), Topic.base.to_a
- assert_equal Topic.find(:first), Topic.base.first
- assert_equal Topic.find(:all), Topic.base.map { |i| i }
+ assert_equal Topic.all, Topic.base
+ assert_equal Topic.all, Topic.base.to_a
+ assert_equal Topic.first, Topic.base.first
+ assert_equal Topic.all, Topic.base.map { |i| i }
end
def test_found_items_are_cached
@@ -38,10 +38,10 @@ class NamedScopeTest < ActiveRecord::TestCase
end
def test_delegates_finds_and_calculations_to_the_base_class
- assert !Topic.find(:all).empty?
+ assert !Topic.all.empty?
- assert_equal Topic.find(:all), Topic.base.find(:all)
- assert_equal Topic.find(:first), Topic.base.find(:first)
+ assert_equal Topic.all, Topic.base.all
+ assert_equal Topic.first, Topic.base.first
assert_equal Topic.count, Topic.base.count
assert_equal Topic.average(:replies_count), Topic.base.average(:replies_count)
end
@@ -58,10 +58,10 @@ class NamedScopeTest < ActiveRecord::TestCase
end
def test_scopes_with_options_limit_finds_to_those_matching_the_criteria_specified
- assert !Topic.find(:all, :conditions => {:approved => true}).empty?
+ assert !Topic.scoped(:where => {:approved => true}).all.empty?
- assert_equal Topic.find(:all, :conditions => {:approved => true}), Topic.approved
- assert_equal Topic.count(:conditions => {:approved => true}), Topic.approved.count
+ assert_equal Topic.scoped(:where => {:approved => true}).all, Topic.approved
+ assert_equal Topic.where(:approved => true).count, Topic.approved.count
end
def test_scopes_with_string_name_can_be_composed
@@ -70,13 +70,9 @@ class NamedScopeTest < ActiveRecord::TestCase
assert_equal Topic.replied.approved, Topic.replied.approved_as_string
end
- def test_scopes_can_be_specified_with_deep_hash_conditions
- assert_equal Topic.replied.approved, Topic.replied.approved_as_hash_condition
- end
-
def test_scopes_are_composable
- assert_equal((approved = Topic.find(:all, :conditions => {:approved => true})), Topic.approved)
- assert_equal((replied = Topic.find(:all, :conditions => 'replies_count > 0')), Topic.replied)
+ assert_equal((approved = Topic.scoped(:where => {:approved => true}).all), Topic.approved)
+ assert_equal((replied = Topic.scoped(:where => 'replies_count > 0').all), Topic.replied)
assert !(approved == replied)
assert !(approved & replied).empty?
@@ -84,8 +80,8 @@ class NamedScopeTest < ActiveRecord::TestCase
end
def test_procedural_scopes
- topics_written_before_the_third = Topic.find(:all, :conditions => ['written_on < ?', topics(:third).written_on])
- topics_written_before_the_second = Topic.find(:all, :conditions => ['written_on < ?', topics(:second).written_on])
+ topics_written_before_the_third = Topic.where('written_on < ?', topics(:third).written_on)
+ topics_written_before_the_second = Topic.where('written_on < ?', topics(:second).written_on)
assert_not_equal topics_written_before_the_second, topics_written_before_the_third
assert_equal topics_written_before_the_third, Topic.written_before(topics(:third).written_on)
@@ -93,30 +89,11 @@ class NamedScopeTest < ActiveRecord::TestCase
end
def test_procedural_scopes_returning_nil
- all_topics = Topic.find(:all)
+ all_topics = Topic.all
assert_equal all_topics, Topic.written_before(nil)
end
- def test_scopes_with_joins
- address = author_addresses(:david_address)
- posts_with_authors_at_address = Post.find(
- :all, :joins => 'JOIN authors ON authors.id = posts.author_id',
- :conditions => [ 'authors.author_address_id = ?', address.id ]
- )
- assert_equal posts_with_authors_at_address, Post.with_authors_at_address(address)
- end
-
- def test_scopes_with_joins_respects_custom_select
- address = author_addresses(:david_address)
- posts_with_authors_at_address_titles = Post.find(:all,
- :select => 'title',
- :joins => 'JOIN authors ON authors.id = posts.author_id',
- :conditions => [ 'authors.author_address_id = ?', address.id ]
- )
- assert_equal posts_with_authors_at_address_titles.map(&:title), Post.with_authors_at_address(address).find(:all, :select => 'title').map(&:title)
- end
-
def test_scope_with_object
objects = Topic.with_object
assert_operator objects.length, :>, 0
@@ -153,20 +130,16 @@ class NamedScopeTest < ActiveRecord::TestCase
end
def test_active_records_have_scope_named__all__
- assert !Topic.find(:all).empty?
+ assert !Topic.all.empty?
- assert_equal Topic.find(:all), Topic.base
+ assert_equal Topic.all, Topic.base
end
def test_active_records_have_scope_named__scoped__
- assert !Topic.find(:all, scope = {:conditions => "content LIKE '%Have%'"}).empty?
+ scope = Topic.where("content LIKE '%Have%'")
+ assert !scope.empty?
- assert_equal Topic.find(:all, scope), Topic.scoped(scope)
- end
-
- def test_first_and_last_should_support_find_options
- assert_equal Topic.base.first(:order => 'title'), Topic.base.find(:first, :order => 'title')
- assert_equal Topic.base.last(:order => 'title'), Topic.base.find(:last, :order => 'title')
+ assert_equal scope, Topic.scoped(where: "content LIKE '%Have%'")
end
def test_first_and_last_should_allow_integers_for_limit
@@ -183,15 +156,6 @@ class NamedScopeTest < ActiveRecord::TestCase
end
end
- def test_first_and_last_find_options_should_use_query_when_results_are_loaded
- topics = Topic.base
- topics.reload # force load
- assert_queries(2) do
- topics.first(:order => 'title')
- topics.last(:order => 'title')
- end
- end
-
def test_empty_should_not_load_results
topics = Topic.base
assert_queries(2) do
@@ -254,9 +218,9 @@ class NamedScopeTest < ActiveRecord::TestCase
end
def test_many_should_return_false_if_none_or_one
- topics = Topic.base.scoped(:conditions => {:id => 0})
+ topics = Topic.base.where(:id => 0)
assert !topics.many?
- topics = Topic.base.scoped(:conditions => {:id => 1})
+ topics = Topic.base.where(:id => 1)
assert !topics.many?
end
@@ -334,7 +298,7 @@ class NamedScopeTest < ActiveRecord::TestCase
def test_chaining_with_duplicate_joins
join = "INNER JOIN comments ON comments.post_id = posts.id"
post = Post.find(1)
- assert_equal post.comments.size, Post.scoped(:joins => join).scoped(:joins => join, :conditions => "posts.id = #{post.id}").size
+ assert_equal post.comments.size, Post.joins(join).joins(join).where("posts.id = #{post.id}").size
end
def test_chaining_should_use_latest_conditions_when_creating
@@ -460,26 +424,11 @@ class NamedScopeTest < ActiveRecord::TestCase
klass.table_name = 'posts'
assert_deprecated do
- klass.scope :welcome, { :conditions => { :id => posts(:welcome).id } }
- end
- assert_equal [posts(:welcome).title], klass.welcome.map(&:title)
-
- assert_deprecated do
klass.scope :welcome_2, klass.where(:id => posts(:welcome).id)
end
assert_equal [posts(:welcome).title], klass.welcome_2.map(&:title)
end
- def test_eager_default_scope_hashes_are_deprecated
- klass = Class.new(ActiveRecord::Base)
- klass.table_name = 'posts'
-
- assert_deprecated do
- klass.send(:default_scope, :conditions => { :id => posts(:welcome).id })
- end
- assert_equal [posts(:welcome).title], klass.all.map(&:title)
- end
-
def test_eager_default_scope_relations_are_deprecated
klass = Class.new(ActiveRecord::Base)
klass.table_name = 'posts'
@@ -515,7 +464,7 @@ class DynamicScopeTest < ActiveRecord::TestCase
def test_dynamic_scope
assert_equal @test_klass.scoped_by_author_id(1).find(1), @test_klass.find(1)
- assert_equal @test_klass.scoped_by_author_id_and_title(1, "Welcome to the weblog").first, @test_klass.find(:first, :conditions => { :author_id => 1, :title => "Welcome to the weblog"})
+ assert_equal @test_klass.scoped_by_author_id_and_title(1, "Welcome to the weblog").first, @test_klass.scoped(:where => { :author_id => 1, :title => "Welcome to the weblog"}).first
end
def test_dynamic_scope_should_create_methods_after_hitting_method_missing
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index adfd8e83a1..3bc59560f0 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -13,12 +13,14 @@ require 'models/warehouse_thing'
require 'models/parrot'
require 'models/minivan'
require 'models/person'
+require 'models/pet'
+require 'models/toy'
require 'rexml/document'
require 'active_support/core_ext/exception'
class PersistencesTest < ActiveRecord::TestCase
- fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts, :minivans
+ fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts, :minivans, :pets, :toys
# Oracle UPDATE does not support ORDER BY
unless current_adapter?(:OracleAdapter)
@@ -53,7 +55,7 @@ class PersistencesTest < ActiveRecord::TestCase
author = authors(:david)
assert_nothing_raised do
assert_equal 1, author.posts_sorted_by_id_limited.size
- assert_equal 2, author.posts_sorted_by_id_limited.find(:all, :limit => 2).size
+ assert_equal 2, author.posts_sorted_by_id_limited.scoped(:limit => 2).all.size
assert_equal 1, author.posts_sorted_by_id_limited.update_all([ "body = ?", "bulk update!" ])
assert_equal "bulk update!", posts(:welcome).body
assert_not_equal "bulk update!", posts(:thinking).body
@@ -76,10 +78,20 @@ class PersistencesTest < ActiveRecord::TestCase
assert_equal Topic.count, Topic.delete_all
end
- def test_update_by_condition
- Topic.update_all "content = 'bulk updated!'", ["approved = ?", true]
- assert_equal "Have a nice day", Topic.find(1).content
- assert_equal "bulk updated!", Topic.find(2).content
+ def test_delete_all_with_joins_and_where_part_is_hash
+ where_args = {:toys => {:name => 'Bone'}}
+ count = Pet.joins(:toys).where(where_args).count
+
+ assert_equal count, 1
+ assert_equal count, Pet.joins(:toys).where(where_args).delete_all
+ end
+
+ def test_delete_all_with_joins_and_where_part_is_not_hash
+ where_args = ['toys.name = ?', 'Bone']
+ count = Pet.joins(:toys).where(where_args).count
+
+ assert_equal count, 1
+ assert_equal count, Pet.joins(:toys).where(where_args).delete_all
end
def test_increment_attribute
@@ -108,7 +120,7 @@ class PersistencesTest < ActiveRecord::TestCase
def test_destroy_all
conditions = "author_name = 'Mary'"
- topics_by_mary = Topic.all(:conditions => conditions, :order => 'id')
+ topics_by_mary = Topic.scoped(:where => conditions, :order => 'id').to_a
assert ! topics_by_mary.empty?
assert_difference('Topic.count', -topics_by_mary.size) do
@@ -119,7 +131,7 @@ class PersistencesTest < ActiveRecord::TestCase
end
def test_destroy_many
- clients = Client.find([2, 3], :order => 'id')
+ clients = Client.scoped(:order => 'id').find([2, 3])
assert_difference('Client.count', -2) do
destroyed = Client.destroy([2, 3]).sort_by(&:id)
@@ -320,7 +332,7 @@ class PersistencesTest < ActiveRecord::TestCase
end
def test_update_all_with_non_standard_table_name
- assert_equal 1, WarehouseThing.update_all(['value = ?', 0], ['id = ?', 1])
+ assert_equal 1, WarehouseThing.where(id: 1).update_all(['value = ?', 0])
assert_equal 0, WarehouseThing.find(1).value
end
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index d93478513b..a712e5f689 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -96,7 +96,7 @@ class QueryCacheTest < ActiveRecord::TestCase
def test_cache_clear_after_close
mw = ActiveRecord::QueryCache.new lambda { |env|
- Post.find(:first)
+ Post.first
[200, {}, nil]
}
body = mw.call({}).last
@@ -233,8 +233,8 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
def test_cache_is_expired_by_habtm_update
ActiveRecord::Base.connection.expects(:clear_query_cache).times(2)
ActiveRecord::Base.cache do
- c = Category.find(:first)
- p = Post.find(:first)
+ c = Category.first
+ p = Post.first
p.categories << c
end
end
diff --git a/activerecord/test/cases/readonly_test.rb b/activerecord/test/cases/readonly_test.rb
index e21109baae..39b66b3399 100644
--- a/activerecord/test/cases/readonly_test.rb
+++ b/activerecord/test/cases/readonly_test.rb
@@ -27,7 +27,7 @@ class ReadOnlyTest < ActiveRecord::TestCase
def test_find_with_readonly_option
- Developer.find(:all).each { |d| assert !d.readonly? }
+ Developer.all.each { |d| assert !d.readonly? }
Developer.readonly(false).each { |d| assert !d.readonly? }
Developer.readonly(true).each { |d| assert d.readonly? }
Developer.readonly.each { |d| assert d.readonly? }
@@ -48,7 +48,7 @@ class ReadOnlyTest < ActiveRecord::TestCase
post = Post.find(1)
assert !post.comments.empty?
assert !post.comments.any?(&:readonly?)
- assert !post.comments.find(:all).any?(&:readonly?)
+ assert !post.comments.all.any?(&:readonly?)
assert post.comments.readonly(true).all?(&:readonly?)
end
@@ -70,13 +70,13 @@ class ReadOnlyTest < ActiveRecord::TestCase
end
def test_readonly_scoping
- Post.send(:with_scope, :find => { :conditions => '1=1' }) do
+ Post.where('1=1').scoped do
assert !Post.find(1).readonly?
assert Post.readonly(true).find(1).readonly?
assert !Post.readonly(false).find(1).readonly?
end
- Post.send(:with_scope, :find => { :joins => ' ' }) do
+ Post.joins(' ').scoped do
assert !Post.find(1).readonly?
assert Post.readonly.find(1).readonly?
assert !Post.readonly(false).find(1).readonly?
@@ -85,14 +85,14 @@ class ReadOnlyTest < ActiveRecord::TestCase
# Oracle barfs on this because the join includes unqualified and
# conflicting column names
unless current_adapter?(:OracleAdapter)
- Post.send(:with_scope, :find => { :joins => ', developers' }) do
+ Post.joins(', developers').scoped do
assert Post.find(1).readonly?
assert Post.readonly.find(1).readonly?
assert !Post.readonly(false).find(1).readonly?
end
end
- Post.send(:with_scope, :find => { :readonly => true }) do
+ Post.readonly(true).scoped do
assert Post.find(1).readonly?
assert Post.readonly.find(1).readonly?
assert !Post.readonly(false).find(1).readonly?
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index 16f05f2198..7dd5698dcf 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -63,7 +63,7 @@ class ReflectionTest < ActiveRecord::TestCase
end
def test_column_null_not_null
- subscriber = Subscriber.find(:first)
+ subscriber = Subscriber.first
assert subscriber.column_for_attribute("name").null
assert !subscriber.column_for_attribute("nick").null
end
diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb
index edf38cb7a3..342f7a86fa 100644
--- a/activerecord/test/cases/relation_scoping_test.rb
+++ b/activerecord/test/cases/relation_scoping_test.rb
@@ -53,8 +53,8 @@ class RelationScopingTest < ActiveRecord::TestCase
end
def test_scoped_find_last_preserves_scope
- lowest_salary = Developer.first :order => "salary ASC"
- highest_salary = Developer.first :order => "salary DESC"
+ lowest_salary = Developer.order("salary ASC").first
+ highest_salary = Developer.order("salary DESC").first
Developer.order("salary").scoping do
assert_equal highest_salary, Developer.last
@@ -323,8 +323,8 @@ class DefaultScopingTest < ActiveRecord::TestCase
fixtures :developers, :posts
def test_default_scope
- expected = Developer.find(:all, :order => 'salary DESC').collect { |dev| dev.salary }
- received = DeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
+ expected = Developer.scoped(:order => 'salary DESC').all.collect { |dev| dev.salary }
+ received = DeveloperOrderedBySalary.all.collect { |dev| dev.salary }
assert_equal expected, received
end
@@ -362,12 +362,12 @@ class DefaultScopingTest < ActiveRecord::TestCase
end
def test_default_scope_with_conditions_string
- assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.find(:all).map(&:id).sort
+ assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.all.map(&:id).sort
assert_equal nil, DeveloperCalledDavid.create!.name
end
def test_default_scope_with_conditions_hash
- assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeveloperCalledJamis.find(:all).map(&:id).sort
+ assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeveloperCalledJamis.all.map(&:id).sort
assert_equal 'Jamis', DeveloperCalledJamis.create!.name
end
@@ -395,23 +395,9 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal 50000, wheres[:salary]
end
- def test_method_scope
- expected = Developer.find(:all, :order => 'salary DESC, name DESC').collect { |dev| dev.salary }
- received = DeveloperOrderedBySalary.all_ordered_by_name.collect { |dev| dev.salary }
- assert_equal expected, received
- end
-
- def test_nested_scope
- expected = Developer.find(:all, :order => 'salary DESC, name DESC').collect { |dev| dev.salary }
- received = DeveloperOrderedBySalary.send(:with_scope, :find => { :order => 'name DESC'}) do
- DeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
- end
- assert_equal expected, received
- end
-
def test_scope_overwrites_default
- expected = Developer.find(:all, :order => 'salary DESC, name DESC').collect { |dev| dev.name }
- received = DeveloperOrderedBySalary.by_name.find(:all).collect { |dev| dev.name }
+ expected = Developer.scoped(:order => 'salary DESC, name DESC').all.collect { |dev| dev.name }
+ received = DeveloperOrderedBySalary.by_name.all.collect { |dev| dev.name }
assert_equal expected, received
end
@@ -427,17 +413,9 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal expected, received
end
- def test_nested_exclusive_scope
- expected = Developer.find(:all, :limit => 100).collect { |dev| dev.salary }
- received = DeveloperOrderedBySalary.send(:with_exclusive_scope, :find => { :limit => 100 }) do
- DeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
- end
- assert_equal expected, received
- end
-
def test_order_in_default_scope_should_prevail
- expected = Developer.find(:all, :order => 'salary desc').collect { |dev| dev.salary }
- received = DeveloperOrderedBySalary.find(:all, :order => 'salary').collect { |dev| dev.salary }
+ expected = Developer.scoped(:order => 'salary desc').all.collect { |dev| dev.salary }
+ received = DeveloperOrderedBySalary.scoped(:order => 'salary').all.collect { |dev| dev.salary }
assert_equal expected, received
end
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index ac6dee3c6a..8a7a2441d4 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -19,33 +19,12 @@ module ActiveRecord
assert !relation.loaded, 'relation is not loaded'
end
- def test_single_values
- assert_equal [:limit, :offset, :lock, :readonly, :from, :reordering, :reverse_order, :uniq].map(&:to_s).sort,
- Relation::SINGLE_VALUE_METHODS.map(&:to_s).sort
- end
-
def test_initialize_single_values
relation = Relation.new :a, :b
- Relation::SINGLE_VALUE_METHODS.each do |method|
+ (Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |method|
assert_nil relation.send("#{method}_value"), method.to_s
end
- end
-
- def test_association_methods
- assert_equal [:includes, :eager_load, :preload].map(&:to_s).sort,
- Relation::ASSOCIATION_METHODS.map(&:to_s).sort
- end
-
- def test_initialize_association_methods
- relation = Relation.new :a, :b
- Relation::ASSOCIATION_METHODS.each do |method|
- assert_equal [], relation.send("#{method}_values"), method.to_s
- end
- end
-
- def test_multi_value_methods
- assert_equal [:select, :group, :order, :joins, :where, :having, :bind, :references].map(&:to_s).sort,
- Relation::MULTI_VALUE_METHODS.map(&:to_s).sort
+ assert_equal({}, relation.create_with_value)
end
def test_multi_value_initialize
@@ -64,19 +43,19 @@ module ActiveRecord
relation = Relation.new :a, :b
assert_equal({}, relation.where_values_hash)
- relation.where_values << :hello
+ relation.where! :hello
assert_equal({}, relation.where_values_hash)
end
def test_has_values
relation = Relation.new Post, Post.arel_table
- relation.where_values << relation.table[:id].eq(10)
+ relation.where! relation.table[:id].eq(10)
assert_equal({:id => 10}, relation.where_values_hash)
end
def test_values_wrong_table
relation = Relation.new Post, Post.arel_table
- relation.where_values << Comment.arel_table[:id].eq(10)
+ relation.where! Comment.arel_table[:id].eq(10)
assert_equal({}, relation.where_values_hash)
end
@@ -85,7 +64,7 @@ module ActiveRecord
left = relation.table[:id].eq(10)
right = relation.table[:id].eq(10)
combine = left.and right
- relation.where_values << combine
+ relation.where! combine
assert_equal({}, relation.where_values_hash)
end
@@ -108,7 +87,7 @@ module ActiveRecord
def test_create_with_value_with_wheres
relation = Relation.new Post, Post.arel_table
- relation.where_values << relation.table[:id].eq(10)
+ relation.where! relation.table[:id].eq(10)
relation.create_with_value = {:hello => 'world'}
assert_equal({:hello => 'world', :id => 10}, relation.scope_for_create)
end
@@ -118,7 +97,7 @@ module ActiveRecord
relation = Relation.new Post, Post.arel_table
assert_equal({}, relation.scope_for_create)
- relation.where_values << relation.table[:id].eq(10)
+ relation.where! relation.table[:id].eq(10)
assert_equal({}, relation.scope_for_create)
relation.create_with_value = {:hello => 'world'}
@@ -132,7 +111,7 @@ module ActiveRecord
def test_eager_load_values
relation = Relation.new :a, :b
- relation.eager_load_values << :b
+ relation.eager_load! :b
assert relation.eager_loading?
end
@@ -149,10 +128,116 @@ module ActiveRecord
assert_equal ['foo'], relation.references_values
end
- def test_apply_finder_options_takes_references
+ test 'merging a hash into a relation' do
relation = Relation.new :a, :b
- relation = relation.apply_finder_options(:references => :foo)
- assert_equal ['foo'], relation.references_values
+ relation = relation.merge where: :lol, readonly: true
+
+ assert_equal [:lol], relation.where_values
+ assert_equal true, relation.readonly_value
+ end
+
+ test 'merging an empty hash into a relation' do
+ assert_equal [], Relation.new(:a, :b).merge({}).where_values
+ end
+
+ test 'merging a hash with unknown keys raises' do
+ assert_raises(ArgumentError) { Relation::HashMerger.new(nil, omg: 'lol') }
+ end
+
+ test '#values returns a dup of the values' do
+ relation = Relation.new(:a, :b).where! :foo
+ values = relation.values
+
+ values[:where] = nil
+ assert_not_nil relation.where_values
+ end
+
+ test 'relations can be created with a values hash' do
+ relation = Relation.new(:a, :b, where: [:foo])
+ assert_equal [:foo], relation.where_values
+ end
+
+ test 'merging a single where value' do
+ relation = Relation.new(:a, :b)
+ relation.merge!(where: :foo)
+ assert_equal [:foo], relation.where_values
+ end
+
+ test 'merging a hash interpolates conditions' do
+ klass = stub
+ klass.stubs(:sanitize_sql).with(['foo = ?', 'bar']).returns('foo = bar')
+
+ relation = Relation.new(klass, :b)
+ relation.merge!(where: ['foo = ?', 'bar'])
+ assert_equal ['foo = bar'], relation.where_values
+ end
+ end
+
+ class RelationMutationTest < ActiveSupport::TestCase
+ def relation
+ @relation ||= Relation.new :a, :b
+ end
+
+ (Relation::MULTI_VALUE_METHODS - [:references, :extending]).each do |method|
+ test "##{method}!" do
+ assert relation.public_send("#{method}!", :foo).equal?(relation)
+ assert_equal [:foo], relation.public_send("#{method}_values")
+ end
+ end
+
+ test '#references!' do
+ assert relation.references!(:foo).equal?(relation)
+ assert relation.references_values.include?('foo')
+ end
+
+ test 'extending!' do
+ mod = Module.new
+
+ assert relation.extending!(mod).equal?(relation)
+ assert [mod], relation.extending_values
+ assert relation.is_a?(mod)
+ end
+
+ test 'extending! with empty args' do
+ relation.extending!
+ assert_equal [], relation.extending_values
+ end
+
+ (Relation::SINGLE_VALUE_METHODS - [:lock, :reordering, :reverse_order, :create_with]).each do |method|
+ test "##{method}!" do
+ assert relation.public_send("#{method}!", :foo).equal?(relation)
+ assert_equal :foo, relation.public_send("#{method}_value")
+ end
+ end
+
+ test '#lock!' do
+ assert relation.lock!('foo').equal?(relation)
+ assert_equal 'foo', relation.lock_value
+ end
+
+ test '#reorder!' do
+ relation = self.relation.order('foo')
+
+ assert relation.reorder!('bar').equal?(relation)
+ assert_equal ['bar'], relation.order_values
+ assert relation.reordering_value
+ end
+
+ test 'reverse_order!' do
+ assert relation.reverse_order!.equal?(relation)
+ assert relation.reverse_order_value
+ relation.reverse_order!
+ assert !relation.reverse_order_value
+ end
+
+ test 'create_with!' do
+ assert relation.create_with!(foo: 'bar').equal?(relation)
+ assert_equal({foo: 'bar'}, relation.create_with_value)
+ end
+
+ test 'merge!' do
+ assert relation.merge!(where: :foo).equal?(relation)
+ assert_equal [:foo], relation.where_values
end
end
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 25eb7c1672..4b8b57bac2 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -219,6 +219,7 @@ class RelationTest < ActiveRecord::TestCase
assert_no_queries do
assert_equal [], Developer.none
assert_equal [], Developer.scoped.none
+ assert Developer.none.is_a?(ActiveRecord::NullRelation)
end
end
@@ -228,6 +229,38 @@ class RelationTest < ActiveRecord::TestCase
end
end
+ def test_none_chained_to_methods_firing_queries_straight_to_db
+ assert_no_queries do
+ assert_equal [], Developer.none.pluck(:id) # => uses select_all
+ assert_equal 0, Developer.none.delete_all
+ assert_equal 0, Developer.none.update_all(:name => 'David')
+ assert_equal 0, Developer.none.delete(1)
+ assert_equal false, Developer.none.exists?(1)
+ end
+ end
+
+ def test_null_relation_content_size_methods
+ assert_no_queries do
+ assert_equal 0, Developer.none.size
+ assert_equal 0, Developer.none.count
+ assert_equal true, Developer.none.empty?
+ assert_equal false, Developer.none.any?
+ assert_equal false, Developer.none.many?
+ end
+ end
+
+ def test_null_relation_calculations_methods
+ assert_no_queries do
+ assert_equal 0, Developer.none.count
+ assert_equal nil, Developer.none.calculate(:average, 'salary')
+ end
+ end
+
+ def test_null_relation_metadata_methods
+ assert_equal "", Developer.none.to_sql
+ assert_equal({}, Developer.none.where_values_hash)
+ end
+
def test_joins_with_nil_argument
assert_nothing_raised { DependentFirm.joins(nil).first }
end
@@ -249,7 +282,7 @@ class RelationTest < ActiveRecord::TestCase
end
def test_find_on_hash_conditions
- assert_equal Topic.find(:all, :conditions => {:approved => false}), Topic.where({ :approved => false }).to_a
+ assert_equal Topic.scoped(:where => {:approved => false}).all, Topic.where({ :approved => false }).to_a
end
def test_joins_with_string_array
@@ -297,7 +330,6 @@ class RelationTest < ActiveRecord::TestCase
end
def test_respond_to_class_methods_and_scopes
- assert DeveloperOrderedBySalary.scoped.respond_to?(:all_ordered_by_name)
assert Topic.scoped.respond_to?(:by_lifo)
end
@@ -1027,10 +1059,6 @@ class RelationTest < ActiveRecord::TestCase
assert_equal Post.all, all_posts.all
end
- def test_extensions_with_except
- assert_equal 2, Topic.named_extension.order(:author_name).except(:order).two
- end
-
def test_only
relation = Post.where(:author_id => 1).order('id ASC').limit(1)
assert_equal [posts(:welcome)], relation.all
@@ -1042,10 +1070,6 @@ class RelationTest < ActiveRecord::TestCase
assert_equal Post.limit(1).all.first, all_posts.first
end
- def test_extensions_with_only
- assert_equal 2, Topic.named_extension.order(:author_name).only(:order).two
- end
-
def test_anonymous_extension
relation = Post.where(:author_id => 1).order('id ASC').extending do
def author
@@ -1067,36 +1091,26 @@ class RelationTest < ActiveRecord::TestCase
assert_equal Post.order(Post.arel_table[:title]).all, Post.order("title").all
end
- def test_order_with_find_with_order
- assert_equal 'zyke', CoolCar.order('name desc').find(:first, :order => 'id').name
- assert_equal 'zyke', FastCar.order('name desc').find(:first, :order => 'id').name
- end
-
def test_default_scope_order_with_scope_order
assert_equal 'zyke', CoolCar.order_using_new_style.limit(1).first.name
- assert_equal 'zyke', CoolCar.order_using_old_style.limit(1).first.name
assert_equal 'zyke', FastCar.order_using_new_style.limit(1).first.name
- assert_equal 'zyke', FastCar.order_using_old_style.limit(1).first.name
end
def test_order_using_scoping
car1 = CoolCar.order('id DESC').scoping do
- CoolCar.find(:first, :order => 'id asc')
+ CoolCar.scoped(:order => 'id asc').first
end
assert_equal 'zyke', car1.name
car2 = FastCar.order('id DESC').scoping do
- FastCar.find(:first, :order => 'id asc')
+ FastCar.scoped(:order => 'id asc').first
end
assert_equal 'zyke', car2.name
end
def test_unscoped_block_style
assert_equal 'honda', CoolCar.unscoped { CoolCar.order_using_new_style.limit(1).first.name}
- assert_equal 'honda', CoolCar.unscoped { CoolCar.order_using_old_style.limit(1).first.name}
-
assert_equal 'honda', FastCar.unscoped { FastCar.order_using_new_style.limit(1).first.name}
- assert_equal 'honda', FastCar.unscoped { FastCar.order_using_old_style.limit(1).first.name}
end
def test_intersection_with_array
@@ -1107,10 +1121,6 @@ class RelationTest < ActiveRecord::TestCase
assert_equal [rails_author], relation & [rails_author]
end
- def test_removing_limit_with_options
- assert_not_equal 1, Post.limit(1).all(:limit => nil).count
- end
-
def test_primary_key
assert_equal "id", Post.scoped.primary_key
end
diff --git a/activerecord/test/cases/validations/association_validation_test.rb b/activerecord/test/cases/validations/association_validation_test.rb
index c72b7b35cd..7ac34bc71e 100644
--- a/activerecord/test/cases/validations/association_validation_test.rb
+++ b/activerecord/test/cases/validations/association_validation_test.rb
@@ -86,7 +86,7 @@ class AssociationValidationTest < ActiveRecord::TestCase
assert !r.valid?
assert r.errors[:topic].any?
- r.topic = Topic.find :first
+ r.topic = Topic.first
assert r.valid?
end
diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb
index ec09479c95..c173ee9a15 100644
--- a/activerecord/test/cases/validations/uniqueness_validation_test.rb
+++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb
@@ -189,7 +189,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase
assert t_utf8.save, "Should save t_utf8 as unique"
# If database hasn't UTF-8 character set, this test fails
- if Topic.find(t_utf8, :select => 'LOWER(title) AS title').title == "я тоже уникальный!"
+ if Topic.scoped(:select => 'LOWER(title) AS title').find(t_utf8).title == "я тоже уникальный!"
t2_utf8 = Topic.new("title" => "я тоже УНИКАЛЬНЫЙ!")
assert !t2_utf8.valid?, "Shouldn't be valid"
assert !t2_utf8.save, "Shouldn't save t2_utf8 as unique"
@@ -261,10 +261,10 @@ class UniquenessValidationTest < ActiveRecord::TestCase
assert i1.errors[:value].any?, "Should not be empty"
end
- def test_validates_uniqueness_inside_with_scope
+ def test_validates_uniqueness_inside_scoping
Topic.validates_uniqueness_of(:title)
- Topic.send(:with_scope, :find => { :conditions => { :author_name => "David" } }) do
+ Topic.where(:author_name => "David").scoping do
t1 = Topic.new("title" => "I'm unique!", "author_name" => "Mary")
assert t1.save
t2 = Topic.new("title" => "I'm unique!", "author_name" => "David")
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb
index e575a98170..b11b330374 100644
--- a/activerecord/test/cases/validations_test.rb
+++ b/activerecord/test/cases/validations_test.rb
@@ -93,30 +93,6 @@ class ValidationsTest < ActiveRecord::TestCase
end
end
- def test_scoped_create_without_attributes
- WrongReply.send(:with_scope, :create => {}) do
- assert_raise(ActiveRecord::RecordInvalid) { WrongReply.create! }
- end
- end
-
- def test_create_with_exceptions_using_scope_for_protected_attributes
- assert_nothing_raised do
- ProtectedPerson.send(:with_scope, :create => { :first_name => "Mary" } ) do
- person = ProtectedPerson.create! :addon => "Addon"
- assert_equal person.first_name, "Mary", "scope should ignore attr_protected"
- end
- end
- end
-
- def test_create_with_exceptions_using_scope_and_empty_attributes
- assert_nothing_raised do
- ProtectedPerson.send(:with_scope, :create => { :first_name => "Mary" } ) do
- person = ProtectedPerson.create!
- assert_equal person.first_name, "Mary", "should be ok when no attributes are passed to create!"
- end
- end
- end
-
def test_create_without_validation
reply = WrongReply.new
assert !reply.save
diff --git a/activerecord/test/models/car.rb b/activerecord/test/models/car.rb
index 42ac81690f..b4bc0ad5fa 100644
--- a/activerecord/test/models/car.rb
+++ b/activerecord/test/models/car.rb
@@ -15,7 +15,6 @@ class Car < ActiveRecord::Base
scope :incl_engines, -> { includes(:engines) }
scope :order_using_new_style, -> { order('name asc') }
- scope :order_using_old_style, -> { { :order => 'name asc' } }
end
diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb
index 00f5a74070..3e9f1b0635 100644
--- a/activerecord/test/models/comment.rb
+++ b/activerecord/test/models/comment.rb
@@ -9,6 +9,8 @@ class Comment < ActiveRecord::Base
belongs_to :post, :counter_cache => true
has_many :ratings
+ belongs_to :first_post, :foreign_key => :post_id
+
has_many :children, :class_name => 'Comment', :foreign_key => :parent_id
belongs_to :parent, :class_name => 'Comment', :counter_cache => :children_count
@@ -17,7 +19,7 @@ class Comment < ActiveRecord::Base
end
def self.search_by_type(q)
- self.find(:all, :conditions => ["#{QUOTED_TYPE} = ?", q])
+ self.scoped(:where => ["#{QUOTED_TYPE} = ?", q]).all
end
def self.all_as_method
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index 4cc4947e3b..83482f4d07 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -2,20 +2,20 @@ require 'ostruct'
module DeveloperProjectsAssociationExtension
def find_most_recent
- find(:first, :order => "id DESC")
+ scoped(:order => "id DESC").first
end
end
module DeveloperProjectsAssociationExtension2
def find_least_recent
- find(:first, :order => "id ASC")
+ scoped(:order => "id ASC").first
end
end
class Developer < ActiveRecord::Base
has_and_belongs_to_many :projects do
def find_most_recent
- find(:first, :order => "id DESC")
+ scoped(:order => "id DESC").first
end
end
@@ -37,7 +37,7 @@ class Developer < ActiveRecord::Base
:association_foreign_key => "project_id",
:extend => DeveloperProjectsAssociationExtension do
def find_least_recent
- find(:first, :order => "id ASC")
+ scoped(:order => "id ASC").first
end
end
@@ -57,12 +57,6 @@ class Developer < ActiveRecord::Base
def log=(message)
audit_logs.build :message => message
end
-
- def self.all_johns
- self.with_exclusive_scope :find => where(:name => 'John') do
- self.all
- end
- end
end
class AuditLog < ActiveRecord::Base
@@ -102,12 +96,6 @@ class DeveloperOrderedBySalary < ActiveRecord::Base
default_scope { order('salary DESC') }
scope :by_name, -> { order('name DESC') }
-
- def self.all_ordered_by_name
- with_scope(:find => { :order => 'name DESC' }) do
- find(:all)
- end
- end
end
class DeveloperCalledDavid < ActiveRecord::Base
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index 5002ab9ff8..1aaf9a1b82 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -9,11 +9,6 @@ class Post < ActiveRecord::Base
scope :ranked_by_comments, -> { order("comments_count DESC") }
scope :limit_by, lambda {|l| limit(l) }
- scope :with_authors_at_address, lambda { |address| {
- :conditions => [ 'authors.author_address_id = ?', address.id ],
- :joins => 'JOIN authors ON authors.id = posts.author_id'
- }
- }
belongs_to :author do
def greeting
@@ -32,13 +27,11 @@ class Post < ActiveRecord::Base
scope :with_special_comments, -> { joins(:comments).where(:comments => {:type => 'SpecialComment'}) }
scope :with_very_special_comments, -> { joins(:comments).where(:comments => {:type => 'VerySpecialComment'}) }
- scope :with_post, lambda {|post_id|
- { :joins => :comments, :conditions => {:comments => {:post_id => post_id} } }
- }
+ scope :with_post, ->(post_id) { joins(:comments).where(:comments => { :post_id => post_id }) }
has_many :comments do
def find_most_recent
- find(:first, :order => "id DESC")
+ scoped(:order => "id DESC").first
end
def newest
@@ -71,8 +64,8 @@ class Post < ActiveRecord::Base
has_many :taggings, :as => :taggable
has_many :tags, :through => :taggings do
def add_joins_and_select
- find :all, :select => 'tags.*, authors.id as author_id',
- :joins => 'left outer join posts on taggings.taggable_id = posts.id left outer join authors on posts.author_id = authors.id'
+ scoped(:select => 'tags.*, authors.id as author_id',
+ :joins => 'left outer join posts on taggings.taggable_id = posts.id left outer join authors on posts.author_id = authors.id').all
end
end
diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb
index 785839be75..079e403444 100644
--- a/activerecord/test/models/topic.rb
+++ b/activerecord/test/models/topic.rb
@@ -2,7 +2,7 @@ class Topic < ActiveRecord::Base
scope :base, -> { scoped }
scope :written_before, lambda { |time|
if time
- { :conditions => ['written_on < ?', time] }
+ where 'written_on < ?', time
end
}
scope :approved, -> { where(:approved => true) }
@@ -11,11 +11,7 @@ class Topic < ActiveRecord::Base
scope :scope_with_lambda, lambda { scoped }
scope :by_lifo, -> { where(:author_name => 'lifo') }
-
- ActiveSupport::Deprecation.silence do
- scope :approved_as_hash_condition, :conditions => {:topics => {:approved => true}}
- scope :replied, :conditions => ['replies_count > 0']
- end
+ scope :replied, -> { where 'replies_count > 0' }
scope 'approved_as_string', -> { where(:approved => true) }
scope :anonymous_extension, -> { scoped } do
@@ -35,18 +31,6 @@ class Topic < ActiveRecord::Base
2
end
end
- module MultipleExtensionOne
- def extension_one
- 1
- end
- end
- module MultipleExtensionTwo
- def extension_two
- 2
- end
- end
- scope :named_extension, -> { { :extend => NamedExtension } }
- scope :multiple_extensions, -> { { :extend => [MultipleExtensionTwo, MultipleExtensionOne] } }
has_many :replies, :dependent => :destroy, :foreign_key => "parent_id"
has_many :replies_with_primary_key, :class_name => "Reply", :dependent => :destroy, :primary_key => "title", :foreign_key => "parent_title"