aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md15
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb6
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb15
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb9
-rw-r--r--activerecord/lib/active_record/core.rb16
-rw-r--r--activerecord/lib/active_record/persistence.rb2
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb21
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb41
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb2
9 files changed, 100 insertions, 27 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 474b11f537..c255f59b00 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,16 @@
+* Migration dump UUID default functions to schema.rb.
+
+ Fixes #10751.
+
+ *kennyj*
+
+* Fixed a bug in `ActiveRecord::Associations::CollectionAssociation#find_by_scan`
+ when using `has_many` association with `:inverse_of` option and UUID primary key.
+
+ Fixes #10450.
+
+ *kennyj*
+
* ActiveRecord::Base#<=> has been removed. Primary keys may not be in order,
or even be numbers, so sorting by id doesn't make sense. Please use `sort_by`
and specify the attribute you wish to sort with. For example, change:
@@ -8,6 +21,8 @@
Post.all.to_a.sort_by(&:id)
+ *Aaron Patterson*
+
* Fix: joins association, with defined in the scope block constraints by using several
where constraints and at least of them is not `Arel::Nodes::Equality`,
generates invalid SQL expression.
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index e32c0b0377..98d573a3a2 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -554,14 +554,14 @@ module ActiveRecord
# specified, then #find scans the entire collection.
def find_by_scan(*args)
expects_array = args.first.kind_of?(Array)
- ids = args.flatten.compact.map{ |arg| arg.to_i }.uniq
+ ids = args.flatten.compact.map{ |arg| arg.to_s }.uniq
if ids.size == 1
id = ids.first
- record = load_target.detect { |r| id == r.id }
+ record = load_target.detect { |r| id == r.id.to_s }
expects_array ? [ record ] : record
else
- load_target.select { |r| ids.include?(r.id) }
+ load_target.select { |r| ids.include?(r.id.to_s) }
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index dc2399643c..19e81abba5 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -19,8 +19,7 @@ module ActiveRecord
# Attempts to +save+ the record and clears changed attributes if successful.
def save(*)
if status = super
- @previously_changed = changes
- @changed_attributes.clear
+ changes_applied
end
status
end
@@ -28,16 +27,14 @@ module ActiveRecord
# Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
def save!(*)
super.tap do
- @previously_changed = changes
- @changed_attributes.clear
+ changes_applied
end
end
# <tt>reload</tt> the record and clears changed attributes.
def reload(*)
super.tap do
- @previously_changed.clear
- @changed_attributes.clear
+ reset_changes
end
end
@@ -48,11 +45,11 @@ module ActiveRecord
# The attribute already has an unsaved change.
if attribute_changed?(attr)
- old = @changed_attributes[attr]
- @changed_attributes.delete(attr) unless _field_changed?(attr, old, value)
+ old = changed_attributes[attr]
+ changed_attributes.delete(attr) unless _field_changed?(attr, old, value)
else
old = clone_attribute_value(:read_attribute, attr)
- @changed_attributes[attr] = old if _field_changed?(attr, old, value)
+ changed_attributes[attr] = old if _field_changed?(attr, old, value)
end
# Carry on.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 13978fd113..af240fab95 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -45,16 +45,18 @@ module ActiveRecord
module ConnectionAdapters
# PostgreSQL-specific extensions to column definitions in a table.
class PostgreSQLColumn < Column #:nodoc:
- attr_accessor :array
+ attr_accessor :array, :default_function
# Instantiates a new PostgreSQL column definition in a table.
def initialize(name, default, oid_type, sql_type = nil, null = true)
@oid_type = oid_type
+ default_value = self.class.extract_value_from_default(default)
+ @default_function = default if !default_value && default && default =~ /.+\(.*\)/
if sql_type =~ /\[\]$/
@array = true
- super(name, self.class.extract_value_from_default(default), sql_type[0..sql_type.length - 3], null)
+ super(name, default_value, sql_type[0..sql_type.length - 3], null)
else
@array = false
- super(name, self.class.extract_value_from_default(default), sql_type, null)
+ super(name, default_value, sql_type, null)
end
end
@@ -439,6 +441,7 @@ module ActiveRecord
def prepare_column_options(column, types)
spec = super
spec[:array] = 'true' if column.respond_to?(:array) && column.array
+ spec[:default] = "\"#{column.default_function}\"" if column.respond_to?(:default_function) && column.default_function
spec
end
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 5e6fee52f7..366ebde418 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -163,7 +163,7 @@ module ActiveRecord
# ==== Example:
# # Instantiates a single new object
# User.new(first_name: 'Jamie')
- def initialize(attributes = nil)
+ def initialize(attributes = nil, options = {})
defaults = self.class.column_defaults.dup
defaults.each { |k, v| defaults[k] = v.dup if v.duplicable? }
@@ -176,7 +176,9 @@ module ActiveRecord
ensure_proper_type
populate_with_current_scope_attributes
- assign_attributes(attributes) if attributes
+ # +options+ argument is only needed to make protected_attributes gem easier to hook.
+ # Remove it when we drop support to this gem.
+ init_attributes(attributes, options) if attributes
yield self if block_given?
run_callbacks :initialize unless _initialize_callbacks.empty?
@@ -411,8 +413,6 @@ module ActiveRecord
@aggregation_cache = {}
@association_cache = {}
@attributes_cache = {}
- @previously_changed = {}
- @changed_attributes = {}
@readonly = false
@destroyed = false
@marked_for_destruction = false
@@ -429,8 +429,14 @@ module ActiveRecord
# optimistic locking) won't get written unless they get marked as changed
self.class.columns.each do |c|
attr, orig_value = c.name, c.default
- @changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value, @attributes[attr])
+ changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value, @attributes[attr])
end
end
+
+ # This method is needed to make protected_attributes gem easier to hook.
+ # Remove it when we drop support to this gem.
+ def init_attributes(attributes, options)
+ assign_attributes(attributes)
+ end
end
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index d630f31f5f..bdd00ee259 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -434,7 +434,7 @@ module ActiveRecord
changes[self.class.locking_column] = increment_lock if locking_enabled?
- @changed_attributes.except!(*changes.keys)
+ changed_attributes.except!(*changes.keys)
primary_key = self.class.primary_key
self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 1181cc739e..8986d255cd 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -17,9 +17,19 @@ module ActiveRecord
cattr_accessor :ignore_tables
@@ignore_tables = []
- def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
- new(connection).dump(stream)
- stream
+ class << self
+ def dump(connection=ActiveRecord::Base.connection, stream=STDOUT, config = ActiveRecord::Base)
+ new(connection, generate_options(config)).dump(stream)
+ stream
+ end
+
+ private
+ def generate_options(config)
+ {
+ table_name_prefix: config.table_name_prefix,
+ table_name_suffix: config.table_name_suffix
+ }
+ end
end
def dump(stream)
@@ -32,10 +42,11 @@ module ActiveRecord
private
- def initialize(connection)
+ def initialize(connection, options = {})
@connection = connection
@types = @connection.native_database_types
@version = Migrator::current_version rescue nil
+ @options = options
end
def header(stream)
@@ -201,7 +212,7 @@ HEADER
end
def remove_prefix_and_suffix(table)
- table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
+ table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[:table_name_suffix]})$/, "\\2")
end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index b573d48807..0cd5b420fc 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -61,6 +61,7 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase
schema = StringIO.new
ActiveRecord::SchemaDumper.dump(@connection, schema)
assert_match(/\bcreate_table "pg_uuids", id: :uuid\b/, schema.string)
+ assert_match(/t\.uuid "other_uuid", default: "uuid_generate_v4\(\)"/, schema.string)
end
end
@@ -93,3 +94,43 @@ class PostgresqlUUIDTestNilDefault < ActiveRecord::TestCase
assert_nil col_desc["default"]
end
end
+
+class PostgresqlUUIDTestInverseOf < ActiveRecord::TestCase
+ class UuidPost < ActiveRecord::Base
+ self.table_name = 'pg_uuid_posts'
+ has_many :uuid_comments, inverse_of: :uuid_post
+ end
+
+ class UuidComment < ActiveRecord::Base
+ self.table_name = 'pg_uuid_comments'
+ belongs_to :uuid_post
+ end
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ @connection.reconnect!
+
+ @connection.transaction do
+ @connection.create_table('pg_uuid_posts', id: :uuid) do |t|
+ t.string 'title'
+ end
+ @connection.create_table('pg_uuid_comments', id: :uuid) do |t|
+ t.uuid :uuid_post_id, default: 'uuid_generate_v4()'
+ t.string 'content'
+ end
+ end
+ end
+
+ def teardown
+ @connection.transaction do
+ @connection.execute 'drop table if exists pg_uuid_comments'
+ @connection.execute 'drop table if exists pg_uuid_posts'
+ end
+ end
+
+ def test_collection_association_with_uuid
+ post = UuidPost.create!
+ comment = post.uuid_comments.create!
+ assert post.uuid_comments.find(comment.id)
+ end
+end
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index a48ae1036f..32f86f9c88 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -299,7 +299,7 @@ class SchemaDumperTest < ActiveRecord::TestCase
def test_schema_dump_includes_uuid_shorthand_definition
output = standard_dump
- if %r{create_table "poistgresql_uuids"} =~ output
+ if %r{create_table "postgresql_uuids"} =~ output
assert_match %r{t.uuid "guid"}, output
end
end