This is something I recently noted while working at my new employer’s codebase.
The platform that I work on at my current full time job is your standard Rails application with some Backbone sprinkled in there for organizing JavaScript code. The first thing I noticed when I started working on this new codebase was that the way the code in ActiveRecord models were written was very different than the codebases that I’ve come across before and the way I like to write my Rails models.
I think a simple example will help explain the differences I’ve noticed a lot better. Normally, when I write a typical model in a Rails app, I like to group different types of code together. For example, I like to put all of my validations in one place, all of my class methods in another, all of my instance methods in another, and etc. For example, let’s say that we have your average User
model.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class User < ApplicationRecord ROLES = %w(user admin superadmin) validates :first_name, presence: true validates :last_name, presence: true validates :role, inclusion: { in: ROLES } before_save :set_full_name, :set_slug def set_slug self.slug = "#{first_name}-#{last_name}".downcase end def set_full_name self.full_name = "#{first_name} #{last_name}" end end |
This could be your typical Rails model that represents a User
. However, if I rewrite this User
model following the style guide of the codebase that I work full time on, it’ll look like this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class User < ApplicationRecord validates :first_name, presence: true validates :last_name, presence: true ROLES = %w(user admin superadmin) validates :role, inclusion: { in: ROLES } before_save :set_slug def set_slug self.slug = "#{first_name}-#{last_name}".downcase end before_save :set_full_name def set_full_name self.full_name = "#{first_name} #{last_name}" end end |
See how the ROLES
constant was moved to above the validates :role
validation and the set_slug
and the set_full_name
before_save callbacks were moved right above to the methods that they’re calling.
If I’m being 100% honest, I find this coding style to be kind of ugly. However, I’ve noticed that organizing my Rails model this way provides a huge advantage in that I find it easier to dissect the immediate impact of each method, variable, constants, and etc has on my model. The above User
model is a very simple example, but in real production applications, you’ll find models that span hundreds or even a few thousands of lines long. In these large classes, it’s a huge advantage to look at a method and immediately know that it’s being called in an ActiveRecord callback, whether the method includes any variables that are required by the model to be valid, and etc.
I still don’t know for sure which style I prefer. The style in the second example is new to me, and I still think it kind of looks ugly, but I have to admit that it gives me a better insight into what the code is actually doing at first glance rather than having to skip around a large Ruby file trying to figure out how the code actually works.