-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Additional types of ResultSet should not contain keys of #attributes_to_define_after_schema_loads #34528
Additional types of ResultSet should not contain keys of #attributes_to_define_after_schema_loads #34528
Conversation
What you are seeing is the expected behavior in my opinion. Because you ignored the column Rails should not know how to handle it coming from the database. |
Thanks for the feedback! This behaviour seemed confusing to me, because the doc says that "Ignored columns won't have attribute accessors defined", but since we do have the accessor (because of |
I agree the behavior should be consistent, so we need to understand why with no changes your test pass in MySQL and SQLite and not in PostgreSQL and make it work in PostgreSQL without adding |
@@ -40,7 +40,7 @@ module Querying | |||
def find_by_sql(sql, binds = [], preparable: nil, &block) | |||
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable) | |||
column_types = result_set.column_types.dup | |||
columns_hash.each_key { |k| column_types.delete k } | |||
columns_hash.merge(attributes_to_define_after_schema_loads).each_key { |k| column_types.delete k } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that it is better to always use the connection.schema_cache.columns_hash
here. attributes_to_define_after_schema_loads
can contain attributes that are not in the database and we use this just to remove from column_types
c67ee5d
to
0fbdcad
Compare
I've traced the code to figure out why this issue does not affect other adapters. |
Cool! Thank you for investigating. What do you think on my suggestion of always using the column_hash returned by the schema cache on that line? |
I've added it to my commit, waiting for the tests to pass :) Thanks for the suggestion |
f14b765
to
6e531b9
Compare
6e531b9
to
d34c1fc
Compare
|
Great work on this |
Additional types of ResultSet should not contain keys of #attributes_to_define_after_schema_loads
First of all, let me explain my use case: I have a heavy JSONB DB column which I want to exclude from most of the queries, that's why I've decided to use ignored_columns feature. This column is populated via DB trigger, and sometimes I do want to have it loaded, in such cases I explicitly load it (for instance, using
.select("*")
). Also, I have a customActiveRecord::Type
to make interactions with the underlying JSON easier. The problem is that with this combination the value I get when I call that accessor is a value from the DB, custom type is completely ignored.Here is a simplier example with a string instead of JSON:
Here is a reason why it happens:
ignored_columns
removes the column from the column_hash#select_all
can fillcolumn_types
for the result set when DB provides the types (only PostgreSQL does it, so other tests for other DBs cannot reproduce the problem)#find_by_sql
prepares theActiveRecord::Result
, it usescolumn_hash
to remove all the types coming from the DB because we know how to handle themcolumn_hash
so#find_by_sql
defines the accessor method with the DB-provided type and customattribute
is ignoredMy solution is to remove
attributes_to_define_after_schema_loads
keys from thecolumn_types
along withcolumn_hash
keys because having the custom attributes means that we do know how to deserialize this field.