Polymorphic associations In Ruby on Rails
Efficiently Modeling Relationships Across Diverse Entities with Polymorphic Associations in Ruby on Rails
What is a polymorphic association?
A polymorphic association is a design pattern used in object-relational mapping (ORM) and database schema design to enable a model or table to be associated with multiple other types of models or tables. It provides a flexible and reusable way to model relationships between different entities in a database.
In the context of databases, a polymorphic association involves creating a single table with columns that can store information about the relationships between multiple entities. This table usually includes a reference to the related record (foreign key), as well as a column indicating the type of entity being referenced (e.g., ‘commentable_type’).
In the context of an ORM, such as Ruby on Rails’ ActiveRecord, a polymorphic association allows a single model to be associated with multiple other models without the need for creating multiple join tables or foreign key columns. This is achieved by specifying the association as ‘polymorphic’ in the model definition and including the type information when saving or querying the relationship.
An example of a polymorphic association could be a “Comment” model that can be associated with various entities, like “Posts” or “Images”. Instead of creating separate tables or columns for each relationship, you could create a single “comments” table that would store the foreign key and entity type for each association. This approach allows for greater flexibility and easier maintenance, as you can add new types of entities that can have comments without altering the existing schema or model definitions.
How do you create a polymorphic association in Rails 7
To implement a polymorphic association in Rails 7, you can follow these steps
Create the migration for the polymorphic association
First, create a migration that adds the necessary columns for the polymorphic association. In this example, we’ll use a “Comment” model associated with “Post” and “Image” models.
Generate a migration for the “comments” table:
rails generate migration CreateComments
Edit the generated migration file (e.g., db/migrate/XXXXXXXXXXXX_create_comments.rb
) to include the foreign key and entity type columns:
class CreateComments < ActiveRecord::Migration[7.0]
def change
create_table :comments do |t|
t.text :content
t.references :commentable, polymorphic: true, null: false
t.timestamps
end
end
end
Run the migration
rails db:migrate
Create the associated models
Create the “Comment” model
# app/models/comment.rb
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
Update the “Post” and “Image” models to include the polymorphic relationship:
# app/models/post.rb
class Post < ApplicationRecord
has_many :comments, as: :commentable
end
# app/models/image.rb
class Image < ApplicationRecord
has_many :comments, as: :commentable
end
Use the polymorphic association in your controllers and views
Now, you can use the polymorphic association in your controllers and views. For example, when creating a new comment for a post, you can do:
# app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
@commentable = find_commentable
@comment = @commentable.comments.build(comment_params)
if @comment.save
redirect_to @commentable, notice: 'Comment was successfully created.'
else
render :new
end
end
private
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
def comment_params
params.require(:comment).permit(:content)
end
end
And in your views, you can display comments for both “Post” and “Image” models:
<!-- app/views/posts/show.html.erb -->
<h2>Comments</h2>
<%= render partial: 'comments/comment', collection: @post.comments %>
<!-- app/views/images/show.html.erb -->
<h2>Comments</h2>
<%= render partial: 'comments/comment', collection: @image.comments %>
Now you have implemented a polymorphic association in Rails 7 that allows the “Comment” model to be associated with both “Post” and “Image” models.