12/08/2018, 12:46

Tìm hiểu đa hình trong Rails (Polymorphic Association in rails)

Mối quan hệ đa hình trong lập trình hướng đối tượng đôi khi là khó hiểu và đặc biệt đối với người mới tìm hiểu một ngôn ngữ nào đó. Hầu hết các ngôn ngữ lập trình bậc cao đều có kiểu quan hệ này như trong C++ hay Java. Trong khuôn khổ bài viết này, tìm hiểu quan hệ đa hình trong Ruby on Rails ...

Mối quan hệ đa hình trong lập trình hướng đối tượng đôi khi là khó hiểu và đặc biệt đối với người mới tìm hiểu một ngôn ngữ nào đó. Hầu hết các ngôn ngữ lập trình bậc cao đều có kiểu quan hệ này như trong C++ hay Java. Trong khuôn khổ bài viết này, tìm hiểu quan hệ đa hình trong Ruby on Rails (Polymorphic Associations in Rails).

Đi đến trả lời các câu hỏi "what?", "when?", "how?", "why?".

Giới thiệu

Định nghĩa

Các quan hệ trong Active Record là một trong những tính năng quan trọng nhất của Rails. Và trong số đó có quan hệ đa hình (Polymorphic Association). Theo "Ruby on Rails Guide" rằng: "Quan hệ đa hình, một Model có thể theo nhiều hơn một Model khác, trong một liên kết duy nhất".

Hiểu qua ví dụ

Để hiểu đơn giản về quan hệ trên, tôi lấy một ví dụ như sau: Anh A có một bài viết trên diễn đàn (gọi là một bài post), anh B có một album ảnh trên diễn đàn (gọi là một album). Mọi người khác có thể vào bình luận trên bài viết của anh A và album ảnh của anh B. Gỉa sử như anh C, D, E, ... bình luận vào bài post và album (gọi là những comments). Vậy Comment của mọi người này có thể đi theo Post và Album, tức một Model có thể theo nhiều hơn một Model khác trong một liên kết duy nhất.

Nội dung

Như vậy, phần trên chúng ta đã trả lời cho câu hỏi "what?".

Để tìm hiểu chi tiết hơn và trả lời lần lượt các câu hỏi tiếp theo, tôi sẽ trình bày ngắn gọn kết hợp với ví dụ ở phía trên cho demo.

when?

Khi nào chúng ta nên sử dụng quan hệ này? Như ngay phần định nghĩa và ví dụ trên đã rõ. Chúng ta sử dụng quan hệ này khi cần cho một mô hình quan hệ có 1 Model cần belongs_to nhiều Model khác mà chỉ trong một liên kết duy nhất.

Tôi xin lấy một ví dụ khác cho vấn đề này:

Chúng ta có một model Post lưu trữ các bài posts của người dùng. Các người dùng khác có thể vào xem các bài posts này. Một vấn đề là mỗi người vào xem 1 bài post thì đánh dấu baì post đó sang trạng thái "đã xem" đối với người đó, còn đối với các người dùng khác chưa xem thì ở trạng thái "chưa xem" chẳng hạn. Để giải quyết vấn đề này, chúng ta có thể có phương án là quan hệ "polymorphic association".

why?

Vậy, tại sao chúng ta lại sử dụng quan hệ này? Có cách nào khác hay không?

Mỗi một vấn đề luôn luôn có những cách giải quyết khác nhau, và đối với vấn đề này, đây là một cách để giải quyết nó.

Với ví dụ như ở phần định nghĩa trên, chúng ta không thể tạo ra nhiều bảng comments cho posts hoặc album, như vậy sẽ rất khó kiểm soát dữ liệu và các quan hệ khi có nhiều Object khác album hay post. Và cũng không thể đặt các album_id, post_id trong comments để xử lý được.

Và Rails cung cấp cho chúng ta một quan hệ để giải quyết vấn đề trên đó là đa hình (polymorphic association).

how?

Rails Guide cung cấp hướng dẫn đầy đủ về quan hệ này trong Rails. Chúng ta đi đến ví dụ như trong phần định nghĩa đã nêu qua bài toán.

  • Tạo model Album
rails g scaffold album name:string
  • Tạo model Post
rails g scaffold post title:string content:text
  • Tạo model Comment
rails g scaffold comment content:string commentable_id:integer commentable_type:string
rake db:migrate
  • Khởi tạo quan hệ
 #comment.rb
 class Comment < ActiveRecord::Base
   belongs_to :commentable, polymorphic: true
 end
#album.rb
class Album < ActiveRecord::Base
  has_many :comments, as: :commentable
end
#post.rb
class Post < ActiveRecord::Base
  has_many :comments, as: :commentable
end

Như vậy, cài đặt quan hệ trên có thể hiểu đơn giản là Album và Post có nhiều Comment (mối quan hệ 1 - n) và Comment theo 2 bảng là Album và Post song hành qua một liên kết duy nhất thông qua commentable.

  • Kiểm tra cài đặt quan hệ
rails c
Loading development environment (Rails 4.1.1)
2.0.0-p247 :001 > cmt = Comment.create(content: 'test content')
2.0.0-p247 :002 > album = Album.create(name: 'Album 01')
2.0.0-p247 :003 > cmt.update(:commentable, album)
 => true
2.0.0-p247 :004 > Album.last.comments.last.content
 => "test content"
2.0.0-p247 :005 >

STI vs Polymorphic Association

STI (Single Table Inheritence) là một kiểu quan hệ tương đương với Polymorphic association nhưng ngược lại. Nó phức tạp hơn trong việc triển khai cài đặt vì cần phải tạo ra nhiều class khác. Đôi khi nó cũng là một giải pháp có thể là tốt hơn để thay thế cho đa hình tùy thuộc vào từng trường hợp của bài toán.

Dưới đây là mô hình cho quan hệ này.

Screenshot from 2015-11-23 22:13:37.png

Tổng kết

Như vậy, bài viết này tóm lại tổng quan những điểm cơ bản nhất của quan hệ đa hình trong rails (Polymorphic association in Rails). Qua đó trả lời các câu hỏi cho các tình huống, trường hợp để vận dụng quan hệ này cho phù hợp với bài toán cụ thể cũng như so sánh nét cơ bản nhất với các quan hệ khác tương đương.

Hy vọng có thể giúp ích một phần nào đó tới người tham khảo, cảm ơn các bạn đã xem bài viết của tôi, xin hãy để lại comment hay +1 helpful cho bài viết tiếp theo nhé! :hehe:

Tham khảo

  1. Ruby on Rails Guide
  2. Ruby on Rails API
  3. gotealeaf
0