Reputation: 51
I can't understand the Rails Active Record logic.
I have 2 models:
# wdsl
class Wsdl < ApplicationRecord
has_one :status
validates :mis_url, presence: true
validates :short_name, presence: true
end
# status
class Status < ApplicationRecord
belongs_to :wsdl
end
I'm doing a simple SQL query via a program (not ActiveRecord and Rails), and as you can see, I have 9 columns in each record:
But, if I execute this query via Active Record I get an object with "3 columns" in each "record":
As you can see the queries are equal but I get data without the "Status" model.
PS I can't modify the "Wsdls" table in real - I really need the "Statuses" table and I don't want use a raw SQL query in Rails to get data from two tables.
What am I doing wrong?
Upvotes: 0
Views: 2717
Reputation: 101811
In Rails .joins
is used primarily for applying conditions on the joined table:
Wsdl.joins(:status).where(statuses: { code: 99 })
Since this creates an inner join only rows from users that have a match in addresses will be returned.
You can also use .joins
or .left_joins
(Rails 5+) together with a custom select to select aggregates or columns from the joined table.
Wsdl.joins(:status).select('wsdl.*', 'status.code as status_code')
# Using a LEFT OUTER JOIN instead of INNER will return rows with no status
Wsdl.left_joins(:status).select('wsdl.*', 'status.code as status_code')
If you instead want to load model instances and avoid N+1 query issues use .includes
or .eager_load
instead. The difference is that .eager_load
loads everything up front while .includes
tries to be smart and load only if needed.
# This will load all the records and the assocation at once
@wsdls = Wsdl.eager_load(:status)
@wsdls.each do |object|
# this would cause a N+1 query if we didn't eager load.
puts object.status.code
end
Upvotes: 1
Reputation: 18444
ActiveRecord relation joins
is for writing complex queries, but model loads attributes only from its own table (unless you write something like .select('statuses.code as attr_name_for_code, wsdls.*')
)
You can use .joins(:status).includes(:status)
to eager load the association, rails will construct select ... from ... join ...
with all fields from both models itself, and wsdl.status
objects will already be loaded.
Upvotes: 3