【Rails 应用实战】6. 表单单选(有限的种类、无额外 Model)

87 阅读2分钟

6-1 情境准备

这一章我们要示范如何在表单实作一个单选的UI,单选的选项是固定的,不需要额外建立Model 来存选项。例如活动(Event)需要一个状态字段,有多少种「状态」是固定的、有限的。在后台可以编辑,前台可以显示。或是活动可以选择固定种类的分类等等,都属于这种UI。

首先,在资料库新增一个字段来存这个状态,我们会用字串代号来代表不同状态,而不直接存给用户看的中文:

  • draft 代表草稿活动
  • public 代表公开活动
  • private 代表私密活动

这个范例使用字串来代表不同状态,有些程序员喜欢用数字。用字串的优点是一目了然,可读性高。用数字的优点是资料库占的空间较少效能较高一些,但是缺点是光看数字是不懂意义的。

这是因为:

  1. 要显示给用户的的中文,可能会因为需求而改变。但是资料库的资料不会改。
  2. 多国语系的支援,实际显示给用户的会依照用户语系而改变
  3. 程序可能会依赖这个代码,写程序时一律写英文比较一致,例如if event.status == 'draft'

请执行rails g migration add_status_to_events

编辑20170414072940_add_status_to_events.rb

  class AddStatusToEvents < ActiveRecord::Migration[5.0]
    def change
+     add_column :events, :status, :string, :default => "draft"
    end
  end

执行bin/rails db:migrate

可以编辑app/models/event.rb,加上资料验证

  class Event < ApplicationRecord

+   STATUS = ["draft", "public", "private"]
+   validates :status, inclusion: { in: STATUS }

6-2 显示输出

资料库存的是代码而已,实际显示给用户时,需要转换成中文,作法有两种:

方法一:用Helper

编辑app/helpers/events_helper.rb

  module EventsHelper

+   def display_event_status(event)
+     case event.status
+       when "draft"
+         "草稿"
+       else
+         ""
+     end
+   end

  end

编辑app/views/events/show.html.erb

+ <h2><%= display_event_status(@event) %></h2>

方法二:用I18n

如果已经配置了多国语系,可以改用i18n,以下我们会用这种做法。

编辑app/views/events/show.html.erb

+ <h2><%= t(@event.status, :scope => "event.status") %></h2>

编辑config/locals/zh-CN.yml

  "zh-CN":
+   event:
+     status:
+       draft: 草稿
+       public: 公開
+       private: 私密

如果只做中文版,就不编辑 en.yml 也没关系。

6-3 使用Select 下拉选单

接着我们编辑后台的表单,加一个下拉选单来选择状态:

编辑app/views/admin/events/_form.html.erb

+   <div class="form-group">
+     <%= f.label :status %>
+
+     <%= f.select :status, Event::STATUS.map{ |s| [t(s, :scope => "event.status"), s] }, {}, :class => "form-control" %>

+   </div>

其中第二个参数 Event::STATUS.map{ |s| [t(s, :scope => "event.status"), s] } 是一个二维阵列,表示下拉的选项、第三个和第四个参数都是Hash,为了顺利让第四个参数(设置Bootstrap 样式需要的class)传进去,所以要补一个空的Hash 在第三个参数。详见Rails select 文档

编辑app/controllers/admin/events_controller.rb

   def event_params
-    params.require(:event).permit(:name, :description, :friendly_id)
+    params.require(:event).permit(:name, :description, :friendly_id, :status)
   end

这样就可以选择状态了:

6-4 改用Radio Button UI

如果选项是3 个以下,可以考虑改用Radio Button,对用户会更方便(鼠标只要点一次就可以选择):

再次编辑app/views/admin/events/_form.html.erb,把 f.select :status 改成:

  <% Event::STATUS.each do |status| %>
    <label>
      <%= f.radio_button :status, status %>
      <%= t(status, :scope => "event.status") %>
    </label>
  <% end %>

用label 标签包起来的话,点选文字才会有选radio 的效果

6-5 使用Radio Button 加上Bootstrap Button 样式

Radio Button UI 也可以考虑搭配Bootstrap 按钮样式,请修改成:

  <div class="btn-group" data-toggle="buttons">
    <% Event::STATUS.each do |status| %>
      <label class="btn btn-default <%= (status == f.object.status)? 'active' : '' %>">
        <%= f.radio_button :status, status %>
        <%= t(status, :scope => "event.status") %>
      </label>
    <% end %>
  </div>

这样就很漂亮了。