Title
ActiveRecord#joins
can’t join delegated table if the model is defined with delegated_type method.
summary
ActiveRecord#joins
says error messages if I execute INNER JOIN
delegated table with the symbol which is association method’s name of the table.
environment
- Ruby: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [aarch64-linux]
- Rails: 7.0.4
- activerecord 7.0.4
Steps to reproduce
- Create DelegatedType-ed table and models in your Rails App.
class Chat::Message < ApplicationRecord
delegated_type :messageable, types: %w[
Chat::NormalMessage
Chat::NotifyMessage
],
dependent: :destroy
...
end
class Chat::NormalMessage < ApplicationRecord
included do
has_one :message, as: :messageable, touch: true, dependent: :destroy
end
end
- Call joins method with a symbol of delegated table
irb(main):006:0> Chat::Message.last(2).first.chat_normal_message
Chat::Message Load (9.5ms) SELECT `chat_messages`.* FROM `chat_messages` ORDER BY `chat_messages`.`id` DESC LIMIT 2
Chat::NormalMessage Load (6.8ms) SELECT `chat_normal_messages`.* FROM `chat_normal_messages` WHERE `chat_normal_messages`.`id` = 449 LIMIT 1
=> #<Chat::NormalMessage:0x0000ffffac1dfa40 id: 449, body: "test", created_at: Thu, 07 Sep 2023 13:34:48.000000000 JST +09:00, updated_at: Thu, 07 Sep 2023 13:34:48.000000000 JST +09:00>
irb(main):011:0> Chat::Message.joins(:chat_normal_message)
actual result
Rails console says ActiveRecord::ConfigurationError.
irb(main):011:0> Chat::Message.joins(:chat_normal_message)
An error occurred when inspecting the object: #<ActiveRecord::ConfigurationError: Can't join 'Chat::Message' to association named 'chat_normal_message'; perhaps you misspelled it?>
Result of Kernel#inspect: #<Chat::Message::ActiveRecord_Relation:0x0000ffffac06ce10 @klass=Chat::Message(id: integer, room_id: integer, property_bulk_suggestion_id: integer, messageable_id: integer, messageable_type: string, sender_type_id: integer, staff_id: integer, status_id: integer, created_at: datetime, updated_at: datetime), @table=#<Arel::Table:0x0000ffffae925be0 @name="chat_messages", @klass=Chat::Message(id: integer, room_id: integer, test_id: integer, messageable_id: integer, messageable_type: string, status_id: integer, created_at: datetime, updated_at: datetime), @type_caster=#<ActiveRecord::TypeCaster::Map:0x0000ffffae924f60 ...
expected result
Got an array of ActiveRecord instances with INNER JOIN
delegated table.
irb(main):024:0> Chat::Message.joins(:chat_normal_message)
Chat::Message Load (23.7ms) SELECT `chat_messages`.* FROM `chat_messages` INNER JOIN chat_normal_messages ON chat_messages.messageable_type = "Chat::NormalMessage" AND chat_messages.messageable_id = chat_normal_messages.id
=>
[#<Chat::Message:0x0000ffffac12b1a8
id: 1,
...]
additional information
I’ve confirmed that INNER JOIN is effective if I pass a raw SQL statements as a parameter of the joins
method.
irb:1:0* join_chat_normal_messages = 'INNER JOIN chat_normal_messages ' \
irb:2:0* 'ON ' \
irb:3:0* 'chat_messages.messageable_type = "Chat::NormalMessage" ' \
irb:4:0> 'AND chat_messages.messageable_id = chat_normal_messages.id'
=> "INNER JOIN chat_normal_messages ON chat_messages.messageable_type = \"Chat::NormalMessage\" AND chat_messages.messageable_id = chat_normal_messages.id"
irb:5:0> Chat::Message.joins(join_chat_normal_messages)
Chat::Message Load (21.0ms) SELECT `chat_messages`.* FROM `chat_messages` INNER JOIN chat_normal_messages ON chat_messages.messageable_type = "Chat::NormalMessage" AND chat_messages.messageable_id = chat_normal_messages.id
=>
[#<Chat::Message:0x0000ffffac9ef4b0
id: 1,
...]