I have inherited some legacy rails code with workarounds around standard polymorphic associations. These used to work up until rails 5. Now I am trying to upgrade to rails6.1 and they break and I have no clue as to how to fix them.
Problem: We have following 2 tables:
posts
- id
- text
- ...
comments
- id
- commentable_id
- commentable_type
- ...
A post has 3 types of comments -
- Admin comment
- Anonymous comment
- User comment
We have modeled this as polymorphic relationship as follows:
# comment.rb
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
# post.rb
class Post < ActiveRecord::Base
has_many :comments, as :commentable, dependent: :destroy, inverse_of: :post
has_many :admin_comments, -> { where commentable_type: "AdminComment" },
class_name: 'Comment', foreign_key: :commentable_id,
foreign_type: :commentable_type, dependent: :destroy, inverse_of: :post
has_many :user_comments, -> { where commentable_type: "UserComment" },
class_name: 'Comment', foreign_key: :commentable_id,
foreign_type: :commentable_type, dependent: :destroy, inverse_of: :post
has_many :anonymous_comments, -> { where commentable_type: "AnonymousComment" },
class_name: 'Comment', foreign_key: :commentable_id,
foreign_type: :commentable_type, dependent: :destroy, inverse_of: :post
end
With this setup, I could fetch either all comments by doing -
p = Post.find(123)
p.comments
or fetch comments by specific type of user -
p = Post.find(123)
p.user_comments
p.anonymous_comments
With rails 6.1 this setup does not work.
When trying to run rails console It fails with error:
ruby2.7.x/lib/ruby/gems/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/core_ext/hash/keys.rb:52:in `block in assert_valid_keys': Unknown key: :foreign_type. Valid keys are: :class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading, :autosave, :before_add, :after_add, :before_remove, :after_remove, :extend, :counter_cache, :join_table, :index_errors, :ensuring_owner_was (ArgumentError)
After looking for potential answers online, the closest I could get was by adding as: :commentable to each association like -
has_many :user_comments, -> { where commentable_type: "UserComment" },
class_name: 'Comment', foreign_key: :commentable_id,
foreign_type: :commentable_type, dependent: :destroy, inverse_of: :post, as: :commentable
But this does not get me correct result set. It generates sql as follows -
SELECT comments.* FROM comments WHERE comments.commentable_id = 123 AND comments.commentable_type = 'Post' AND comments.commentable_type = 'UserComment'
without as: :commentable it would generate sql as -
SELECT comments.* FROM comments WHERE comments.commentable_id = 123 AND comments.commentable_type = 'UserComment'
I am kinda lost and would appreciate any help!
Thanks!