romushqa
romushqa

Reputation: 51

How to get data from 2 tables via active record in rails

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

Tables in DataBase:
tables in db

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:

sql query via program

But, if I execute this query via Active Record I get an object with "3 columns" in each "record":

active record sql query

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

Answers (2)

max
max

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

Vasfed
Vasfed

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

Related Questions