0
0
Lập trình
Flame Kris
Flame Krisbacodekiller

Hướng dẫn sử dụng Associações Polimórficas trong Rails

Đăng vào 7 tháng trước

• 5 phút đọc

Hướng dẫn sử dụng Associações Polimórficas trong Rails

Gần đây, trong quá trình làm việc, mình gặp phải một tình huống cần triển khai một bảng có khả năng liên kết với nhiều bảng khác nhau, nhưng lại có các trường chung. Qua tìm hiểu, mình đã phát hiện ra rằng associações polimórficas trong Rails là giải pháp lý tưởng cho vấn đề này.

Trong bài viết này, chúng ta sẽ cùng nhau khám phá cách triển khai, cũng như thảo luận về ưu điểm, nhược điểm và thời điểm nên sử dụng chúng.

Associações Polimórficas là gì?

Associação polimórfica là một tính năng trong Rails cho phép một mô hình có thể thuộc về nhiều mô hình khác nhau thông qua một cấu trúc chung.

Ví dụ thực tế

Giả sử bạn có một hệ thống trong đó người dùng và công ty đều có thể có liên hệ (email, điện thoại). Thay vì tạo hai bảng riêng biệt (user_contactscompany_contacts), bạn có thể thiết lập một bảng duy nhất là contacts để chứa tất cả dữ liệu liên hệ của cả hai mô hình này.

Cách tạo Associações Polimórficas

Triển khai associações polimórficas trong Rails rất đơn giản. Chúng ta sẽ bắt đầu bằng cách tạo một bảng contacts có khả năng liên kết với cả userscompanies (hoặc bất kỳ mô hình nào khác cần có thông tin liên hệ).

Migration

ruby Copy
class CreateContacts < ActiveRecord::Migration[7.1]
  def change
    create_table :contacts do |t|
      t.string :email
      t.string :phone

      t.references :contactable, polymorphic: true, null: false

      t.timestamps
    end
  end
end

Dòng t.references :contactable, polymorphic: true sẽ tạo ra hai cột:

  • contactable_id (integer)
  • contactable_type (string)

Hai trường này sẽ chỉ định ai là chủ sở hữu của liên hệ.

Models

ruby Copy
class Contact < ApplicationRecord
  belongs_to :contactable, polymorphic: true
end

class User < ApplicationRecord
  has_many :contacts, as: :contactable
end

class Company < ApplicationRecord
  has_many :contacts, as: :contactable
end

Giờ đây, cả UserCompany đều có thể có nhiều liên hệ.

Ví dụ sử dụng

ruby Copy
user = User.create(name: "Pedro")
company = Company.create(name: "ABC")

user.contacts.create(email: "pedro@email.com", phone: "1111-1111")
company.contacts.create(email: "contato@tech.com", phone: "2222-2222")

puts user.contacts.first.email     # => "pedro@email.com"
puts company.contacts.first.phone  # => "2222-2222"

Nhờ đó, chúng ta có thể tái sử dụng bảng contacts trong nhiều ngữ cảnh khác nhau.

Ưu điểm của Associações Polimórficas

  • Tái sử dụng: bạn chỉ cần tạo một bảng duy nhất cho nhiều mô hình khác nhau.
  • Giảm thiểu trùng lặp: tránh việc tạo nhiều bảng để lưu trữ dữ liệu tương tự.
  • Linh hoạt: nếu trong tương lai có mô hình mới cần thông tin liên hệ (ví dụ: Suppliers), bạn chỉ cần thêm một liên kết.
  • Tích hợp tốt với Rails: hỗ trợ tích hợp sẵn giúp đơn giản hóa quy trình.

