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