Best practices for writing and collaborating on Rails code
Here are some best practices for writing code and working better together as a team.
These same principles were used in all the organizations I worked in and apply to any Rails dev team.
1. Teamwork #
Prefer written communication.
Have meetings only when writing would take longer.
Promote independency in decision making.
2. Coding together #
main
/master
branch should accept changes only via Pull Request.
Do not review DRAFT Pull Requests.
Pull Request should require 1 approval and a passing CI to be merged.
Do not merge a PR if you are not the author.
Trust your colleagues best intentions.
If you are stuck - ASK FOR HELP.
Pair coding can help in getting unstuck and create a “productivity rush”.
3. Coding in general #
The less code you write, the less code there is to maintain. In a mature app, aim to be “code-neutral” (delete at least as much as you add).
Do not overcomplicate. Look for the shortest good path to solve a problem.
Do not reinvent the wheel. Search for an existing solution before rolling out your own.
Good code does not require a lot of comments to explain it.
4. Writing Rails code #
Views #
Do not disable turbo by default in the app. The limitations of turbolinks are irrelevant in 2023.
Do not use <a>
tag. Use link_to
instead.
Do not embed SVG code in an HTML page. Store the SVG as a separate object and use gem inline_svg
to render it.
Prefer using ViewComponents over _partials. Here are some rules of thumb:
- logic that you would pass in locals? VC
- view rendering logic? VC
- non-reusable HTML abstraction? partials
- reusable HTML? partials
When using ViewComponent, try to store all the view login in the .rb
file, not in the .html.erb
file.
Do not store view logic in a Rails model. Use app/helpers
, app/components
, app/decorators
instead.
Do not use jQuery and jQuery-based libraries.
If you can’t render a turbo_stream as a one-liner in a controller, use a *.turbo_stream.erb
template.
When writing text, use “sentence case capitalization”:
- Bad: “These Are Some Words”
- Good: “These are some words”
Design patterns #
Use app/services
to extract complex logic and test it in isolation.
As you application gets complex, you can use a more advanced system of design patterns:
-
app/services
for working with exteranal APIs (Twilio::SendSms
) -
app/operations
for working with (Book::GenerateBarcode
) -
app/interactors
for extracting logical sequences (if Book::GenerateBarcode.success? ? Twilio::SendSms
)
Models #
When doing database migrations, don’t forget to validate null
and default
on the database level.
Avoid using ActiveRecord callbacks. Call methods explicitly when needed.
Testing #
Always use a CI tool for:
- code style: rubocop, prettier, erblint
- tests
Minitest or Rspec? Does not matter. FactoryBot is more versatile that fixtures. Ultimately, use the tools that you feel more comfortable with.
When testing, focus on writing good Controller and System tests.
🤔💠I will be adding more to the list, if I remember something.
Other #
Prefer storing text in en.yml
i18n file and inheriting from there.
- Bad:
redirect_to posts_path, notice: 'post created!'
- Good:
redirect_to posts_path, notice: t('.success')
Prefer symbols over strings:
- Bad
"payment pending"
- Good:
:payment_pending
Use gem Pagy for pagination. WillPaginate and Kaminari are simply not as great.
Do not use magic strftime
Do not use magic strings:
- Bad:
tax_amount = price * 0,17
- Good:
TAX_AMOUNT = 0,17
&&tax_amount = price * TAX_AMOUNT
Did you like this article? Did it save you some time?