Nhược điểm của Associações Polimórficas

  • Truy vấn phức tạp hơn: việc lọc dữ liệu polimorphic có thể tạo ra các truy vấn nặng nề.
  • Khó khăn trong việc duy trì tính toàn vẹn: Rails không tự động tạo khóa ngoại cho các cột polimorphic (do các trường này có thể liên kết đến nhiều bảng khác nhau).
  • Khả năng mở rộng: nếu bảng chứa quá nhiều dữ liệu từ nhiều mô hình, nó có thể trở thành điểm nghẽn.
  • Khó đọc: đối với những ai chưa quen, việc hiểu contactable_type có thể gây nhầm lẫn.

Khi nào nên sử dụng Associações Polimórficas?

Nên sử dụng khi:

  • Bạn có dữ liệu giống nhau cần có trong nhiều mô hình (ví dụ: liên hệ, địa chỉ, hình ảnh, bình luận).
  • Cấu trúc dữ liệu lặp lại nhiều và việc tạo bảng riêng sẽ không hợp lý.

Tránh sử dụng khi:

  • Dữ liệu khác nhau nhiều giữa các mô hình (ví dụ: nếu liên hệ của UserCompany có các trường hoàn toàn khác nhau).
  • Bạn cần ràng buộc mạnh mẽ trong cơ sở dữ liệu (tính toàn vẹn tham chiếu thông qua các khóa ngoại trực tiếp).
  • Bảng polimorphic có nguy cơ phát triển quá lớn, ảnh hưởng đến hiệu suất.

Các phương án thay thế cho Associações Polimórficas

Một phương án thay thế cho associações polimórficas là tạo các quan hệ một cách rõ ràng trong bảng, bằng cách thêm các cột cụ thể như user_id, company_id, supplier_id, v.v.

Ví dụ về migration không sử dụng polimorfismo:

ruby Copy
class CreateContacts < ActiveRecord::Migration[7.1]
  def change
    create_table :contacts do |t|
      t.string :email
      t.string :phone

      # Quan hệ rõ ràng
      t.references :user, foreign_key: true
      t.references :company, foreign_key: true

      t.timestamps
    end
  end
end

Ưu điểm của phương pháp này:

  • Hiệu suất cao hơn: truy vấn nhanh hơn vì không phụ thuộc vào trường type.
  • Tính toàn vẹn trong cơ sở dữ liệu: bạn có thể sử dụng khóa ngoại trực tiếp, đảm bảo tính nhất quán.
  • Dễ đọc hơn: dễ hiểu quan hệ chỉ bằng cách nhìn vào bảng.

Nhược điểm của phương pháp này:

  • Khả năng mở rộng kém: nếu sau này có mô hình mới (ví dụ: Supplier), bạn sẽ cần thay đổi bảng và thêm cột mới.
  • Trùng lặp cấu trúc: càng nhiều mô hình khác nhau, bảng càng có nhiều cột dư thừa.

Phương pháp này thường được chọn trong các tình huống mà hiệu suất là ưu tiên và số mô hình liên quan là có thể dự đoán và giới hạn.

Kết luận

Associações polimórficas là một công cụ mạnh mẽ trong Rails. Chúng mang đến sự đơn giản và khả năng tái sử dụng khi được áp dụng đúng cách, nhưng cũng có thể tạo ra phức tạp không cần thiết và thậm chí ảnh hưởng đến hiệu suất trong các tình huống có khối lượng dữ liệu lớn.

Một lựa chọn hợp lý là tạo các tham chiếu rõ ràng (user_id, company_id, v.v.) thay vì sử dụng trường polimorphic. Phương pháp này cải thiện hiệu suất và cho phép duy trì tính toàn vẹn thông qua khóa ngoại, nhưng lại giảm đi tính linh hoạt và yêu cầu thay đổi bảng mỗi khi có mô hình mới.

Cuối cùng, không có giải pháp nào là hoàn hảo:

  • Nếu bạn cần tính linh hoạt và khả năng tái sử dụng → hãy chọn associação polimórfica.
  • Nếu bạn cần hiệu suất và tính toàn vẹn cao trong cơ sở dữ liệu → hãy chọn khóa rõ ràng (_id).

Sự lựa chọn phụ thuộc vào ngữ cảnh và ưu tiên của dự án.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào