การทำความเข้าใจ: ตัวเลือกแหล่งที่มาของ has_one / has_many ผ่านทางราง


184

โปรดช่วยฉันในการทำความเข้าใจ:sourceตัวเลือกการhas_one/has_many :throughเชื่อมโยง คำอธิบาย Rails API ทำให้ฉันเข้าใจน้อยมาก

"ระบุชื่อการเชื่อมโยงแหล่งที่มาที่ใช้โดยhas_many :through => :queriesใช้เฉพาะในกรณีที่ชื่อไม่สามารถอนุมานได้จากการเชื่อมโยงhas_many :subscribers, :through => :subscriptionsจะค้นหาอย่างใดอย่างหนึ่ง:subscribersหรือ:subscriberบนSubscriptionเว้นแต่:sourceจะได้รับ"

คำตอบ:


238

บางครั้งคุณต้องการใช้ชื่ออื่นสำหรับการเชื่อมโยงที่แตกต่างกัน หากชื่อที่คุณต้องการใช้สำหรับการเชื่อมโยงในแบบจำลองนั้นไม่เหมือนกับการตั้งค่าใน:throughแบบจำลองคุณสามารถใช้:sourceเพื่อระบุ

ฉันไม่คิดว่าย่อหน้าด้านบนมีความชัดเจนยิ่งกว่าหนึ่งในเอกสารดังนั้นนี่เป็นตัวอย่าง สมมติว่าเรามีสามรุ่นPet, และDogDog::Breed

class Pet < ActiveRecord::Base
  has_many :dogs
end

class Dog < ActiveRecord::Base
  belongs_to :pet
  has_many :breeds
end

class Dog::Breed < ActiveRecord::Base
  belongs_to :dog
end

ในกรณีนี้เราได้เลือกเนมสเปซDog::Breedเนื่องจากเราต้องการเข้าถึงDog.find(123).breedsการเชื่อมโยงที่ดีและสะดวกสบาย

ตอนนี้ถ้าเราต้องการสร้างความhas_many :dog_breeds, :through => :dogsสัมพันธ์Petเราก็มีปัญหา ทางรถไฟจะไม่สามารถที่จะหา:dog_breedsการเชื่อมโยงบนDogดังนั้นทางรถไฟไม่อาจรู้ที่ Dogเชื่อมโยงคุณต้องการที่จะใช้ ใส่:source:

class Pet < ActiveRecord::Base
  has_many :dogs
  has_many :dog_breeds, :through => :dogs, :source => :breeds
end

ด้วย:sourceเรากำลังบอกทางรถไฟที่จะมองหาการเชื่อมโยงที่เรียกว่า:breedsในDogรูปแบบ (เป็นที่รุ่นที่ใช้สำหรับการ:dogs) และการใช้งานที่


2
ฉันคิดว่าคุณหมายถึงสัตว์ชั้นสุดท้ายของคุณที่จะเรียกว่าคลาสสัตว์เลี้ยงเพียงแค่พิมพ์ผิดที่ฉันเชื่อ
Kamilski81

3
ในตัวอย่างข้างต้นที่สมาคมภายใต้ควรDogจะhas_many :breedแทน:breedsแล้ว:sourceจะ:breedเอกพจน์เพื่อเป็นตัวแทนของชื่อรุ่นแทน:breedsซึ่งหมายถึงชื่อตารางหรือไม่ เช่นhas_many :dog_breeds, :through => :dogs, :source => :breed(ไม่มีคำsต่อท้าย:breed)
LazerSharks

1
ฉันเคยทดสอบสิ่งนี้ มันเป็นเอกพจน์ไม่มีsคำต่อท้ายใน:source =>
อันวาร์

"ในกรณีนี้เราได้เลือกเนมสเปซ Dog :: Breed เพราะเราต้องการเข้าถึง Dog.find (123) .breeds เป็นการเชื่อมโยงที่ดีและสะดวกสบาย" คุณไม่ต้องการเนมสเปซสำหรับคุณใช่ไหม
Jwan622

201

ให้ฉันขยายตัวอย่างต่อไปนี้:

class User
  has_many :subscriptions
  has_many :newsletters, :through => :subscriptions
end

class Newsletter
  has_many :subscriptions
  has_many :users, :through => :subscriptions
end

class Subscription
  belongs_to :newsletter
  belongs_to :user
end

ด้วยรหัสนี้คุณสามารถทำสิ่งต่างๆNewsletter.find(id).usersเพื่อรับรายชื่อสมาชิกของจดหมายข่าว แต่ถ้าคุณต้องการชัดเจนและสามารถพิมพ์Newsletter.find(id).subscribersแทนคุณต้องเปลี่ยนคลาสจดหมายข่าวเป็น:

class Newsletter
  has_many :subscriptions
  has_many :subscribers, :through => :subscriptions, :source => :user
end

คุณกำลังเปลี่ยนชื่อสมาคมusers subscribersหากคุณไม่ได้ระบุ:sourceRails จะค้นหาการเชื่อมโยงที่เรียกว่าsubscriberในชั้นสมัครสมาชิก คุณต้องบอกให้ใช้การuserเชื่อมโยงในคลาส Subscription เพื่อสร้างรายชื่อสมาชิก


2
โปรดทราบว่าควรใช้ชื่อโมเดลที่เป็นเอกพจน์:source =>ไม่ใช่พหูพจน์ ดังนั้น:usersผิด:userถูกต้อง
Anwar

นี่เป็นคำตอบที่ดีที่สุด! ขอผมขอเน้นเฉพาะส่วนนี้: "คุณกำลังเปลี่ยนชื่อผู้ใช้ที่เชื่อมโยงกับสมาชิกหากคุณไม่ได้ระบุ: แหล่งที่มา Rails จะค้นหาสมาคมที่เรียกว่าสมาชิกในชั้นสมัครสมาชิก"
Brian Joseph Spinos

11

คำตอบที่ง่ายที่สุด:

คือชื่อของความสัมพันธ์ในตารางที่อยู่ตรงกลาง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.