Reputation: 2434
I have 3 models.
Model A belongs to model B and model B has many model C
by using through
I can set in model A class has_many :c,through: :b
Now whenever I call a_instance.cs
It would JOIN with table B unnecessarily What I want is direct association of A
& C
using b_id
in both A & C class.
So how can I write a has_one/has_many rails association without through
clause when both Source and Destination entities has same foreign_key of 3rd entity? (b_id
for this example)
class C
belongs_to :b #b_id column is there in DB
end
class B
has_many :cs
end
class A
belongs_to :b #b_id column is there in DB
has_many :cs , through: :b #This is the association in Question
#WHAT I WANT TO DO. So something in place of primary_key which would fetch C class directly.
has_many :cs ,class_name: 'C',foreign_key: 'b_id',primary_key: 'b_id'
end
Upvotes: 4
Views: 1241
Reputation: 526
Following your example of classes A,B & C and changing only the implementation of class A.
class A
belongs_to :b
def cs
self.id = b_id
b_cast = self.becomes(B)
b_cast.cs
end
end
Console
A.first ==>#<A id: 105, b_id: 1 ...>
B.first ==>#<B id: 1 ...>
C.all ==>#<C id: 1, b_id: 1 ...>,
#<C id: 2, b_id: 1 ...>,
#<C id: 3, b_id: 1 ...>,
#<C id: 4, b_id: 1 ...>
A.first.cs
A Load (0.2ms) SELECT "as".* FROM "as" ORDER BY "as"."id" ASC LIMIT ? [["LIMIT", 1]]
C Load (0.1ms) SELECT "cs".* FROM "cs" WHERE "cs"."b_id" = ? LIMIT ? [["b_id", 1], ["LIMIT", 11]]
A.first.cs ==>#<C id: 1, b_id: 1 ...>,
#<C id: 2, b_id: 1 ...>,
#<C id: 3, b_id: 1 ...>,
#<C id: 4, b_id: 1 ...>
Official #becomes(klass) documentation can be found here!
On other end, the same effect can be achieved creating an instance of the class B and giving it the id stored in A.first.b_id as follows:
B.new(id: A.first.b_id).cs
A Load (0.2ms) SELECT "as".* FROM "as" ORDER BY "as"."id" ASC LIMIT ? [["LIMIT", 1]]
C Load (0.1ms) SELECT "cs".* FROM "cs" WHERE "cs"."b_id" = ? LIMIT ? [["b_id", 1], ["LIMIT", 11]]
B.new(id: A.first.b_id).cs ==>#<C id: 1, b_id: 1 ...>,
#<C id: 2, b_id: 1 ...>,
#<C id: 3, b_id: 1 ...>,
#<C id: 4, b_id: 1 ...>
Upvotes: 0
Reputation: 2436
An example, Teacher and Student models belong to Group, Teacher has many Student:
class Group < ApplicationRecord
has_many :teachers
has_many :students
end
class Teacher < ApplicationRecord
belongs_to :group
has_many :students, :foreign_key => 'group_id', :primary_key => 'group_id'
end
class Student < ApplicationRecord
belongs_to :group
end
And you can retrieve a teacher's students in a group like this:
teacher = Teacher.find(:teacher_id)
students = teacher.students
Upvotes: 1