Algumas dicas sobre inclusões e junções nos trilhos 3

Trabalhando com tabelas auxiliares de banco de dados em trilhos, muitas vezes vejo carregamento de dados muito abaixo do ideal nos controladores (especialmente para índice) que resulta em baixo desempenho do aplicativo. Use inclui e junta , eles são seus amigos!

class Item
belongs_to
:user
end

class User
has_many
:items

def permissioned_name
if can_see?
name

else
"Mister"
end
end

def can_see?
Time.now == Time.now.midnight # shows real name only on midnight
end
end

Isso geralmente é ruim em uma visualização de índice:

items = Item.all

items
.each do |i|
i
.user.name # this will result in a separate query for each user, N queries where N is Item.count
end

Como regra geral , as junções devem ser usadas quando precisamos de dados puros ou agregação de dados de outra tabela e inclui quando você precisa de dados + lógica.

Bom uso de incluir:

items = Item.includes(:users) # Loads all items, loads all users. Big memory and ActiveRecord init cost

items
.each do |t|
i
.permissioned_name # this will not result in N queries, since rails will preload users association
end

Uso subótimo de include, melhor do que não usá-lo:

items = Item.includes(:users) # Loads all items, loads all users. Big memory and ActiveRecord init cost

items
.each do |i|
i
.user.name # No additional query, but we are just taking one data field from user, why do we need all the heavy AR?
end

Use joins para acessar dados:

items = Item.joins(:users).group("item.id").select("items.*, count(users.id) as user_count")
# this will result in query like this:
# SELECT items.*, count(users.id) as user_count FROM `items` INNER JOIN `users` ON `items`.`user_id` = `users`.`id` GROUP BY items.id

items
.each do |i|
i
.user_count # notice that I can't use i.users.size, I have to use method user_count (which accesses the attribute loaded from DB)
end

Para se divertir, nunca use isso:

items = Item.includes(:users) # Loads all items, loads all users. Big memory and ActiveRecord init cost

items
.each do |i|
t
.users.count # N queries to DB for users count since count method is used!
end