新手问题 china_city Gem 为什么用 f.select 不能正常显示?

mayalin · 2016年10月09日 · 最后由 jasl 回复于 2016年10月10日 · 3056 次阅读

想要使用@sabermachina_city 实现一个 三阶地址选择,Gemfile/Application.js/routes.rb 已按官方指南设定。

在 view checkout.html.erb 里用 select_tag来选择省市区域,选择框正常,且后台可以看到 province/city/area 有被赋值。

<h2>订单资讯</h2>

  <div class="order-form">
    <%= simple_form_for @order do |f| %>
      <legend>配送地址</legend>
        <div class="form-group col-md-6">
          <%= f.input :shipping_name, label: '姓名' %>
          <div class="city-group">
            <%= f.label '地区' %>
            <%= select_tag :province, options_for_select(ChinaCity.list.unshift(["--省份--", 0]),0), class: "city-select" %>
            <%= select_tag :city, options_for_select(["--城市--", 0]), class: "city-select" %>
            <%= select_tag :area, options_for_select(["--地区--", 0]), class: "city-select" %>
          </div>
          <br>
           <%= f.input :shipping_address, label: '街道地址' %>
           <%= f.input :phone_number, label: '电话' %>
        </div>

        <legend></legend>
        <div class="checkout">
          <%= f.submit "生成订单", class: "btn btn-lg btn-danger pull-right",
                        data: {disable_with: "Submitting..."} %>
        </div>
    <% end %>
  </div>

但在下页 show.html.erb 里面,用ChinaCity.get无法读出对应的 province/city/area。select_tag并没有把值传递出去。

<h2>寄送资讯</h2>

    <table class="table table-striped table-bordered">
      <tbody>
        <tr>
          <td>
            配送地址
          </td>
        </tr>
        <tr>
          <td>
            <%= @order.shipping_name %><br>
            <%= ChinaCity.get(@order.province) %> <%= ChinaCity.get(@order.city) %> <%= ChinaCity.get(@order.area) %><br>
            <%= @user7ss %><br>
            <%= @order.phone_number %>
          </td>
        </tr>
      </tbody>
    </table>

然后尝试把 checkout.html.erb 里面的select_tag都换f.select,选择框只有 province 可用,城市/地区 不可用;但是省份的值可以传递到 show 页面。

<!--同上,略-->
              <%= f.select :province, options_for_select(ChinaCity.list.unshift(["--省份--", 0]),0), class: "city-select" %>
              <%= f.select :city, options_for_select(["--城市--", 0]), class: "city-select" %>
              <%= f.select :area, options_for_select(["--地区--", 0]), class: "city-select" %>

尝试看了 Form Helpers,并没有找到可行的方案。现在我要怎么做才能使 地址选择框在 checkout.html.erb 正常可用,然后值可以传递到下页 show.html.erb 里面?谢谢~

select_tagf.select 是不同的。 你看一下这两个函数参数的区别。

  1. select_tag
  2. f.select

你这里其实有两个问题,

  1. form 中的内容 province/city/area 没有提交并被保存,所以 show 中看不到。
  2. china_city 在使用f.select时不工作但是能够提交。

我给几个提示

  1. 你看一下 f.selectselect_tag生成的 HTML 代码有什么不同,它们具体是怎么用的。
  2. 再看一下 china_city 中 demo 中的 html 是什么样子的。
  3. province 被保存和没有被保存的两种情况下,HTML 代码有什么区别?

ls 说的思路对,补充一点是 Rails 请求的 Log 里打印的 Parameters 是真理

不过那 gem 没封装 form helper 所以用的时候可能比较麻烦,我建议自己写个 helper,比如我们的

def address_select(f, address, field, options = {})
  case field
  when :province
    select_tag "#{f.object_name}[province_code]",
               options_for_select(ChinaCity.list, address.province_code),
               {prompt: '- 省/直辖市 -'}.merge(options)
  when :city
    select_tag "#{f.object_name}[city_code]",
               options_for_select(ChinaCity.list(address.province_code), address.city_code),
               {prompt: '- 城市 -'}.merge(options)
  when :district
    select_tag "#{f.object_name}[district_code]",
               options_for_select(ChinaCity.list(address.city_code), address.district_code),
               {prompt: '- 地区 -'}.merge(options)
  else
    ''
  end

另外,好像那 gem 的 jquery 代码我记得有点问题...我忘记当初因为什么没有 PR 回去了(貌似跟项目耦合还是啥情况来着。。三年前的事情了),我贴下我项目里重写的版本

(($) ->
  $.fn.china_city = () ->
    @each ->
      $selects = $(@).find('.city-select')
      $selects
      .on 'change.city', ->
        $this = $(@)
        select_index = $selects.index($this)+1
        select = $selects.eq(select_index)
        # clear children's options
        $selects.slice($selects.index(@) + 1).each ->
          $(@).children().slice(1).remove()
        # when select value not empty
        if select[0] and $(@).val()
          $.get "/china_city/" + $(@).val(), (data) ->
            options = select[0].options
            $.each data.data, (i, item) -> options.add new Option(item.data[0], item.data[1])

  $ ->
    ($cityGroup = $('.city-group')).length and $cityGroup.china_city()
)(jQuery)

需要 登录 后方可回复, 如果你还没有账号请 注册新账号