12/08/2018, 16:36

Sử dụng selecbox và cache giá trị selecbox trong Rails

Việc sử dụng selectbox trong hiển thị dự liệu là khá phổ biến và dễ dàng, nhưng đôi lúc ta quên mất xét hiệu năng sử dụng của nó. Để tăng tính hiệu quả trong sử dụng selectbox mình xin chia sẻ một thủ thuật nhỏ sưu tầm được. Tạo database test: category model: class CreateCategory ...

Việc sử dụng selectbox trong hiển thị dự liệu là khá phổ biến và dễ dàng, nhưng đôi lúc ta quên mất xét hiệu năng sử dụng của nó. Để tăng tính hiệu quả trong sử dụng selectbox mình xin chia sẻ một thủ thuật nhỏ sưu tầm được.

Tạo database test:

  • category model:
class CreateCategory < ActiveRecord::Migration
  def change
    create_table :category do |t|
      t.string :name

      t.timestamps null: false
    end
  end
end
  • book model:
class CreateBook < ActiveRecord::Migration
  def change
    create_table :book do |t|
      t.references :category, index: true, foreign_key: true
      t.string :name
      
      t.timestamps null: false
    end
  end
end

Giả sử ta muốn hiển thị tất các course dạng selectbox trong views/books/index.html.erb.

  • bookscontroller.rb :
  def index
    @categories = Category.all
  end
  • views/books/index.html.erb
  <%= select("book", "category_id", @categories.collect {|category| [ category.name, category.id ] }, { include_blank: true }) %>

OR

  <%= select_tag "category_id", options_from_collection_for_select(@categories, "id", "name") %>

Nhưng điều gì sẽ xảy ra nếu số lượng Category.all khá lớn ?

Để hạn chế việc liên tục load Category.all vào selectbox ta cần cache nó lại

Cache data trong selectbox

  • Ta tạo một file models/concerns/actsasoptionsprovider.rb
module ActsAsOptionsProvider
  CACHE_OPTION = {expires_in: 30.minutes} # thoi gian cache
  extend ActiveSupport::Concern

  included do
    after_commit{Rails.cache.delete "#{self.class.name}_options"} # *xoa cache khi co su thay doi record*
    acts_as_options_provider
  end

  class_methods do
    def acts_as_options_provider *attrs
      options = attrs.last.is_a?(Hash) ? attrs.pop : CACHE_OPTION
      attrs = [:name, :id] if attrs.empty?
      key_name = "#{name}_options"
      method_name = options.delete(:method_name) || :options
      singleton_class.send :define_method, method_name, -> do
        Rails.cache.fetch key_name, options do
          pluck(*attrs)
        end
      end
    end
  end
end
  • /models/category.rb
class Category< ApplicationRecord
  include ActsAsOptionsProvider
....

  • Xem sự khác biệt giá trị trả về của @categories
#Category.all

[51] pry(main)> Category.all
   (0.2ms)  SET NAMES utf8mb4 COLLATE utf8mb4_bin,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
  Course Load (0.2ms)  SELECT `categories`.* FROM `categories`
=> [#<Category:0x00556e5a8c42e0 id: 1, name: "Category-1", created_at: 2017-12-11 10:59:29 UTC, updated_at: 2017-12-11 10:59:29 UTC>,
 #<Category:0x00556e5a8c0410 id: 2, name: "Category-3", created_at: 2017-12-11 10:59:34 UTC, updated_at: 2017-12-11 10:59:34 UTC>,
 #<Category:0x00556e5a8c02d0 id: 3, name: "Category-4", created_at: 2017-12-11 10:59:37 UTC, updated_at: 2017-12-11 10:59:37 UTC>]

#Category.options

  [52] pry(main)> Category.options
   (0.4ms)  SELECT `categories`.`name`, `categories`.`id` FROM `categories`
=> [["Category-1", 1], ["Category-3", 2], ["Category-4", 3]]
  • bookscontroller.rb
  def index
    @categories = Category.options
 end
  • views/books/index.html.erb
  <%= select_tag "category_id", options_from_collection_for_select(@categories) %>

Link tham khảo:

https://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/select https://apidock.com/rails/ActionView/Helpers/FormTagHelper/select_tag

0