aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb5
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb4
-rw-r--r--activerecord/lib/active_record/core.rb6
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb31
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb2
-rw-r--r--activerecord/lib/active_record/persistence.rb30
-rw-r--r--activerecord/lib/active_record/querying.rb1
-rw-r--r--activerecord/lib/active_record/railtie.rb6
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb19
13 files changed, 82 insertions, 38 deletions
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 253998fb23..b4c3908b10 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -77,7 +77,7 @@ module ActiveRecord
# Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
# Make several smaller queries if necessary or make one query if the adapter supports it
sliced = owner_keys.each_slice(model.connection.in_clause_length || owner_keys.size)
- records = sliced.map { |slice| records_for(slice) }.flatten
+ records = sliced.map { |slice| records_for(slice).to_a }.flatten
end
# Each record may have multiple owners, and vice-versa
@@ -93,7 +93,8 @@ module ActiveRecord
end
def build_scope
- scope = klass.scoped
+ scope = klass.unscoped
+ scope.default_scoped = true
scope = scope.where(interpolate(options[:conditions]))
scope = scope.where(interpolate(preload_options[:conditions]))
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index faed703167..dcc3d79de9 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -67,7 +67,9 @@ module ActiveRecord
@attributes_cache.fetch(attr_name.to_s) { |name|
column = @columns_hash.fetch(name) {
return @attributes.fetch(name) {
- @attributes[self.class.primary_key] if name == 'id'
+ if name == 'id' && self.class.primary_key != name
+ read_attribute(self.class.primary_key)
+ end
}
}
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 174450eb00..e919068909 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)
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)
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..0784b2d11a 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.
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 78e54c4c9b..b7e1513422 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -1,4 +1,5 @@
require 'set'
+require 'active_support/deprecation'
module ActiveRecord
# :stopdoc:
@@ -107,6 +108,9 @@ module ActiveRecord
end
def type_cast_code(var_name)
+ ActiveSupport::Deprecation.warn("Column#type_cast_code is deprecated in favor of" \
+ "using Column#type_cast only, and it is going to be removed in future Rails versions.")
+
klass = self.class.name
case type
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index 3d8dfab05c..91e1482ffd 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -339,9 +339,9 @@ module ActiveRecord
when /^null$/i
field["dflt_value"] = nil
when /^'(.*)'$/
- field["dflt_value"] = $1.gsub(/''/, "'")
+ field["dflt_value"] = $1.gsub("''", "'")
when /^"(.*)"$/
- field["dflt_value"] = $1.gsub(/""/, '"')
+ field["dflt_value"] = $1.gsub('""', '"')
end
SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0)
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 9a2f859fc7..76c424e8b4 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -1,4 +1,5 @@
require 'active_support/concern'
+require 'active_support/core_ext/hash/indifferent_access'
require 'thread'
module ActiveRecord
@@ -326,6 +327,11 @@ module ActiveRecord
"#<#{self.class} #{inspection}>"
end
+ # Returns a hash of the given methods with their names as keys and returned values as values.
+ def slice(*methods)
+ Hash[methods.map { |method| [method, public_send(method)] }].with_indifferent_access
+ end
+
private
# Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index 8266427b71..a3412582fa 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -101,24 +101,29 @@ module ActiveRecord
end
end
- def destroy #:nodoc:
- return super unless locking_enabled?
+ def destroy_row
+ affected_rows = super
- if persisted?
- table = self.class.arel_table
- lock_col = self.class.locking_column
- predicate = table[self.class.primary_key].eq(id).
- and(table[lock_col].eq(send(lock_col).to_i))
+ if locking_enabled? && affected_rows != 1
+ raise ActiveRecord::StaleObjectError.new(self, "destroy")
+ end
- affected_rows = self.class.unscoped.where(predicate).delete_all
+ affected_rows
+ end
- unless affected_rows == 1
- raise ActiveRecord::StaleObjectError.new(self, "destroy")
- end
+ def relation_for_destroy
+ relation = super
+
+ if locking_enabled?
+ column_name = self.class.locking_column
+ column = self.class.columns_hash[column_name]
+ substitute = connection.substitute_at(column, relation.bind_values.length)
+
+ relation = relation.where(self.class.arel_table[column_name].eq(substitute))
+ relation.bind_values << [column, self[column_name].to_i]
end
- @destroyed = true
- freeze
+ relation
end
module ClassMethods
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 6bf0becad8..32a1dae6bc 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -288,7 +288,7 @@ module ActiveRecord
# def pirate_attributes=(attributes)
# assign_nested_attributes_for_one_to_one_association(:pirate, attributes, mass_assignment_options)
# end
- class_eval <<-eoruby, __FILE__, __LINE__ + 1
+ generated_feature_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
if method_defined?(:#{association_name}_attributes=)
remove_method(:#{association_name}_attributes=)
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 35c922e979..bb504ae90f 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -124,19 +124,7 @@ module ActiveRecord
# that no changes should be made (since they can't be persisted).
def destroy
destroy_associations
-
- if persisted?
- pk = self.class.primary_key
- column = self.class.columns_hash[pk]
- substitute = connection.substitute_at(column, 0)
-
- relation = self.class.unscoped.where(
- self.class.arel_table[pk].eq(substitute))
-
- relation.bind_values = [[column, id]]
- relation.delete_all
- end
-
+ destroy_row if persisted?
@destroyed = true
freeze
end
@@ -335,6 +323,22 @@ module ActiveRecord
def destroy_associations
end
+ def destroy_row
+ relation_for_destroy.delete_all
+ end
+
+ def relation_for_destroy
+ pk = self.class.primary_key
+ column = self.class.columns_hash[pk]
+ substitute = connection.substitute_at(column, 0)
+
+ relation = self.class.unscoped.where(
+ self.class.arel_table[pk].eq(substitute))
+
+ relation.bind_values = [[column, id]]
+ relation
+ end
+
def create_or_update
raise ReadOnlyRecord if readonly?
result = new_record? ? create : update
diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb
index 0e6fecbc4b..95565b503a 100644
--- a/activerecord/lib/active_record/querying.rb
+++ b/activerecord/lib/active_record/querying.rb
@@ -5,6 +5,7 @@ module ActiveRecord
module Querying
delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped
delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :scoped
+ delegate :find_by, :find_by!, :to => :scoped
delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped
delegate :find_each, :find_in_batches, :to => :scoped
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
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/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 2c74f4011d..74f8e30404 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -109,6 +109,25 @@ module ActiveRecord
end
end
+ # Finds the first record matching the specified conditions. There
+ # is no implied ording so if order matters, you should specify it
+ # yourself.
+ #
+ # If no record is found, returns <tt>nil</tt>.
+ #
+ # Post.find_by name: 'Spartacus', rating: 4
+ # Post.find_by "published_at < ?", 2.weeks.ago
+ #
+ def find_by(*args)
+ where(*args).first
+ end
+
+ # Like <tt>find_by</tt>, except that if no record is found, raises
+ # an <tt>ActiveRecord::RecordNotFound</tt> error.
+ def find_by!(*args)
+ 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)