Ruby & Rails guidelines

We follow the Rubocop official Rubocop Ruby coding style guidearrow-up-right as the primary source of best practices and conventions.

1.Do's and Don'ts

Add and follow the official MarsBased Rubocop configurationarrow-up-right, where most of rules are already defined, highlighting these two:

  • Use single quotes when possible.

  • Max length of 90 characters

1.1.Use Dotenv for environment variables

We use the Dotenvarrow-up-right gem for managing the environment variables.

1.2.Loading in batches

Don't iterate unlimited / big queries directly. Use find in batches for loading big queries:

1.3.Avoid Active Record callbacks with side effects

Avoid using Active Record callbacks unless it's related to data persistence specially avoiding side effects like sending and e-email.

Consider using the command patternarrow-up-right to send the e-mail from a controller action.

1.4.Avoid raw SQL queries

Avoid writing raw SQL queries unless strictly necessary.

When using Active Record we have the full power of it. For example if we have a custom serialization for a column, Active Record will automatically convert the value when writing queries.

When writing more complex queries you may use Arel or write the where clause manually. However take into account that if you write it manually you won't have the full power of Active Record, like:

  • You will not be able to use alias attributes.

  • You will not be able to use custom types (serialization and deserialization).

1.5.Size instead of count

Use size instead of count unless you are doing a direct count on a table. Using count always triggers a query while using size is able to use the cached values of a previous query.

1.6.Avoid N+1 Queries with includes

When you have to access an association, avoid N+1 query problems, you can use includes to eager load the associated records:

You can find some more examples in the Active Record guide.

1.7.Avoid Default Scope

In order to avoid unexpected and hidden behaviour, avoid using default_scope and use named scopes and explicit uses of those scopes:

1.8.Use find_by for instead where().first

When retrieving a single record from the database, don’t use where(...).first, use find_by instead. And similarly when selecting a single item from a collection use find { ... } instead of select { ... }.first.

1.9.Check database constraints

Check that constraints are correct and that they match the validations. A typical example is adding a default without a not-null constraint.

1.10.Filter sensitive parameters in logs

When receiving parameters in a controller that contain sensitive information like a password or secret key, add the name of the parameter to the list of filtered parameters. Note that :password is already filtered by default.

2.General project organization and architecture

Follow the standard generated directory structure at project initialization with rails new project_name as described in Ruby On Rails Guidearrow-up-right.

Additionally:

  • Services under the /app/services directory.

  • Commands under the /app/commands directory.

  • Presenters under the /app/presenters directory.

  • Query objects under the /app/queries directory.

  • Form objects under the /app/form_objects directory.

2.1.Project structure example

3.Common Patterns

3.1.Devise (Authentication)

Skip all the default routes generated by devise on routes.rb and create custom controllers and views according to the requirements.

routes.rb

Sessions Controller example: app/controllers/sessions_controller.rb

New session view example: app/views/sessions/new.html.erb

3.2.Testing

We use the Rspecarrow-up-right testing framework and usually we write these kind of tests:

  • Unit tests for models, commands, jobs.

  • System tests for integration.

  • Request specs for APIs.

  • Avoid controller tests: controllers functionality is already covered by integration specs.

3.2.1.Testing Best Practices

3.2.1.1Use let

When you have to assign a variable to test, instead of using a before each block, use let. It is memoized when used multiple times in one example, but not across examples.

3.2.1.2Use factories

Use factory_botarrow-up-right to reduce the verbosity when working with models.

spec/factories/user.rb

Using the factory

3.2.1.3Describe Methods

When testing a method, create a describe block with the name of the method and place the specs inside. Use "." as prefix for class methods and "#" as prefix for instance methods.

4.Gems

Last updated