November 23, 2018

ActiveRecord on a Leash

Rails’ ActiveRecord gives you great power and as we all know with such comes great responsibility.

Just inheriting from ApplicationRecord unlocks a huge interface at your disposal and it is very easy to fell into a trap and find yourself using it from everywhere in your application - controllers, views and other models.

Over the years I found there is one simple rule that helps me keep it all under control.

Treat all ActiveRecord methods as protected.

That is it.

Every time you want to read or write data from the database create your own method, name it something meaningful to your application domain and encapsulate the business logic there. Of course you may make few exceptions for some methods or in some cases but the more you try to follow this rule the better.

I have even found useful to apply this to basic methods like find, especially when you soft-delete your records. For example:

class BlogPost < ApplicationRecord
  def self.[](id)
    not_deleted.find(id)
  end
end

2.4.5 :006 > BlogPost[123]
DEBUG -- :   BlogPost Load (3.9ms)  SELECT  `blog_posts`.* FROM `blog_posts` WHERE `blog_posts`.`deleted_at` IS NULL AND `blog_posts`.`id` = 123 LIMIT 1
 => #<BlogPost id: 123, title: "ActiveRecord on a Leash", ...>

Yes, you can use default scope instead, but I personally will rather not.

Overall this approach is not something revolutionary, does not get you out of the Rails Way and is easy to apply while helps you keep your application sane.

Powered by Hugo & Kiss.