# 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
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://prospect-io.gitbook.io/developer-playbook/our-stack/ruby-on-rails/tips-and-tricks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
