Home Rails includes vs all?
Reply: 1

Rails includes vs all?

Iggy
1#
Iggy Published in 2018-01-12 20:02:17Z

I am going back to refresh my Rails knowledge by watching some tutorials, and I came across where the tutorial rails app uses includes() on index.

  def index
    @books = Book.all
  end

vs

  def index
    @books = Book.includes(:author, :genre)
  end

As a side note, book belongs_to author and genre. Author has_many books and genre also has_many books.

When all is used, it looks like this when I refresh page:

 Rendering books/index.html.erb within layouts/application
  Book Load (1.4ms)  SELECT "books".* FROM "books"
  Author Load (0.3ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
  Genre Load (0.3ms)  SELECT  "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
  Author Load (0.4ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Genre Load (0.3ms)  SELECT  "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
  CACHE (0.0ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  CACHE (0.0ms)  SELECT  "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
  CACHE (0.0ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  CACHE (0.0ms)  SELECT  "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]

When includes is used, when I reload the page it shows:

  Rendering books/index.html.erb within layouts/application
  Book Load (0.4ms)  SELECT "books".* FROM "books"
  Author Load (0.5ms)  SELECT "authors".* FROM "authors" WHERE "authors"."id" IN (2, 1)
  Genre Load (0.4ms)  SELECT "genres".* FROM "genres" WHERE "genres"."id" IN (2, 3)

I think this makes includes far more efficient than all because it hits the entire model database.

My question is, why do people still use all? Why not completely eradicate all and use includes from now on? Is there any situation where I would prefer to use all and not use includes? I am using Rails 5.0.1.

Phong Phan
2#
Phong Phan Reply to 2018-01-13 07:09:11Z

Let me talk a little bit about includes.

Suppose you need to get the user name of first five post. You quickly write the query below and go enjoy your weekend.

posts = Post.limit(5)

posts.each do |post|
  puts post.user.name
end

Good. But let's look at the queries

Post Load (0.5ms)  SELECT  `posts`.* FROM `posts` LIMIT 5
User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE  `users`.`id` = 1 LIMIT 1
User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE  `users`.`id` = 1 LIMIT 1
User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE  `users`.`id` = 2 LIMIT 1
User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE  `users`.`id` = 2 LIMIT 1
User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE  `users`.`id` = 1 LIMIT 1

1 query to fetch all posts and 1 query to fetch users for each post results in a total of 6 queries. Check out the solution below which does the same thing, just in 2 queries:

posts = Post.includes(:user).limit(5)

posts.each do |post|
  puts post.user.name
end

#####

Post Load (0.3ms)  SELECT  `posts`.* FROM `posts` LIMIT 5
User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 2)

There’s one little difference. Add includes(:posts) to your query, and problem solved. Quick, nice, and easy.

But don’t just add includes in your query without understanding it properly. Using includes with joins might result in cross-joins depending on the situation, and you don’t need that in most cases.

If you want to add conditions to your included models you’ll have to explicitly reference them. For example:

User.includes(:posts).where('posts.name = ?', 'example')

Will throw an error, but this will work:

User.includes(:posts).where('posts.name = ?', 'example').references(:posts)

Note that includes works with association names while references needs the actual table name.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.321106 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO