> For the complete documentation index, see [llms.txt](https://prospect-io.gitbook.io/developer-playbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://prospect-io.gitbook.io/developer-playbook/our-stack/ruby-on-rails/tips-and-tricks.md).

# Tips and tricks

## Tips and Tricks

### ActiveRecord

#### **Generic warnings**

ActiveRecord is a very powerful component of rails. That's an abstraction between our models and the database, which allows to achieve many things.&#x20;

But sometimes, that comes at the cost of the performance. Ruby is good for many things, but manipulating a lot of data in Ruby can be sometimes very inefficient due to the cost of the memory that we use.&#x20;

So, when using ActiveRecord, let's think about the produced SQL statements and think if we could not optimize ActiveRecord usage by offloading some part of the work to the database.&#x20;

For instance:&#x20;

```ruby
# Don't do 
Account.last(10).map(&:name) 
# It produces SELECT * FROM accounts ; Then it selects the name

# Do 
Account.last(10).pluck(:name) 
# It produces SELECT name FROM accounts ; So it fetches less data

# Don't do 
Account.last(10).group_by(&:country).map do |k, v| [k, v.count] end
# It produces SELECT * FROM accounts ; Then it groups
  
# Do 
Account.last(10).group(:country).count.to_a 
# It produces SELECT company, count(*) FROM accounts GROUP BY country 
# so, this lets the database making the work  
```

#### N+1 request

One big performance killer of rails is the N+1 request. \
N+1 can occur in scenarios as the following:&#x20;

```ruby
Account.last(10).each { |account| puts(account.admin.name) } 
```

In that case, we can see in the database that the queries produced are:&#x20;

```
SELECT * FROM admin WHERE account_id = xxx 
SELECT * FROM admin WHERE account_id = xxx 
SELECT * FROM admin WHERE account_id = xxx 
SELECT * FROM admin WHERE account_id = xxx 
SELECT * FROM admin WHERE account_id = xxx 
SELECT * FROM admin WHERE account_id = xxx 
SELECT * FROM admin WHERE account_id = xxx 
SELECT * FROM admin WHERE account_id = xxx 
```

That's because we're asking the name of the account's admin, which is loaded, as with the account's admin while trying to access that value.&#x20;

Instead, it's better to pre-fetch all the data, using one of the following techniques:&#x20;

```ruby
# Method 1, using active record
Account.include(:admin).last(10).each do ... end 
# or 
Account.join(:admin).last(10).each do ... end 

# Method 2, doing manual pre-fetching 
Admin.where(account_id: Account.last(10).pluck(:id)).each do ... end 

# Method 3, doing a hash 
admins = Admin.where(account_id: Account.last(10).pluck(:id))
                  .group_by(&:account_id) 
Account.last(10).each do |account| puts(admins[account.id].first.name) end 
```

#### Reset columns information in a migration

*r*[*eset\_column\_information*](https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema/ClassMethods.html#method-i-reset_column_information) is a useful method when just after creating a table or a column in a migration, you want to populate it with some default values.

Without it, the following migration will throw an error on line 7 stating that *is\_happy* does not exist on the table *employees*:

```ruby
class AddHappyToEmployees < ActiveRecord::Migration[5.1]
  def change
    add_column :employees, :is_happy, :boolean, default: false

    Employee.reset_column_information
    
    Employee.where(company: 'Prospect.io').update_all(is_happy: true)
  end
end
```

### Rails Migration

#### Interesting article on Zero Downtime&#x20;

Read this article to better understand steps you can put in place to ensure that you rails migration are not locking the DB in production.

<https://medium.com/klaxit-techblog/zero-downtime-migrations-with-activerecord-47528abe5136> &#x20;

###

### Rails console

#### Using reload!&#x20;

When interacting into the rails console, using `reload!` will reflect changes made into the code immediately, without the need to quit and re-open console.

```
$ rails c
pry> Account.new_method
NoMethodError: undefined method `new_method' for #<Class:0x00007f94daf8ede8>
Did you mean?  undef_method

// define `new_method` into account.rb

pry> reload!

// `new_method` will immidiately be available
pry> Account.new_method
```
