文章目錄
  1. 1. 前言
  2. 2. 準備環境
  3. 3. 建立專案
  4. 4. 建立model及準備樣本資料
    1. 4.1. 說明
    2. 4.2. 準備樣本資料
  5. 5. 建立Controllers
    1. 5.1. 說明:
  6. 6. view
    1. 6.1. 說明
  7. 7. 待改進處:
  8. 8. 整個完整流程

前言

所謂的單頁表單,就是在同一頁面中,上面有一個選單,下面則是選擇區。當你在選單中選擇項目時,下方的選擇區會根據你在選單中的選項而有所變動。目前單頁應用程式(Single Page Appliation, SPA)非常流行,事實上製作SPA最棒的後端還是node.js,我們以後有機會會提到,在本篇文章中,我們使用rails來看看一個非常簡單的單頁表單作法,先用最簡單的http get的方法來完成,這應該是最簡單的rails應用了。

舉例來說,我們有三個國家,分別是美國、中國、日本,每個國家有自己城市如下:

中國
–北京
–上海
–廣州

日本
–東京
–北海道
–大阪

美國
–洛杉磯
–紐約
–芝加哥

我們要的效果就是在選單中選擇國家,同一頁下方的顯示區就會顯示對應的城市。

準備環境

作業系統:Mac OS或是Ubuntu 16.04
ruby版本:2.3.0
rails版本:4.2.6
請遵照前面文章安裝rvm來管理不同版本的ruby以及gem set。

建立專案

mkdir updateForm
cd updateForm
echo 2.3.0 > .ruby-version
echo jobexam > .ruby-gemset
rails new .
bundle install
git init

其中.ruby-version.ruby-gemsetrvm管理ruby以及gem set的專案資源檔,如果目錄中有這兩個檔案,只要進入該目錄,就會自動切換成這兩個檔案指定的ruby版本及gemset。讀者要注意的是jobexam這個gemset是之間我已經建立好的。讀者可以自行建立你的gemset,只要確定你的rails版本為4.2.6即可,之後用rails new .建立專案,bundle install安裝需要的gem

建立model及準備樣本資料

我們需要兩個model,一個是國家,一個是城市,輸入下面指令建立

rails g model country name:string
rails g model city name:string country:reference
rake db:migrate

說明

首先建立一個model名稱為country,只有一個自訂屬性name即國家名稱。接下來建立另一個model為city,有一個自訂屬性name為城市名稱之為,我們要讓系統知道這個model是country這個model的子類別,即一個country可以有多個cities,因此加上country:reference。這句話的意思其實就是在city這個model中加上belongs_to :country

另外我們要到country這個model中手動加入擁有多個cities的敘述,打開app/models/country.rb輸入如下:

# app/model/country.rb
class Country < ApplicationRecord
  has_many :cities
end

你也可以打開app/models/city.rb來看,由於使用了country:reference的參數來建立model,因此已經會預設有belongs_to :country了。

# app/model/city.rb
class City < ApplicationRecord
  belongs_to :country
end

準備樣本資料

開啟db/seeds.rb,並且輸入資料如下:

# db/seeds.rb

Country.delete_all

Country.create!(
  { id: 1,
    name: "美國"
  }
)
Country.create!(
  { id: 2,
    name: "中國"
  }
)
Country.create!(
  { id: 3,
    name: "日本"
  }
)

City.delete_all

City.create!(
  { id: 1,
    name: "洛杉磯",
    country_id: 1
  }
)
City.create!(
  { id: 2,
    name: "紐約",
    country_id: 1
  }
)
City.create!(
  { id: 3,
    name: "芝加哥",
    country_id: 1
  }
)
City.create!(
  { id: 4,
    name: "北京",
    country_id: 2
  }
)
City.create!(
  { id: 5,
    name: "上海",
    country_id: 2
  }
)
City.create!(
  { id: 6,
    name: "廣州",
    country_id: 2
  }
)
City.create!(
  { id: 7,
    name: "東京",
    country_id: 3
  }
)
City.create!(
  { id: 8,
    name: "北海道",
    country_id: 3
  }
)
City.create!(
  { id: 9,
    name: "大阪",
    country_id: 3
  }
)

