+5

Rendering Collections in Rails

Render partial là một trong những tính năng đem lại sự mãnh mẽ của Rails framework. Nó cung cấp cho chúng ta khả năng tách những view phức tạp thành các phần nhỏ hơn, dễ quản lý hơn, cũng như giữ cho code của chúng ta luôn DRY (Don't Repeat Yourself) Hẳn ai làm qua Rails cũng dùng từng dòng code như thế này:

<% @cart.products.each do |product| %>
    <%= render partial: "products/product",  locals: {product: product} %>
<% end %>

Tuy nhiên đoạn code dùng với each như trên nhìn rất xấu.

Partial path

Rất may Rails cung cấp cho chúng ta một cách viết ngắn gọn hơn.

    <%= render @cart.products %>

Nhìn rất ngắn gọn, dễ đọc, kết quả thì hoàn toàn tương tự. Vậy Rails đã làm điều này như thế nào?
Câu trả lời là function to_partial_path
Hàm này được implement như sau:

# File activemodel/lib/active_model/conversion.rb, line 84
    def to_partial_path
      self.class._to_partial_path
    end

Các model sẽ include ActiveModel::Conversion

class Product
  include ActiveModel::Conversion
end

product = Product.new
product.to_partial_path # => "products/product"

Như vậy ở đoạn code trên:

<%= render @cart.products %>

thì render đã gọi to_partial_path trên từng product để lấy đường dẫn đến file partial dùng cho việc render.

PORO (Plain Old Ruby Object)

to_partial_path cũng được sử dụng với Plain Old Ruby Object (hiểu đơn giản là không inherit từ ActiveRecord::Base)

Giả sử chúng ta code class Guest:

class Guest
  def name
    'Guest'
  end

  def to_partial_path
    'users/user'
  end
end

Yêu cầu trong ứng dụng là hiển thị danh sách người dùng, bao gồm guest cũng như registed user đang online trong hệ thống.
Chúng ta có thể sử dụng partial "users/user" cho cả guest lẫn registed user

# home/dashboard.html.erb
<%= render @dashboard.users_online %>
# users/_user.html.erb
<%= user.name %>

Polymorphics

to_partial_path cũng hỗ trợ với Polymorphic. Giả sử ứng dụng web của chúng ta cho phép người dùng có thể like các bài Post, Comment, hoặc Image của người khác. Ứng dụng yêu cầu hiển thị các post, comments, hay images mà người dùng đã like. Chúng ta sẽ không cần phải viết từng đoạn code xử lý điều kiệnif..else để render cho từng loại Post, Comment hay Image mà chỉ cần viết như sau:

# users/activity_log.html.erb
<h1><%= @user.name %>'s activity log:</h1>
<%= render @user.likes %>
# posts/_post.html.erb
<h1><%= article.name %></h1>
<p><%= article.content %></p>
# comments/_comment.html.erb
<div class="comment">
   <em>Last updated: <%= comment.updated_at %></em>
   <p><%= comment.content %></p>
  </div>
# images/_image.html.erb
<h1><%= image.title %></h1>
  <%= image_tag image.url %>

Kết luận

Rails framework cung cấp nhiều magic mang lại nhiều lợi ích trong việc phát triển ứng dụng, tuy nhiên nó cũng làm khó khăn cho những người mới làm quen. Hiểu được những thứ mà mình sử dụng trong framework mình đang sử dụng là một điều rất quan trọng.

Thanks for reading.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí