Modular Models in Ruby on Rails

Models like blog/post and blog/comment are examples of modular models. They help to separate functionality from the rest of the project and it's easy to do in rails just a little config and go.

Modular Models in Ruby on Rails

Every so often we want our models not just in model folder but in module in a folder with many advantages inclusive.

One advantage is maybe those table names are already in project, so by putting a prefix of module name can make the table uniqueness.

Next advantage is you want to put the functionality separate with the rest of the project, we can use modular models.

Last advantage is making engines to be used in other projects, including tables, can be easy using prefixed tables.

How to do it? It’s easy!

Let’s assume we want a blog to our project, which is a separate functionality than the rest of the project. So, we will be creating two models, Post and Comment.

Therefore, run in the project:

rails g model blog/post title:string body:text 

This will create a model with the following files:

blog.rb

# app/models/blog.rb

module Blog
  def self.table_name_prefix
    'blog_'
  end
end

blog/post.rb

# app/models/blog/post.rb

module Blog
  class Post < ApplicationRecord
	validates :title, presence: true
	validates :body, presence: true
  end
end

And the migration file will create the table named blog_posts not just simple posts.

Now, creating the comments in the post is somewhat tricky.

Run the following in the terminal:

rails g model blog/comment body:text blog_post:references user:references

This will ask to override the blog.rb which is not needed at the moment.

The new file of comment model needs to be updated:

# app/models/blog/comment.rb

module Blog
  class Comment < ApplicationRecord
    validates :body, presence: true
    belongs_to :blog_post, class_name: 'Blog::Post'
  end
end

And update the post model with relation:

# app/models/blog/post.rb

has_many :comments, class_name: 'Blog::Comment', dependent: :destroy, foreign_key: :blog_post_id, inverse_of: :blog_post

Final ponts

So now we have modular models in the project. Tables created will be blog_posts and blog_comments. Anywhere in project to call post model you have to use Blog::Post like Blog::Post.find 12. But we can use .comments like:

# rails console
post = Blog::Post.find 1
post.comments.last
# similar for comments
comment = Blog::Comment.last
comment.post.title

However, in database we will have blog_posts table and blog_comments table with foreign key blog_post_id.


Happy Coding!