Build on/off toggle state function in Rails
Xây dựng chức năng chuyển trạng thái on-off trong Rails app. Trong quá trình làm trang web với Rails, mình cần làm một chức năng là người dùng click thay đổi trạng thái on/off và lưu ngay vào database. Có rất nhiều cách làm cho chức năng này, ở đây mình sử dụng ajax để gửi data lên server và ...
Xây dựng chức năng chuyển trạng thái on-off trong Rails app.
Trong quá trình làm trang web với Rails, mình cần làm một chức năng là người dùng click thay đổi trạng thái on/off và lưu ngay vào database.
Có rất nhiều cách làm cho chức năng này, ở đây mình sử dụng ajax để gửi data lên server và cập nhật view sau khi update trên server thành công.
Bài toán
Bài toán đặt ra là mình có một bảng option_groups, bảng này có một trường lưu trữ trạng thái của các bản ghi gọi là is_active. Công việc đặt ra là khi người quản trị click vào button on/off thì sẽ chuyển trạng thái tương tự và cập nhật vào database.
Triển khai
Đầu tiên mình sẽ hiển thị danh sách các option_groups tại trang index theo dạng bảng.
Hiển thị danh sách
Trong controller app/controllers/option_groups_controller.rb
class OptionGroupsController < ApplicationController def index @option_groups = OptionGroup.all end
Tiếp theo là hiển thi ra view
app/views/option_groups/index.slim
.ibox-content#js-option-group-list table.table.table-striped.table-hover.table-bordered thead tr th.col-sm-1.text-center= t(".status") th= t(".option_group_name") tbody - @option_groups.each do |option_group| tr td.text-center = status_for option_group td= link_to option_group.name, option_group_path(option_group)
Như phía trên là mình hiển thị danh sách trong bảng. Có hàm status_for, mình sẽ định nghĩa hàm này trong helpers để mục đích hiển thị ra icon cùng một số thuộc tính cho on/off.
# helpers/option_groups_helper.rb class OptionGroupsHelper def status_for option_group if option_group.is_active content_tag(:i, "", class: "fa fa-toggle-on fa-2x cursor-pointer on-off-swap", data: {id: option_group.id}) else content_tag(:i, "", class: "fa fa-toggle-off fa-2x cursor-pointer on-off-swap", data: {id: option_group.id}) end end end
Cập nhật thay đổi trạng thái vào database
Tiếp theo mình sẽ tiến hành sử dụng ajax để gửi request lên server update lại trạng thái cho option_group tại trường is_active.
Bổ sung thêm vào controller cho hàm update
# app/controllers/option_groups_controller.rb def update @option_group = OptionGroup.find params[:id] respond_to do |format| if @option_group.update(option_group_params) format.json {head :no_content} else format.json {render json: @option_group.errors, status: :unprocessable_entity} end end end private def option_group_params params.require(:option_group).permit :is_active, :name end
Bởi vì ở đây mình update sử dụng json, do đó mình không viết dạng trả về kiểu html.
Sử dụng ajax để gửi data lên server và update trạng thái.
$("#js-option-group-list tbody").on "click", ".on-off-swap", -> id = $(@).data "id" $status_field = $(@).parent().children "i" fa_toggle_class = { 0: "fa-toggle-off", 1: "fa-toggle-on" } if $status_field.hasClass "fa-toggle-off" new_status = 1 else new_status = 0 $.ajax type: "PATCH" url: "/option_groups/#{id}" data: option_group: {is_active: new_status} dataType: "json" success: () -> $status_field.removeClass("fa-toggle-off fa-toggle-on") .addClass fa_toggle_class[new_status] return
Như vậy mỗi khi cập nhật bằng ajax thành công thì trên view sẽ cập nhật thay đổi theo.
Thêm rspec cho hàm helper vừa tạo
describe "status_for" do subject{helper.status_for option_group} context "when is_active is false" do let(:option_group){create :option_group, is_active: false} it{is_expected.to eq content_tag(:i, "", class: "fa fa-toggle-off fa-2x cursor-pointer on-off-swap", data: {id: option_group.id})} end context "when is_active is true" do let(:option_group){create :option_group} it{is_expected.to eq content_tag(:i, "", class: "fa fa-toggle-on fa-2x cursor-pointer on-off-swap", data: {id: option_group.id})} end end