Remy Wang
Remy Wang

Reputation: 783

ActiveRecord Associations(has_one) - Access parent object

class Parent < ApplicationRecord
  has_one: child
end


class Child < ApplicationRecord
  belongs_to :parent
end


childrens = Child.includes(:parent)

puts childrens.to_json
[{"id":1,"parent_id":1,"name":"Jack"},{"id":2,"parent_id":2,"name":"Oleg"}]

In this case, we can access parent object like this: child.parent

But it is not possible to access parent object in view. Is there any way to include parent objects in each child?

Thank you!

Upvotes: 1

Views: 174

Answers (3)

Remy Wang
Remy Wang

Reputation: 783

Child.includes(:parent).as_json(include: :parent)

This helped me!

Upvotes: 0

Sebasti&#225;n Palma
Sebasti&#225;n Palma

Reputation: 33420

You can use as_json with the include option to get each child parent:

Child.includes(:parent).as_json(include: :parent)

For that you get a couple of queries. One for the children, the other one for each children parents (IN clause):

Child Load (1.0ms)  SELECT "children".* FROM "children"
Parent Load (1.2ms)  SELECT "parents".* FROM "parents" WHERE "parents"."id" IN ($1, $2)  [["id", 1], ["id", 2]]

You can limit the columns you're retrieving from the database (with select) as well as each object in the JSON object (that doesn't apply a SQL filter).

Upvotes: 3

radubogdan
radubogdan

Reputation: 2834

There is a bit of confusion which you made with includes. This will not include the objects, but prepares them in case they are needed.

Because you have an association between Parent and Child, you can already get the parents in view, but this will request the parent for every children hence you'll run in n+1 queries.

To put it in code:

Child.all.each { |c| c.parent }; nil

will trigger:

Parent Load (0.2ms)  SELECT  "parents".* FROM "parents" WHERE "parents"."id" = $1 LIMIT 1   [["id", 4750516]]
Parent Load (0.2ms)  SELECT  "parents".* FROM "parents" WHERE "parents"."id" = $1 LIMIT 1   [["id", 4772539]]
Parent Load (0.1ms)  SELECT  "parents".* FROM "parents" WHERE "parents"."id" = $1 LIMIT 1   [["id", 4806512]]

What you do there with includes, will make it look like:

SELECT "children".* FROM "children"
Parent Load (3.3ms)  SELECT "parents".* FROM "parents" WHERE "parents"."id" IN (4750516, 4772539, 4806512)

So, if you want to use it in the view, you'll actually have something like @childrens so don't be afraid to iterate over and call .parent.

You can read more about eager loading here

Upvotes: 0

Related Questions