Search code examples
ruby-on-railsactiverecordpolymorphic-associations

Aliasing names of polymorphic associations


I'm trying to implement a polymorphic association in a project for the first time but I'm not a fan of how the associations read and was wondering if there's a way of aliasing them?

Example:

# app/models/comment.rb
class Comment < ActiveRecord::Base
  belongs_to :commentable, :polymorphic => true
end

# app/models/post.rb
class Post < ActiveRecord::Base
  has_many :comments, :as => :commentable
end

# app/models/picture.rb
class Picture < ActiveRecord::Base
  has_many :comments, :as => :commentable
end

Let's say I wanted to retrieve a Post instance from a given Comment, terrific_post = Comment.first.commentable just doesn't read well in my opinion. Is there a way to alias different association names in the Comment model and avoid relying on a single name such as commentable? I realize you could choose a name which aligns better to your specific dsl rather than say "commentable", however I'd prefer to continue referring to associations with names (or variations) based on their relationships, similar to Comment.first.post and `Comment.first.picture' if at all possible.

At the end of the day it's not a big sacrifice for the flexibility you get with polymorphic associations. Just curious if a solution exists.

Note: the following example was taken from The Odin Project which does a great job explaining various types of associations.


Solution

  • You can alias an association like any other method:

    class Comment < ActiveRecord::Base
      belongs_to :commentable, :polymorphic => true
      alias_method :post, :commentable
      alias_method :picture, :commentable
    end
    

    And you can then do Comment.first.post and Comment.first.picture.

    But Comment.first.post can be either a Post or a Picture, so you should know what are you doing.

    Another approach would be implement methods that return post only if commentable is a Post and picture only when commentable is a Picture:

    class Comment < ActiveRecord::Base
      belongs_to :commentable, polymorphic: true
    
      def post
        commentable if commentable.is_a? Post
      end
    
      def picture
        commentable if commentable.is_a? Picture
      end
    end