-
Note: This is outdated - I've updated my recommendations on about 30% of this. For my most recent recommendations see H1 Rails
-
This is the post I point to when explaining (to friends, employees, contractors), what my current design patterns for Rails are. These standards are designed to keep codebases as contributor-friendly as possible.
-
Contributor-Friendliness may not be a priority for everyone, but because we run an agency, we need to be able to move new developers in and out of a codebase with minimal cognitive friction/overhead. The more layers (of complexity and libraries) that we've added to a codebase, the longer the learning curve for a new developer.
-
For example, it's reasonably common that we need to hand a codebase off to a team or developer that has no experience with Rails. The more esoteric the codebase, the more time we need to spend explaining and helping them get set up.
-
Many of these ideas/principles are also outlined more generally on html-first.com.
-
-
Use HTML over view helpers when the view helper adds nothing
-
Do Images Like This
-
<img src="PATH_HERE" /> -
Not Like This
-
<%= image_tag "myimage.png" %> -
Do Links Like This
-
<a href="<%= my_path %>">Click Here</a> -
Not Like This
-
<%= link_to "Click Here", my_path %> -
-
Routes
-
The Rails routes.rb API is one of the most unnecessarily obscure parts of Rails. Using keywords like
resourcesandcollectionadd very little value and mean that you have to open a terminal window and run a command in order to fully understand what's happening. Given that defining a route is conceptually a very straightforward task which only requires a single line of code per route, it doesn't make sense not to just keep theroutes.rbfile simple so that new developers can just look at it to understand what's happening (as opposed to runningrails routesin a terminal). -
Define routes like this
-
get "/orders" => "orders#index", :as => "orders" get "/oders/:id" => "orders#show", :as => "order" post "/oders/:id" => "orders#edit", :as => "edit_order" -
Not This
-
resources :orders -
-
Gems
-
Because there are so many gems, and they're very easy to install, there's a tendency, particularly among early-career developers, to reach for gems for everything. This is a tendency that should be consciously restrained, because every new gem (usually) comes with it's own syntax that needs to be learned, and it's own maintenance burden.
-
Avoid gems whose only job is to provide a nicer syntax on top of an existing public API. Calling the API endpoint directly using something like HTTParty is almost always more expressive, more familiar, and more maintainable.
-
Avoid gems whose only job is to load in a CSS or javascript library. When those libraries inevitably need to be extended or upgraded, you have little to no control to modify them. And there is generally limited benefit to using a gem beyond slightly fewer lines of code.
-
Avoid gems that are very-slightly better at something that can be done with plain old Ruby or Rails, when that moderate improvement is not needed. The best example of this is using something like Ransack for pages with very simple, known filters. Rails already has a way to do what Ransack does, and while it might be slightly more verbose, it's also one less concept to be learned and library to be maintained.
-
-
-
Use inline_svg for SVGs
-
In an ideal world, we would just use
<img src="icon.svg" />for this. But unfortunately this won't allow us to control the icon's color with CSS or tailwind classes, which is something we want to do very regularly. I still haven't found a neat way around this, so today I'm still recommending using the inline_svg gem. -
# Gemfile gem 'inline_svg' -
<%= inline_svg("/icons/user.svg", class:"text-blue-900 w-4") %> -
-
Avoid The Asset Pipeline
-
The current default way to manage assets in Rails is called the Asset Pipeline. Using it requires understanding several different concepts and being able to deal with issues, particularly during local development.
-
But using the asset pipeline in Rails is not actually necessary. Instead, we can use plain old HTML. All we have to do is place our files in the
/publicfolder, and then reference them from our codebase. We've been doing this for over a year now and have had to make exactly zero trade-offs when it comes to performance and user experience. This is partly because, as you'll see below, we just don't need to load that much javascript and css. -
Load assets like this
-
<link href="/stylesheets/variables.css<%= cache_buster %>" rel="stylesheet" > <script src="/js/htmx.min.js<%= cache_buster %>" defer></script> <img src="/images/my_image.png"> -
Not Like This
-
<%= stylesheet_link_tag 'application', media: 'all' %> <%= javascript_pack_tag 'application' %> <%= image_tag "my_image.png" %> -
-
CSS
-
Use Base Styles for simple components, Tailwind (Litewind) for Single Purpose Classes, and add customizations where required.
-
-
JS
-
First, check Base Styles to see if you can do what you need without JS (you'd be surprised).
-
Use Mini Js for simple frontend state and more advanced components.
-
-
Smooth transitions/ Async Behaviour
-
Another limitation of the web platform is that loading new content, transitioning between screens, and submitting information via forms currently feels slow. We get around this by using htmx to navigate between pages, and submit forms.
-
Here's a short article that shows one of the common patterns we use for submitting forms in Rails asynchronously. (This example is optimised for efficiency but I'm currently exploring simplifying this further by simply recommending hx-boost on the body, but I haven't experimented enough with this yet to know all of its limitations).
-
-
Managing State
-
Opting not to use a rich frontend library, and instead to use something like htmx, whose underlying philosophy is Hypertext as the Engine of Application State, means that there are times when we need to store state on the server where we otherwise might not. There's no clear set of patterns here, but one useful pattern is outlined in this article - Multi Step Forms in Rails.
-
-