Suppose you have a model with a one-to-one-to-many relationship as shown below.
class User
has_one :examinee
end
class Examinee
belongs_to :user
has_many :tests
end
class Test
belongs_to :examinee
end
So how do you implement it when you want to get the relevant Test model from the User model?
There are many ways to do this, but I think you often use ActiveRecord's convenience feature delegate
or has_many-through
.
Both can achieve what you want to do, but the queries that are issued are slightly different, so I will introduce them.
delegate
You can use delegate to delegate a method to another class. See the Rails guide for more details. 3.4.1 delegate
In this case, implement as follows.
app/models/user.rb
delegate :tests, to: :examinee
When executed, two queries will be issued as shown below. The behavior is to first get the delegate examinee (first query) and then execute examinee.tests (second query).
irb> user.tests
Examinee Load SELECT `examinees`.* FROM `examinees` WHERE `examinees`.`user_id` = 1 LIMIT 1
Test Load SELECT `tests`.* FROM `tests` WHERE `tests`.`examinee_id` = 1
has_many-through
has_many-through is often used in many-to-many cases, but it can also be used in one-to-many cases like this one.
See the Rails guide for more details. 2.4 has_many: through association
In this case, implement as follows.
app/models/user.rb
has_many :tests, through: :examinee
When executed, one query will be issued as shown below. In this case, only one joined query will be issued. Considering that this function is implemented so that it corresponds to many-to-many, you can understand that it is acquired by join because it can not be acquired efficiently in two stages like deletgate.
irb> user.tests
Test Load SELECT `tests`.* FROM `tests` INNER JOIN `examinees` ON `tests`.`examinee_id` = `examinees`.`id` WHERE `examinees`.`user_id` = 1
Whether it is better to get it with 2 queries or 1 query joined depends on the execution environment, so it is not possible to judge whether it is good or bad. In most cases, it doesn't matter which one you write, so it doesn't matter which one you write.
However, even if it looks like it is doing the same thing from a black box perspective, the queries issued internally may be different like this time. Occasionally, it would be interesting to check these small differences when considering the origin and purpose of the function.
Recommended Posts