Build on/off toggle state function in Rails
This post hasn't been updated for 7 years
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
All Rights Reserved