Action View Form Helpers(3)

Using Date and Time Form Helpers
select_date,select_time與select_datetime為輸入日期時間的輔助方法,用法如下

<%= select_date DateTime.now, prefix: :start_date %>
<%= select_time DateTime.now, prefix: :select_time %>
<%= select_datetime DateTime.now, prefix: :select_datetime %>

頁面顯示如下
螢幕快照 2017-10-13 下午10.28.36
可視情況來使用

在表單送出後,若使用了select_date的方式,則start_date會包含了:year,:month,:day三個值,請參考下例

Date.civil(params[:start_date][:year].to_i, params[:start_date][:month].to_i, params[:start_date][:day].to_i)

但若是要對應到Model則要採用date_select,time_select,datetime_select,用法如下

<%= date_select :person, :birth_date %>
<%= time_select :person, :birth_date %>
<%= datetime_select :person, :birth_date %>

若是僅僅要顯示時間的某個部份,則可使用 select_year、select_month、select_day、select_hour、select_minute 以及 select_second 這些方法.
例如

<%= select_year(2017) %>
<%= select_year(Time.now) %>

因今年為2017,因此用以上兩種方法輸出都為相同,數值可以在 params[:date][:year] 取出。

Uploading Files
一般頁面上除了輸入資料外,也會有上傳檔案的動作,檔案格式包含圖片,csv…等
檔案上傳最重表單的編碼必須是"multipart/form-data"。若使用 form_for,已經自動設定好了。若使用 form_tag,則必須自己設定

為何編碼須為"multipart/form-data"
以下是表單上傳檔案的兩個例子:

<%= form_tag({action: :upload}, multipart: true) do %>
  <%= file_field_tag 'picture' %>
<% end %>

<%= form_for @person do |f| %>
  <%= f.file_field :picture %>
<% end %>

一般上傳會使用file_field_tag,而若是要對應到Model進行上傳則會使用 file_field,若使用 file_field_tag 上傳的檔名會存在 params[:picture],若使用 file_field 上傳的檔案名則放在 params[:person][:picture]。

圖片上傳後會存放在 {Rails.root}/public/upload 底下
而一般常用的gem為 carrierwavepaperclip

Understanding Parameter Naming Conventions
表單的數值可以在params的第一層,或是嵌套在Hash裡。例如:Person這個Model所對應的Controller create動作中,params[:person]這個Hash,包含建立person所需的屬性。

在console中執行即可了解一個簡易的範例,由此範例中可看到key-value的對應

Rack::Utils.parse_query "name=fred&phone=0123456789"
# => {"name"=>"fred", "phone"=>"0123456789"}

接下來介紹一個基本的流程

<input size="20" name="person[name]" id="person_name" type="text">

頁面產生如下
螢幕快照 2017-10-15 上午12.08.59

則params的內容為
螢幕快照 2017-10-15 上午12.21.24如此一來在 Controller 可以用 params[:person][:name] 來取出表單送出的數值。

另外,若是有多層的狀況怎可採用

<input id="person_address_city" name="person[address][city]" type="text" value="New York"/>

產生如下

{'person' => {'address' => {'city' => 'New York'}}}

此時則用params[:person][:address][:city] 來取得數值 ‘New York’

表單輔助方法–這裏介紹了一個人擁有兩個地址,該如何於一個表單中編輯.其中地址的Model為Address
這裏利用了form_for 與 fields_for,以及 :index 的方式產生表單

<%= form_for @person do |person_form| %>
  <%= person_form.text_field :name %>
  <% @person.addresses.each do |address| %>
    <%= person_form.fields_for address, index: address.id do |address_form|%>
      <%= address_form.text_field :city %>
    <% end %>
  <% end %>
<% end %>

輸出如下,其中23與45為id

<form accept-charset="UTF-8" action="/people/1" class="edit_person" id="edit_person_1" method="post">
  <input id="person_name" name="person[name]" type="text" />
  <input id="person_address_23_city" name="person[address][23][city]" type="text" />
  <input id="person_address_45_city" name="person[address][45][city]" type="text" />
</form>

其params為

{'person' => {'name' => 'Bob', 'address' => {'23' => {'city' => 'Paris'}, '45' => {'city' => 'London'}}}}

此處的重點在於,一個人有可能有多個地址,若是params中少了索引,要修改時若是改了個地址存檔有可能會修改到另一個地址,因此索引是絕對必要的

Forms to External Resources
rails的表單輔助方法中也提供了送出表單資料到一外部資源的方法,此時必須設置一個authenticity_token,可利用 :authenticity_token的方法來完成,如下例:

<%= form_tag 'http://farfar.away/form', authenticity_token: 'external_token' do %>
  Form contents
<% end %>

http://farfar.away/form 為外部資源的URL,而’external_token’可自行設置
有時因外部支援所限,不希望authenticity_token產生則可將其關閉,如下所示:

<%= form_tag 'http://farfar.away/form', authenticity_token: false do %>
  Form contents
<% end %>

一樣的方法在form_for也適用

<%= form_for @invoice, url: external_url, authenticity_token: 'external_token' do |f| %>
  Form contents
<% end %>

其中url需參照routes

Building Complex Forms
如果一個表單中要處理的狀況有不僅是編輯單一Model那麼簡單時–例如一個使用者資料可擁有多個地址(公司地址,住家地址…等),往後編輯使用者表單時可一併編輯地址.

首先建立Model,方式如下

class Person < ActiveRecord::Base
  has_many :addresses
  accepts_nested_attributes_for :addresses
end
class Address < ActiveRecord::Base
  belongs_to :person
end

此處accepts_nested_attributes_for是為必須,可以透過這個語法,在更新資料的時候,同時更新其他Model裡的資料

View的部分如下

<%= form_for @person do |f| %>
  Addresses:
<ul>
    <%= f.fields_for :addresses do |addresses_form| %>
	<li>
        <%= addresses_form.label :kind %>
        <%= addresses_form.text_field :kind %>
        <%= addresses_form.label :street %>
        <%= addresses_form.text_field :street %>
        ...</li>
<% end %></ul>
<% end %>

此處利用fields_for的方式列出Person底下的addresses
而在對應的controller中,新建 person 的表單產生兩組地址欄位.

def new
  @person = Person.new
  2.times { @person.addresses.build}
end

表單送出後即進行create動作,這裏需注意的是白名單處理方式,除了person之外需再加上addresses的欄位

def create
  @person = Person.new(person_params)
  # ...
end
private
  def person_params
    params.require(:person).permit(:name, addresses_attributes: [:id, :kind, :street])
  end
廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s