If you’ve used Ruby on Rails you’ve probably chained where
before.
In app/controllers/posts_controller.rb
:
class PostsController < ApplicationController
def index
@posts = Post.where(active: true).where(user_id: params[:user_id])
end
end
But how does this work?
Understanding when the query gets sent
One thing that’s not readily apparent is that in our above example, @posts
is not loaded?
.
Only when @posts
is iterated upon does it get load
. When does it get iterated upon? Things like each
or map
trigger load
.
Try it yourself:
User.all.limit(3).loaded? # nil
User.all.limit(3).load.loaded? # true
If you hit to_s
, you’ll see when things get queried:
User.all.limit(3).load.to_s # #<User::ActiveRecord_Relation:0x00007f8f892e8298>
User.all.limit(3).loaded.to_s # ""
A practical example of the query builder pattern
class User
def self.all_args
@all_args ||= []
end
def self.where(*args)
all_args << args
self
end
def self.results
@results
end
def self.load
puts "Executing sql #{all_args.join(", ")}"
@results = [1, 2, 3]
end
def self.loaded?
!!!@results.nil?
end
def self.each
load
yield @results
end
end
users = User.where(friend: true)
puts users #
users.each do |record|
puts record # 1, 2, 3
end
If you run that in irb
and compare that to your commands in rails console
, you’ll notice one thing: The rails console
version executes your users
from puts users
. This is because of inspect
.