Ruby on Rails ActiveRecord Associations - Những phần ít được biết đến

ActiveRecord associations là một phần cơ bản của Rails, nhưng không phải tất cả chúng được sử dụng rộng rãi. Dưới đây là những phần ít được biết đến của ActiveRecord association.

Customizing Queries

Có lẽ bạn đã từng phát triển một trang blog cho phép comment. Một số comment có thể không phù hợp, vì vậy bạn muốn đảm bảo những comment sẽ chỉ được hiển thị nếu người kiểm duyệt trang web của bạn chấp thuận. Bạn hãy thêm trường boolean approved vào bảng Comment của mình. Vì mỗi bài đăng trên blog bạn chỉ muốn lấy danh sách các comment đã được phê duyệt, bạn có thể tùy chỉnh truy vấn

# app/models/post.rb
class Post < ActiveRecord::Base
  has_many :approved_comments, -> { where approved: true }, class_name: 'Comment'
  ...

Bây giờ bạn đã có một association my_post.approved_comments mà bạn có thể sử dụng bất cứ nơi nào bạn cần để lấy các bình luận đã được kiểm duyệt của một bài đăng.

Extensions

Có thể bạn muốn có các tùy chọn để hiển thị tất cả comment về bài đăng hoặc hạn chế chỉ cho những bài đăng được tạo ngày hôm nay. Bạn có thể thêm một phần mở rộng, tức là nói một phương pháp tùy chỉnh cho association đặc biệt này.

# app/models/post.rb
class Post < ActiveRecord::Base
  has_many :comments do
    def today
      where("created_at >= ?", Time.zone.now.beginning_of_day)
    end
  end
  ...

Bây giờ, ngoài việc có thể gọi my_post.comments bạn có thể tùy chỉnh các bản ghi được lấy ra bằng cách gọi my_post.comments.today

Callbacks

Có thể gọi các method tự động trước và sau khi bản ghi được thêm vào hoặc gỡ bỏ. Giả sữ bạn có một dự án xây dựng có người lao động... mỗi khi bạn muốn thêm một người lao động mới vào dự án xây dựng mà bạn muốn tính toán các thay đổi cho ngân sách dự án và những thay đổi cho ngày hoàn thành dựa vào loại người lao động, kinh nghiệm của người lao động... một phương pháp phức tạp. Và bạn có thể gọi một cách tự động sau khi nhân viên được thêm vào.

# app/models/building_project.rb
class BuildingProject < ActiveRecord::Base
  has_many :workers, after_add: :recalculate_project_status
  ...
  def recalculate_project_status(newly_added_worker)
    ...
  end
  ...

Inverse Of

inverse_of là một cách tiện dụng để gắn cờ cho Ruby rằng các đối tượng liên quan có thể được truy cập từ một trong hai hướng. my_post.commentsmy_comment.post. Tất nhiên, phải chỉ định has_many :comments trong class Post và belongs_to :post trong class Comment, bạn phải định nghĩa 2 association... nhưng inverse_of làm cho nó rõ ràng rằng các đối tượng trong các mối quan hệ thực sự là cùng một đối tượng. Bạn chỉ định inverse_of như sau:

# app/models/post.rb
class Post < ActiveRecord.Base
 has_many :comments, inverse_of: post
 ...

Nếu bạn làm làm điều này khi không chỉ định inverse_of :

post = Post.first
post.update_attribute(:importance, false)
comment = post.comments.first
working_post = comment.post
working_post.update_attribute(:importance, true)
post.importance?
=> false

Nó vẫn nghĩ răng post là unimportant.. đó là bởi vì comment.post đã thực hiện truy vấn database riêng và có một truy vấn mới và riêng biệt của cùng một bài đăng, và biến post lưu bản gốc không biết rằng bản ghi cơ sở dữ liệu đã được thay đổi. Bây giờ với inverse_of, bạn làm theo các bước tương tự :

post = Post.first
post.update_attribute(:importance, false)
comment = post.comments.first
working_post = comment.post
working_post.update_attribute(:importance, true)
post.importance?
=> true

Tốt hơn nhiều! Bởi vì comment.post không làm một truy vấn cơ sở dử liệu, thay vào đó nó sử dụng cùng một thể hiện của các đối tượng post đã có trong bộ nhớ. Vì vậy, thay đổi trong working_post được tự động hiển thị trong post cùng một lúc, tránh những kết quả bất ngờ.