Tìm hiểu Polymorphic Associations trong Rails
Bài đăng này đã không được cập nhật trong 3 năm
Polymorphic (đa hình) là 1 khái niệm tương đối khó hiểu và dễ bị lẫn lộn khi sử dụng. Vậy sao nào để ta có thể hiểu và sử dụng đúng, qua bài viết này tôi sẽ giúp các bạn làm sáng tỏ
1. Giới thiệu
Active Record Associations
là một trong những chức năng quan trọng nhất của Rails và Polymorphic Association
là một phần trong đó. Với Polymorphic Association
một model có thể tạo quan hệ với nhiều hơn một model khác mà chỉ thông qua một association
.
2. Cài đặt
Khi viết một ứng dụng Rails đôi khi tao gặp phải trường hợp một model có nhiều liên kết có ý nghĩa giống nhau. Ví dụ, chúng ta có 2 model là Course
và Lab
. Với mỗi Course
hay Lab
chúng ta có nhiều TeachingAssistant
. Nếu sử dụng has_many/belongs_to ở đây bạn phải hai liên kết tương ứng giữa Course
với TeachingAssistant
và Lab
với TeachingAssistan
. Thay vì đó, chúng ta có thể sử dụng Polymorphic Association
để tạo một liên kết tới đồng thời tới hai model Course
và Lab
từ TeachingAssistant
.
Trước tiên chúng ta tạo các model bằng cách chạy :
TeachingAssistant
rails g model TeachingAssistant name:string ta_duty_id:integer ta_duty_type:string
Course
rails g model Course name:string
Lab
rails g model Lab name:string
ta_duty_id
: foreign key
ta_duty_type
: quyết định xem TeachingAssistant
liên kết với model nào (Course
hay Lab
)
/db/migrate/********_create_teaching_assistants.rb
class CreateTeachingAssistants < ActiveRecord::Migration
def change
create_table :teaching_assistants do |t|
t.string :name
t.integer :ta_duty_id
t.string :ta_duty_type
t.timestamps
end
end
end
Chạy rake db:migrate
.
Giờ chúng ta đã có model, việc tiếp theo là khai báo Polymorphic Association
cho TeachingAssistant
class TeachingAssistant < ActiveRecord::Base
belongs_to :ta_duty, polymorphic: true
end
Bằng việc khai báo TeachingAssistan
belongs_to ta_duty thay vì Course
hay Lab
chúng ta đã tạo một Polymorphic Association
.
Chú ý : ta_duty
không phải 1 model hay class trong hệ thống mà chỉ là tên đại diện cho Polymorphic Association
.
Tiếp theo là 2 model Course
và Lab
/app/models/course.rb
class Course < ActiveRecord::Base
has_many :teaching_assistants, as: :ta_duty
end
/app/models/lab.rb
class Lab < ActiveRecord::Base
has_many :teaching_assistants, as: :ta_duty
end
Với khai báo ở trên tao có thể hiểu rằng Course
và Lab
has_many TeachingAssistant
thông qua polymorphic association ta_duty. Sơ đồ dưới sẽ giúp các bạn dễ hình dung hơn về mối quan hệ trên.
Giờ hãy vào console tạo một TeachingAssistant
để check nhé:
001 > ta = TeachingAssistant.create name: "ta_name"
002 > c = Course.create name: "course_name"
003 > ta.update_attribute(:ta_duty, c)
=> true
004 > Course.last.teaching_assistants.last.name
=> "ta_name"
2.0.0-p247 :005 >
3. STI vs Polymorphic Association
Single Table Inheritance(STI) thường được so sánh với Polymorphic Association
. Đó cũng là một lựa chọn tương đối tốt so với Polymorphic Association
tùy vào từng trường hợp. STI
sử dụng cơ chế thừa kế tương tự như ActiveRecord::Base
.
Ví dụ :
class TeachingAssistant < ActiveRecord::Base
class CourseTa < TeachingAssistant
class LabTa < TeachingAssistant
Trong trường hợp này ta sẽ có một sơ đồ quan hệ khác với Polymorphic Association
STI
yêu cầu bạn phải tạo ra các class tương ứng để khai báo quan hệ. Bạn phải viết nhiều dòng code hơn và phức tạp hơn sơ với Polymorphic Association
4. Kết hợp has_many :through và Polymorphic Association
Có thể có trường hợp bạn cần phải kết hợp has_many :through với Polymorphic Assoctiation
. Mặc dù không khó để khai báo nhưng trường hợp này rất hay bị nhầm lẫn. Sau đây ta hay xét một ví dụ.
Giáo sư (Professor
) muốn biết Course
hay Lab
nào có TeachingAssistant
của mình. Ta có thẻ khai báo như sau:
/app/models/professor.rb
class Professor < ActiveRecord::Base
has_many :teaching_assistants
has_many :course_tas, through: :teaching_assistants, source: :ta_duty, source_type: "Course"
has_many :lab_tas, through: :teaching_assistants, source: :ta_duty, source_type: "Lab"
end
/app/models/teaching_assistant.rb
class TeachingAssistant < ActiveRecord::Base
belongs_to :professors
belongs_to :ta_duty, polymorphic: true
end
5. Kết luận
Trên đây là những điều cơ bản và cách khai báo Polymorphic Association
trong Rails. Ngoài ra tôi còn giúp các bạn so sánh nó với STI
và cách thức kết hợp nó với một quan hệ khác. Rất mong các bạn có thể hiểu rõ và vận dụng thật tốt vào những project của mình.
Tham khảo thêm
All rights reserved