In ra bảng quan hệ n*n theo dạng ma trận với ít lần hit vào database

Bảng quan hệ (relation) giữa 2 model thường gặp và việc in ra dưới dạng ma trận 2 chiều đôi khi bị chậm lại vì việc hit vào database quá nhiều lần, hi vọng tip nho nhỏ sau đây có thể giúp ích phần nào công việc của bạn. Giả sử chúng ta có 2 bảng x_value, và y_value

# x_value.rb
class XValue < ActiveRecord::Base
  has_and_belongs_to_many :y_values
end
# y_value.rb
class YValue < ActiveRecord::Base
  has_and_belongs_to_many :x_values
end

Bảng quan hệ:

# x_values_y_value.rb
class XValuesYValue < ActiveRecord::Base
  belongs_to :x_value
  belongs_to :y_value
end

Index của bảng quan hệ:

# index.html.erb
<table>
  <tr>
    <td></td>
    <% @x_values.each do |x_value| %>
      <td> x_value.name %>td>
    <% end %>
    </tr><% @y_values.each do |y_value| %>
    <tr>
      <td><%= y_value.name %></td>
      <% @x_values.each do |x_value| %>
        <td> @x_values_y_values.find_by(x_value: x_value,
        y_value: y_value).id rescue nil %><td>
      <% end %>
    </tr>
   <% end %>
  <tr>
</table>

Màn hình sẽ là như thế này (vị trí trống là không có quan hệ, vị trí có quan hệ là id của x_values_y_value):

nn_01.jpg

<%= @x_values_y_values.find_by(x_value: x_value,
y_value: y_value).id rescue nil %>

Dòng này sẽ làm cho việc hit vào database số lần bằng số phần tử trong bảng 😦, không được tốt cho lắm.

nn_02.jpg

Thêm 2 dòng scope class XValuesYValue :

# x_values_y_value.rb
scope :sort_by_x_value_name, ->{joins(:x_value)
.order("x_values.name")}
scope :sort_by_y_value_name, ->{joins(:y_value)
.order("y_values.name")}

Gọi ra từ controller:

# x_values_y_values_controller.rb
@x_values_y_values = XValuesYValue.all.sort_by_x_value_name
.sort_by_y_value_name

Thay đổi trong file index 1 tẹo

# index.html.erb
<table>
  <tr>
    <td></td>
    <% @x_values.each do |x_value| %>
      <td>
        <%= x_value.name %>
      </td>
    <% end %>
  </tr>
  <% index = 0 %>
  <% @y_values.each do |y_value| %>
    <tr>
      <td><%= y_value.name %></td>
      <% @x_values.each do |x_value| %>
        <td>
          <% if @x_values_y_values[index] &&
            (@x_values_y_values[index].x_value_id == x_value.id) &&
              (@x_values_y_values[index].y_value_id == y_value.id) %>
            <%= @x_values_y_values[index].id %>
            <% index += 1 %>
          <% end %>
        </td>
      <% end %>
    </tr>
  <% end %>
</table>

Màn hình sẽ là: nn_01.jpg Số lần hit vào database: nn_03.jpg Cách làm đơn giản chỉ là sort lại dữ liệu theo thứ tự in ra và nhảy index khi giả trị in ra đúng chỗ nn_04.jpg Cảm ơn đã đọc bài viết, hi vọng sẽ giúp ích phần nào công việc của bạn.


All Rights Reserved