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!
Top comments (4)
db_belongs_to
🤔? It's from some gem, not Rails itself, right?Right out of rails☺️
How so?
My mistake... I was using gem
database_validations
but we can usebelongs_to
as well. So I have updated it. Thanks for errata :-)