aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md10
-rw-r--r--activerecord/lib/active_record/associations.rb2
-rw-r--r--activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb36
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb28
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb8
-rw-r--r--activerecord/lib/active_record/scoping/named.rb2
-rw-r--r--activerecord/lib/active_record/type/string.rb8
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb11
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb7
-rw-r--r--activerecord/test/cases/migration/change_table_test.rb6
-rw-r--r--activerecord/test/cases/type/string_test.rb4
-rw-r--r--activerecord/test/cases/validations/uniqueness_validation_test.rb2
-rw-r--r--activerecord/test/fixtures/computers.yml5
-rw-r--r--activerecord/test/fixtures/developers.yml1
-rw-r--r--activerecord/test/models/developer.rb2
-rw-r--r--activerecord/test/schema/schema.rb5
20 files changed, 109 insertions, 48 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index c4b74c6477..e4c59673cd 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,13 @@
+* Add `Table#name` to match `TableDefinition#name`.
+
+ *Cody Cutrer*
+
+* Cache `CollectionAssociation#reader` proxies separately before and after
+ the owner has been saved so that the proxy is not cached without the
+ owner's id.
+
+ *Ben Woosley*
+
* `ActiveRecord::ReadOnlyRecord` now has a descriptive message.
*Franky W.*
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 8911506694..d2bcdc55bf 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1700,7 +1700,7 @@ module ActiveRecord
hm_options[:through] = middle_reflection.name
hm_options[:source] = join_model.right_reflection.name
- [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table].each do |k|
+ [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name].each do |k|
hm_options[k] = options[k] if options.key? k
end
diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
index 815e8eb97f..357b28ac94 100644
--- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
+++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
@@ -98,7 +98,7 @@ module ActiveRecord::Associations::Builder
def middle_options(join_model)
middle_options = {}
- middle_options[:class] = join_model
+ middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
middle_options[:source] = join_model.left_reflection.name
if options.key? :foreign_key
middle_options[:foreign_key] = options[:foreign_key]
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 4411e5ae62..93f611dd8d 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -33,7 +33,13 @@ module ActiveRecord
reload
end
- @proxy ||= CollectionProxy.create(klass, self)
+ if owner.new_record?
+ # Cache the proxy separately before the owner has an id
+ # or else a post-save proxy will still lack the id
+ @new_record_proxy ||= CollectionProxy.create(klass, self)
+ else
+ @proxy ||= CollectionProxy.create(klass, self)
+ end
end
# Implements the writer method, e.g. foo.items= for Foo.has_many :items
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 1a3ed28d66..12b16b2473 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -287,10 +287,6 @@ module ActiveRecord
"DEFAULT VALUES"
end
- def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
- "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
- end
-
# Sanitizes the given LIMIT parameter in order to prevent SQL injection.
#
# The +limit+ may be anything that can evaluate to a string via #to_s. It
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 dd4c4ae9fc..5c4c214385 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -414,8 +414,10 @@ module ActiveRecord
class Table
include TimestampDefaultDeprecation
+ attr_reader :name
+
def initialize(table_name, base)
- @table_name = table_name
+ @name = table_name
@base = base
end
@@ -425,12 +427,12 @@ module ActiveRecord
# ====== Creating a simple column
# t.column(:name, :string)
def column(column_name, type, options = {})
- @base.add_column(@table_name, column_name, type, options)
+ @base.add_column(name, column_name, type, options)
end
# Checks to see if a column exists. See SchemaStatements#column_exists?
def column_exists?(column_name, type = nil, options = {})
- @base.column_exists?(@table_name, column_name, type, options)
+ @base.column_exists?(name, column_name, type, options)
end
# Adds a new index to the table. +column_name+ can be a single Symbol, or
@@ -443,19 +445,19 @@ module ActiveRecord
# ====== Creating a named index
# t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
def index(column_name, options = {})
- @base.add_index(@table_name, column_name, options)
+ @base.add_index(name, column_name, options)
end
# Checks to see if an index exists. See SchemaStatements#index_exists?
def index_exists?(column_name, options = {})
- @base.index_exists?(@table_name, column_name, options)
+ @base.index_exists?(name, column_name, options)
end
# Renames the given index on the table.
#
# t.rename_index(:user_id, :account_id)
def rename_index(index_name, new_index_name)
- @base.rename_index(@table_name, index_name, new_index_name)
+ @base.rename_index(name, index_name, new_index_name)
end
# Adds timestamps (+created_at+ and +updated_at+) columns to the table. See SchemaStatements#add_timestamps
@@ -463,7 +465,7 @@ module ActiveRecord
# t.timestamps
def timestamps(options = {})
emit_warning_if_null_unspecified(options)
- @base.add_timestamps(@table_name, options)
+ @base.add_timestamps(name, options)
end
# Changes the column's definition according to the new options.
@@ -472,7 +474,7 @@ module ActiveRecord
# t.change(:name, :string, limit: 80)
# t.change(:description, :text)
def change(column_name, type, options = {})
- @base.change_column(@table_name, column_name, type, options)
+ @base.change_column(name, column_name, type, options)
end
# Sets a new default value for a column. See SchemaStatements#change_column_default
@@ -480,7 +482,7 @@ module ActiveRecord
# t.change_default(:qualification, 'new')
# t.change_default(:authorized, 1)
def change_default(column_name, default)
- @base.change_column_default(@table_name, column_name, default)
+ @base.change_column_default(name, column_name, default)
end
# Removes the column(s) from the table definition.
@@ -488,7 +490,7 @@ module ActiveRecord
# t.remove(:qualification)
# t.remove(:qualification, :experience)
def remove(*column_names)
- @base.remove_columns(@table_name, *column_names)
+ @base.remove_columns(name, *column_names)
end
# Removes the given index from the table.
@@ -502,21 +504,21 @@ module ActiveRecord
# ====== Remove the index named by_branch_party in the table_name table
# t.remove_index name: :by_branch_party
def remove_index(options = {})
- @base.remove_index(@table_name, options)
+ @base.remove_index(name, options)
end
# Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
#
# t.remove_timestamps
def remove_timestamps
- @base.remove_timestamps(@table_name)
+ @base.remove_timestamps(name)
end
# Renames a column.
#
# t.rename(:description, :name)
def rename(column_name, new_column_name)
- @base.rename_column(@table_name, column_name, new_column_name)
+ @base.rename_column(name, column_name, new_column_name)
end
# Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
@@ -531,7 +533,7 @@ module ActiveRecord
def references(*args)
options = args.extract_options!
args.each do |ref_name|
- @base.add_reference(@table_name, ref_name, options)
+ @base.add_reference(name, ref_name, options)
end
end
alias :belongs_to :references
@@ -546,7 +548,7 @@ module ActiveRecord
def remove_references(*args)
options = args.extract_options!
args.each do |ref_name|
- @base.remove_reference(@table_name, ref_name, options)
+ @base.remove_reference(name, ref_name, options)
end
end
alias :remove_belongs_to :remove_references
@@ -558,8 +560,8 @@ module ActiveRecord
[:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
define_method column_type do |*args|
options = args.extract_options!
- args.each do |name|
- @base.add_column(@table_name, name, column_type, options)
+ args.each do |column_name|
+ @base.add_column(name, column_name, column_type, options)
end
end
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 5f512758e9..167453657d 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -631,10 +631,6 @@ module ActiveRecord
end
end
- def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
- where_sql
- end
-
def strict_mode?
self.class.type_cast_config_to_boolean(@config.fetch(:strict, true))
end
@@ -648,6 +644,8 @@ module ActiveRecord
def initialize_type_map(m) # :nodoc:
super
+ register_class_with_limit m, %r(char)i, MysqlString
+
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
@@ -672,7 +670,7 @@ module ActiveRecord
m.register_type(%r(enum)i) do |sql_type|
limit = sql_type[/^enum\((.+)\)/i, 1]
.split(',').map{|enum| enum.strip.length - 2}.max
- Type::String.new(limit: limit)
+ MysqlString.new(limit: limit)
end
end
@@ -847,6 +845,26 @@ module ActiveRecord
end
end
end
+
+ class MysqlString < Type::String # :nodoc:
+ def type_cast_for_database(value)
+ case value
+ when true then "1"
+ when false then "0"
+ else super
+ end
+ end
+
+ private
+
+ def cast_value(value)
+ case value
+ when true then "1"
+ when false then "0"
+ else super
+ end
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 9941f74766..6310d70192 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -13,7 +13,7 @@ require 'active_record/connection_adapters/postgresql/database_statements'
require 'arel/visitors/bind_visitor'
# Make sure we're using pg high enough for PGResult#values
-gem 'pg', '~> 0.11'
+gem 'pg', '~> 0.15'
require 'pg'
require 'ipaddr'
@@ -596,9 +596,7 @@ module ActiveRecord
}
log(sql, name, type_casted_binds, stmt_key) do
- @connection.send_query_prepared(stmt_key, type_casted_binds.map { |_, val| val })
- @connection.block
- @connection.get_last_result
+ @connection.exec_prepared(stmt_key, type_casted_binds.map { |_, val| val })
end
rescue ActiveRecord::StatementInvalid => e
pgerror = e.original_exception
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 1b5e3bdbac..b18cb353f1 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -179,10 +179,6 @@ module ActiveRecord
true
end
- def supports_add_column?
- true
- end
-
def supports_views?
true
end
@@ -451,12 +447,12 @@ module ActiveRecord
# 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)
+ def valid_alter_table_type?(type)
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 )
+ if valid_alter_table_type?(type)
super(table_name, column_name, type, options)
else
alter_table(table_name) do |definition|
diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb
index ec1edf0e01..35420e6551 100644
--- a/activerecord/lib/active_record/scoping/named.rb
+++ b/activerecord/lib/active_record/scoping/named.rb
@@ -139,7 +139,7 @@ module ActiveRecord
# Article.published.featured.latest_article
# Article.featured.titles
def scope(name, body, &block)
- unless body.respond_to?:call
+ unless body.respond_to?(:call)
raise ArgumentError, 'The scope body needs to be callable.'
end
diff --git a/activerecord/lib/active_record/type/string.rb b/activerecord/lib/active_record/type/string.rb
index 150defb106..fbc0af2c5a 100644
--- a/activerecord/lib/active_record/type/string.rb
+++ b/activerecord/lib/active_record/type/string.rb
@@ -15,8 +15,8 @@ module ActiveRecord
case value
when ::Numeric, ActiveSupport::Duration then value.to_s
when ::String then ::String.new(value)
- when true then "1"
- when false then "0"
+ when true then "t"
+ when false then "f"
else super
end
end
@@ -25,8 +25,8 @@ module ActiveRecord
def cast_value(value)
case value
- when true then "1"
- when false then "0"
+ when true then "t"
+ when false then "f"
# String.new is slightly faster than dup
else ::String.new(value.to_s)
end
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 859310575e..9a57683ee3 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
@@ -1,5 +1,6 @@
require "cases/helper"
require 'models/developer'
+require 'models/computer'
require 'models/project'
require 'models/company'
require 'models/customer'
@@ -80,7 +81,7 @@ end
class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
- :parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings
+ :parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings, :computers
def setup_data_for_habtm_case
ActiveRecord::Base.connection.execute('delete from countries_treaties')
@@ -883,4 +884,12 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
child.special_projects << SpecialProject.new("name" => "Special Project")
assert child.save, 'child object should be saved'
end
+
+ def test_habtm_with_reflection_using_class_name_and_fixtures
+ assert_not_nil Developer._reflections['shared_computers']
+ # Checking the fixture for named association is important here, because it's the only way
+ # we've been able to reproduce this bug
+ assert_not_nil File.read(File.expand_path("../../../fixtures/developers.yml", __FILE__)).index("shared_computers")
+ assert_equal developers(:david).shared_computers.first, computers(:laptop)
+ 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 1617e883ba..69f7bde4bc 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -413,6 +413,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal "Summit", Firm.all.merge!(:order => "id").first.clients_using_primary_key.first.name
end
+ def test_update_all_on_association_accessed_before_save
+ firm = Firm.new(name: 'Firm')
+ firm.clients << Client.first
+ firm.save!
+ assert_equal firm.clients.count, firm.clients.update_all(description: 'Great!')
+ end
+
def test_belongs_to_sanity
c = Client.new
assert_nil c.firm, "belongs_to failed sanity check on new object"
diff --git a/activerecord/test/cases/migration/change_table_test.rb b/activerecord/test/cases/migration/change_table_test.rb
index 777a48ad14..6613783fba 100644
--- a/activerecord/test/cases/migration/change_table_test.rb
+++ b/activerecord/test/cases/migration/change_table_test.rb
@@ -213,6 +213,12 @@ module ActiveRecord
t.rename :bar, :baz
end
end
+
+ def test_table_name_set
+ with_change_table do |t|
+ assert_equal :delete_me, t.name
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/type/string_test.rb b/activerecord/test/cases/type/string_test.rb
index 420177ed49..4d78f287f1 100644
--- a/activerecord/test/cases/type/string_test.rb
+++ b/activerecord/test/cases/type/string_test.rb
@@ -4,8 +4,8 @@ module ActiveRecord
class StringTypeTest < ActiveRecord::TestCase
test "type casting" do
type = Type::String.new
- assert_equal "1", type.type_cast_from_user(true)
- assert_equal "0", type.type_cast_from_user(false)
+ assert_equal "t", type.type_cast_from_user(true)
+ assert_equal "f", type.type_cast_from_user(false)
assert_equal "123", type.type_cast_from_user(123)
end
diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb
index 18221cc73d..c6b58d469d 100644
--- a/activerecord/test/cases/validations/uniqueness_validation_test.rb
+++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb
@@ -41,7 +41,7 @@ class TopicWithUniqEvent < Topic
end
class UniquenessValidationTest < ActiveRecord::TestCase
- fixtures :topics, 'warehouse-things', :developers
+ fixtures :topics, 'warehouse-things'
repair_validations(Topic, Reply)
diff --git a/activerecord/test/fixtures/computers.yml b/activerecord/test/fixtures/computers.yml
index 7281a4d768..ad5ae2ec71 100644
--- a/activerecord/test/fixtures/computers.yml
+++ b/activerecord/test/fixtures/computers.yml
@@ -3,3 +3,8 @@ workstation:
system: 'Linux'
developer: 1
extendedWarranty: 1
+
+laptop:
+ system: 'MacOS 1'
+ developer: 1
+ extendedWarranty: 1
diff --git a/activerecord/test/fixtures/developers.yml b/activerecord/test/fixtures/developers.yml
index 1a74563dc6..54b74e7a74 100644
--- a/activerecord/test/fixtures/developers.yml
+++ b/activerecord/test/fixtures/developers.yml
@@ -2,6 +2,7 @@ david:
id: 1
name: David
salary: 80000
+ shared_computers: laptop
jamis:
id: 2
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index 3627cfdd09..d2a5a7fc49 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -15,6 +15,8 @@ class Developer < ActiveRecord::Base
accepts_nested_attributes_for :projects
+ has_and_belongs_to_many :shared_computers, class_name: "Computer"
+
has_and_belongs_to_many :projects_extended_by_name,
-> { extending(DeveloperProjectsAssociationExtension) },
:class_name => "Project",
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 539a0d2a49..720a127585 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -228,6 +228,11 @@ ActiveRecord::Schema.define do
t.integer :extendedWarranty, null: false
end
+ create_table :computers_developers, id: false, force: true do |t|
+ t.references :computer
+ t.references :developer
+ end
+
create_table :contracts, force: true do |t|
t.integer :developer_id
t.integer :company_id