Tìm hiểu Polymorphic Associations trong Rails
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 ...
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
Ruby on Rails Guide
Ruby on Rails API