建立Controllers

接下來要建立Controllers。由於我們只要顯示城市,因此只要建立cities controller以及在config/routes.rb中對應的路由。先建立controller。

rails g controller cities index create

接下來修改路由如下:

# config/routes.rb
Rails.application.routes.draw do
  resources :cities, only: [:index, :create]
end

上面的路由中,我們使用標準的RestFUL資源型式,但由於只需要用到GET/POST cities,因此只用兩個actions即可。接下來就可以編輯controller了,如下:

# app/controllers/cities_controller.rb
class CitiesController < ApplicationController
  def index
    @countries = Country.all
    @cities = City.where(country_id: params[:country_id])
  end
end

說明:

其中先將所有的國家讀到@countries這個變數中給選單用,然後設定@cities則是使用者選取選單之後,把國家代碼傳回這個action,再去資料庫取出符合國家代碼的城市。

view

View有兩個部分,一個是index這個action對應的template,即app/view/cities/index.html.erb,另一個則是單獨要列出所有城市的partial。如下:

<h2>選擇國家</h2>
<%= form_tag "/cities" ,method: :get do %>
  <%= select_tag :country_id, options_from_collection_for_select(@countries, "id","name")%>
  <%= button_tag "查詢" %>
<% end %>
<ul>
  <%= render @cities %>
</ul>
<%= debug(params) if Rails.env.development? %>

說明

第2行這邊不使用form_for而使用form_tag是為了簡化。首先要做的就是加上method: :get表示這個表單是要用GET,因此在RestFUL的動作中就還是會回到cities#index這個action中,因此我們的controller就沒有對應到POSTcreate這個action

第3行使用了標準的select_tag,並且使用了options_from_collection@countries放入collection中成為選單,並且以idhtmlvaluename為顯示出來的值。最後第4行放上一個按鈕送出。注意:在rails中,輸入表單一定要有一個送出的機制,因此這邊一定要放入一個button_tag,才會產生RestFUL的GET或POST動作。

接下來是第7行的<%= render @cities %>。這句敘述表示要將@cities這整個collection丟到一個叫做_city.html.erbpartial來顯示,而且在_city.html.erb中,你不需要使用@cities.each do |city|的迴圈來執行,這種型式的partial會自動把整個@citiesiterate一遍。因此我們要建立這個partial,檔案為app/view/cities/_city.html.erb

<li><%= city.name %></li>

接下來先將這個版本的程式commit,輸入git add .以及git commit -am "init",然後直接啟動,輸入rails s -b 0.0.0.0 -p 3001,就可以登入看結果,請到該主機上輸入http://localhost:3001/cities/

待改進處:

1.執行結果使用get到原方法,因此選單中的選項會回到最原始的預設值美國
2.使用get表單,因此雖然看起來是在同一頁,其實是有換頁,正確應該用ajax,就是只更新顯示城市的地方而不要換頁。
3.選擇國家後,應後就直接顯示城市,而不需要一個按鈕。

整個完整流程

接下來是整個完整流程

  1. 使用者在瀏覽器中輸入http://192.168.1.105:4000/cities,就是在向後端的伺服器發出GET HTTP。
  2. 伺服器檢查使用者的請求,去查routes是否存在這個請求。
  3. 伺服器發現這個請求對應的是’cities#index`這個action,因此執行這個action中的動作。
  4. 執行index這個action之後,把變數代表的值丟到對應的template index.html.erb
  5. index.html.erb把變數代表的值換掉其中的變數,成為index.html
  6. index.html傳回使用者瀏覽器執行。
  7. 使用者從index.html中的選單選擇,並且按下按鈕。
  8. 重複2-6的動作。
文章目錄
  1. 1. 前言
  2. 2. 準備環境
  3. 3. 建立專案
  4. 4. 建立model及準備樣本資料
    1. 4.1. 說明
    2. 4.2. 準備樣本資料
  5. 5. 建立Controllers
    1. 5.1. 說明:
  6. 6. view
    1. 6.1. 說明
  7. 7. 待改進處:
  8. 8. 整個完整流程