Skip to content

Commit d34c1fc

Browse files
Cached columns_hash fields should be excluded from ResultSet#column_types
1 parent b9c7305 commit d34c1fc

File tree

5 files changed

+57
-1
lines changed

5 files changed

+57
-1
lines changed

activerecord/CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1+
* Cached columns_hash fields should be excluded from ResultSet#column_types
2+
3+
PR #34528 addresses the inconsistent behaviour when attribute is defined for an ignored column. The following test
4+
was passing for SQLite and MySQL, but failed for PostgreSQL:
5+
6+
```ruby
7+
class DeveloperName < ActiveRecord::Type::String
8+
def deserialize(value)
9+
"Developer: #{value}"
10+
end
11+
end
12+
13+
class AttributedDeveloper < ActiveRecord::Base
14+
self.table_name = "developers"
15+
16+
attribute :name, DeveloperName.new
17+
18+
self.ignored_columns += ["name"]
19+
end
20+
21+
developer = AttributedDeveloper.create
22+
developer.update_column :name, "name"
23+
24+
loaded_developer = AttributedDeveloper.where(id: developer.id).select("*").first
25+
puts loaded_developer.name # should be "Developer: name" but it's just "name"
26+
```
27+
28+
*Dmitry Tsepelev*
29+
130
* Make the implicit order column configurable.
231

332
When calling ordered finder methods such as +first+ or +last+ without an

activerecord/lib/active_record/querying.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ module Querying
4040
def find_by_sql(sql, binds = [], preparable: nil, &block)
4141
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
4242
column_types = result_set.column_types.dup
43-
columns_hash.each_key { |k| column_types.delete k }
43+
cached_columns_hash = connection.schema_cache.columns_hash(table_name)
44+
cached_columns_hash.each_key { |k| column_types.delete k }
4445
message_bus = ActiveSupport::Notifications.instrumenter
4546

4647
payload = {

activerecord/test/cases/base_test.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,14 @@ def test_default_values_are_deeply_dupped
14471447
assert_not_respond_to developer, :first_name=
14481448
end
14491449

1450+
test "when ignored attribute is loaded, cast type should be preferred over DB type" do
1451+
developer = AttributedDeveloper.create
1452+
developer.update_column :name, "name"
1453+
1454+
loaded_developer = AttributedDeveloper.where(id: developer.id).select("*").first
1455+
assert_equal "Developer: name", loaded_developer.name
1456+
end
1457+
14501458
test "ignored columns not included in SELECT" do
14511459
query = Developer.all.to_sql.downcase
14521460

activerecord/test/cases/instrumentation_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
module ActiveRecord
77
class InstrumentationTest < ActiveRecord::TestCase
8+
def setup
9+
ActiveRecord::Base.connection.schema_cache.add(Book.table_name)
10+
end
11+
812
def test_payload_name_on_load
913
Book.create(name: "test book")
1014
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |*args|

activerecord/test/models/developer.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,17 @@ class DeveloperWithIncorrectlyOrderedHasManyThrough < ActiveRecord::Base
279279
has_many :companies, through: :contracts
280280
has_many :contracts, foreign_key: :developer_id
281281
end
282+
283+
class DeveloperName < ActiveRecord::Type::String
284+
def deserialize(value)
285+
"Developer: #{value}"
286+
end
287+
end
288+
289+
class AttributedDeveloper < ActiveRecord::Base
290+
self.table_name = "developers"
291+
292+
attribute :name, DeveloperName.new
293+
294+
self.ignored_columns += ["name"]
295+
end

0 commit comments

Comments
 (0)