aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG.md9
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/model_schema.rb9
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb14
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb21
-rw-r--r--activerecord/test/cases/base_test.rb18
-rw-r--r--activerecord/test/models/developer.rb5
-rw-r--r--activerecord/test/schema/schema.rb1
9 files changed, 78 insertions, 3 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 98a5b27854..45c330b8af 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Correctly apply `unscope` when preloading through associations.
+
+ *Jimmy Bourassa*
+
* Fixed taking precision into count when assigning a value to timestamp attribute
Timestamp column can have less precision than ruby timestamp
@@ -28,6 +32,11 @@
*Yves Senn*, *Matthew Draper*
+* Add `ActiveRecord::Base.ignored_columns` to make some columns
+ invisible from ActiveRecord.
+
+ *Jean Boussier*
+
* `ActiveRecord::Tasks::MySQLDatabaseTasks` fails if shellout to
mysql commands (like `mysqldump`) is not successful.
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 1dc8bff193..92792a7a15 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -154,7 +154,7 @@ module ActiveRecord
scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name })
end
- scope.unscope_values = Array(values[:unscope])
+ scope.unscope_values = Array(values[:unscope]) + Array(preload_values[:unscope])
klass.default_scoped.merge(scope)
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 9de79a614c..25dfda9ef8 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -761,7 +761,7 @@ module ActiveRecord
end
def extract_table_ref_from_insert_sql(sql) # :nodoc:
- sql[/into\s+([^\(]*).*values\s*\(/im]
+ sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
$1.strip if $1
end
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index c461c04a26..a9bd094a66 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -50,6 +50,13 @@ module ActiveRecord
class_attribute :pluralize_table_names, instance_writer: false
self.pluralize_table_names = true
+ ##
+ # :singleton-method:
+ # Accessor for the list of columns names the model should ignore. Ignored columns won't have attribute
+ # accessors defined, and won't be referenced in SQL queries.
+ class_attribute :ignored_columns, instance_accessor: false
+ self.ignored_columns = [].freeze
+
self.inheritance_column = 'type'
delegate :type_for_attribute, to: :class
@@ -308,7 +315,7 @@ module ActiveRecord
end
def load_schema!
- @columns_hash = connection.schema_cache.columns_hash(table_name)
+ @columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
@columns_hash.each do |name, column|
warn_if_deprecated_type(column)
define_attribute(
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index 6e6850c4a9..e361521155 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -123,6 +123,20 @@ module ActiveRecord
assert_equal expect.to_i, result.rows.first.first
end
+ def test_exec_insert_default_values_with_returning_disabled_and_no_sequence_name_given
+ connection = connection_without_insert_returning
+ result = connection.exec_insert("insert into postgresql_partitioned_table_parent DEFAULT VALUES", nil, [], 'id')
+ expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first
+ assert_equal expect.to_i, result.rows.first.first
+ end
+
+ def test_exec_insert_default_values_quoted_schema_with_returning_disabled_and_no_sequence_name_given
+ connection = connection_without_insert_returning
+ result = connection.exec_insert('insert into "public"."postgresql_partitioned_table_parent" DEFAULT VALUES', nil, [], 'id')
+ expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first
+ assert_equal expect.to_i, result.rows.first.first
+ end
+
def test_sql_for_insert_with_returning_disabled
connection = connection_without_insert_returning
result = connection.sql_for_insert('sql', nil, nil, nil, 'binds')
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 d160c30375..20af436e02 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
@@ -95,6 +95,15 @@ class DeveloperWithExtendOption < Developer
has_and_belongs_to_many :projects, extend: NamedExtension
end
+class ProjectUnscopingDavidDefaultScope < ActiveRecord::Base
+ self.table_name = 'projects'
+ has_and_belongs_to_many :developers, -> { unscope(where: 'name') },
+ class_name: "LazyBlockDeveloperCalledDavid",
+ join_table: "developers_projects",
+ foreign_key: "project_id",
+ association_foreign_key: "developer_id"
+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, :computers
@@ -936,4 +945,16 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
end
assert_equal 1, professor.courses.count
end
+
+ def test_habtm_scope_can_unscope
+ project = ProjectUnscopingDavidDefaultScope.new
+ project.save!
+
+ developer = LazyBlockDeveloperCalledDavid.new(name: "Not David")
+ developer.save!
+ project.developers << developer
+
+ projects = ProjectUnscopingDavidDefaultScope.includes(:developers).where(id: project.id)
+ assert_equal 1, projects.first.developers.size
+ end
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 991145bed4..dbbcaa075d 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1571,4 +1571,22 @@ class BasicsTest < ActiveRecord::TestCase
assert_not topic.id_changed?
end
+
+ test "ignored columns are not present in columns_hash" do
+ cache_columns = Developer.connection.schema_cache.columns_hash(Developer.table_name)
+ assert_includes cache_columns.keys, 'first_name'
+ refute_includes Developer.columns_hash.keys, 'first_name'
+ end
+
+ test "ignored columns have no attribute methods" do
+ refute Developer.new.respond_to?(:first_name)
+ refute Developer.new.respond_to?(:first_name=)
+ refute Developer.new.respond_to?(:first_name?)
+ end
+
+ test "ignored columns don't prevent explicit declaration of attribute methods" do
+ assert Developer.new.respond_to?(:last_name)
+ assert Developer.new.respond_to?(:last_name=)
+ assert Developer.new.respond_to?(:last_name?)
+ end
end
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index 8ac7a9df6a..7565e8f967 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -7,6 +7,8 @@ module DeveloperProjectsAssociationExtension2
end
class Developer < ActiveRecord::Base
+ self.ignored_columns = %w(first_name last_name)
+
has_and_belongs_to_many :projects do
def find_most_recent
order("id DESC").first
@@ -61,6 +63,9 @@ class Developer < ActiveRecord::Base
developer.audit_logs.build :message => "Computer created"
end
+ attr_accessor :last_name
+ define_attribute_method 'last_name'
+
def log=(message)
audit_logs.build :message => message
end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 4c6d1ef3ce..4b7272f10a 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -250,6 +250,7 @@ ActiveRecord::Schema.define do
create_table :developers, force: true do |t|
t.string :name
+ t.string :first_name
t.integer :salary, default: 70000
if subsecond_precision_supported?
t.datetime :created_at, precision: 6