在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Ruby/ 3.2 表單
寫(xiě)在后面
寫(xiě)在前面
第六章 Rails 的配置及部署
第四章 Rails 中的模型
4.4 模型中的校驗(yàn)(Validates)
1.3 用戶界面(UI)設(shè)計(jì)
6.5 生產(chǎn)環(huán)境部署
3.2 表單
4.3 模型中的關(guān)聯(lián)關(guān)系(Relations)
4.5 模型中的回調(diào)(Callback)
第五章 Rails 中的控制器
4.2 深入模型查詢
5.2 控制器中的方法
6.2 緩存
3.4 模板引擎的使用
6.4 I18n
第一章 Ruby on Rails 概述
6.6 常用 Gem
1.2 Rails 文件簡(jiǎn)介
2.2 REST 架構(gòu)
2.3 深入路由(routes)
第三章 Rails 中的視圖
6.3 異步任務(wù)及郵件發(fā)送
第二章 Rails 中的資源
3.3 視圖中的 AJAX 交互

3.2 表單

概要:

本課時(shí)講解 Rails 如何通過(guò)表單(Form)傳遞數(shù)據(jù),以及表單中的輔助方法使用,并實(shí)現(xiàn)登陸注冊(cè)功能。

知識(shí)點(diǎn):

  1. 表單
  2. 表單中的輔助方法(helper)
  3. 表單綁定模型(Model)
  4. 注冊(cè)和登錄

正文

3.2.1 搜索表單(Form)

如果我們的表單不產(chǎn)生某個(gè)資源的狀態(tài)改變,我們可以使用 GET 發(fā)送表單,這么說(shuō)很抽象,比如一個(gè)搜索表單,就可以是 GET 表單。

我們?cè)陧?yè)面的導(dǎo)航欄上,增加一個(gè)搜索框:

<%= form_tag(products_path, method: "get") do %>
  <%= label_tag(:q) %>
  <%= text_field_tag(:q) %>
  <%= submit_tag("搜索") %>
<% end %>

form_tag 產(chǎn)生了一個(gè)表單,我們?cè)O(shè)定它的 methodget,它的 action 地址是 products_path,我們也可以設(shè)定一個(gè) hash 來(lái)制定地址,比如:

form_tag({action: "search"}, method: "get") do

這需要你在 products 里再增加一個(gè) search 方法,否則,你會(huì)得到一個(gè) No route matches {:action=>"search", :controller=>"products"} 的提示,這告訴我們,form_tag 的第一個(gè)參數(shù)需要是一個(gè)可解析的 routes 地址。當(dāng)然,你也可以給它一個(gè)字符串,這個(gè)地址即便不存在,也不會(huì)造成 no route 提示了。

form_tag("/i/dont/know", method: "get") do

這并不是我們最終的代碼,我們還需要增加一些附加的屬性,讓我們的式樣看起來(lái)正常一些。而且我用了 params[:q] 這個(gè)方法,獲得地址中的 q 參數(shù),把搜索的內(nèi)容放回到搜索框中。

http://wiki.jikexueyuan.com/project/rails-practice/images/chapter_3/4.png" alt="" />

我們可以在 controller 里,使用 ActiveRecord 的 where 方法查詢傳入的參數(shù),我們也可以使用 (ransack)[https://github.com/activerecord-hackery/ransack] 這種 gem 來(lái)實(shí)現(xiàn)搜索功能。

ransack 是一個(gè) metasearch 的 gem,實(shí)現(xiàn)它非常的方便。我們把它加入到 gemfile 里:

gem 'ransack'

我們?cè)谝晥D里,使用 ransack 提供的輔助方法,來(lái)實(shí)現(xiàn)表單:

<%= search_form_for @q, html: { class: "navbar-form navbar-left" } do |f| %>
  <div class="form-group">
    <%= f.search_field :name_cont, class: "form-control", placeholder: "輸入商品名稱" %>
  </div>
<% end %>

提示:如果每個(gè)頁(yè)面都包含這個(gè)搜索框,但是不見(jiàn)得每個(gè)頁(yè)面都有 @q 這個(gè)實(shí)例,所以我們可以自己寫(xiě)一個(gè)表單,實(shí)現(xiàn)搜索:

<%= form_tag products_path, method: :get, class: "navbar-form navbar-left" do %>
  <div class="form-group">
    <%= text_field_tag "q[name_cont]", params["q"] && params["q"]["name_cont"], class: "form-control input-sm search-form", placeholder: "輸入商品名稱" %>
  </div>
<% end %>

在商品的 controller 中,我們修改 index 方法:

def index
  @q = Product.ransack(params[:q])
  @products = @q.result(distinct: true)
end

好了,一個(gè)簡(jiǎn)單的查詢實(shí)現(xiàn)了。這里我們使用的是 name_cont 來(lái)實(shí)現(xiàn)模糊查詢,文檔 上提供了詳盡的方法,實(shí)現(xiàn)更復(fù)雜的查詢。

3.2.2 常用的表單輔助方法

在我們使用 form_tag 的同時(shí),我們還需要一些輔助方法來(lái)生成表單控件。

<%= text_area_tag(:message, "Hi, nice site", size: "24x6") %>
<%= password_field_tag(:password) %>
<%= hidden_field_tag(:parent_id, "5") %>
<%= search_field(:user, :name) %>
<%= telephone_field(:user, :phone) %>
<%= date_field(:user, :born_on) %>
<%= datetime_field(:user, :meeting_time) %>
<%= datetime_local_field(:user, :graduation_day) %>
<%= month_field(:user, :birthday_month) %>
<%= week_field(:user, :birthday_week) %>
<%= url_field(:user, :homepage) %>
<%= email_field(:user, :address) %>
<%= color_field(:user, :favorite_color) %>
<%= time_field(:task, :started_at) %>
<%= number_field(:product, :price, in: 1.0..20.0, step: 0.5) %>
<%= range_field(:product, :discount, in: 1..100) %>

解析后的代碼是:

<textarea id="message" name="message" cols="24" rows="6">Hi, nice site</textarea>
<input id="password" name="password" type="password" />
<input id="parent_id" name="parent_id" type="hidden" value="5" />
<input id="user_name" name="user[name]" type="search" />
<input id="user_phone" name="user[phone]" type="tel" />
<input id="user_born_on" name="user[born_on]" type="date" />
<input id="user_meeting_time" name="user[meeting_time]" type="datetime" />
<input id="user_graduation_day" name="user[graduation_day]" type="datetime-local" />
<input id="user_birthday_month" name="user[birthday_month]" type="month" />
<input id="user_birthday_week" name="user[birthday_week]" type="week" />
<input id="user_homepage" name="user[homepage]" type="url" />
<input id="user_address" name="user[address]" type="email" />
<input id="user_favorite_color" name="user[favorite_color]" type="color" value="#000000" />
<input id="task_started_at" name="task[started_at]" type="time" />
<input id="product_price" max="20.0" min="1.0" name="product[price]" step="0.5" type="number" />
<input id="product_discount" max="100" min="1" name="product[discount]" type="range" />

更多的表單輔助方法,建議大家直接查看這個(gè)部分的 源代碼,我一直認(rèn)為源代碼是最好的教材。

3.2.3 模型(Model)的輔助方法

我們還可以使用不帶有 _tag 結(jié)尾的輔助方法,來(lái)顯示一個(gè)模型(Model) 實(shí)例(Instance),比如我們的 @product,可以在它的編輯頁(yè)面中這樣來(lái)寫(xiě):

<%= text_field(:product, :name) %>

他會(huì)給我們

<input type="text" value="測(cè)試商品" name="product[name]" id="product_name">

它接受兩個(gè)參數(shù),并把它拼裝成 product[name],并且把 value 賦予這個(gè)屬性的值。我們提交表單的時(shí)候,Rails 會(huì)把它解釋成 product: {name: '測(cè)試商品', ...},這樣,Product.create(...) 可以添加這個(gè)商品信息到數(shù)據(jù)庫(kù)中了。

不過(guò)這樣做會(huì)有個(gè)問(wèn)題,這個(gè)商品會(huì)有很多屬性需要我們填寫(xiě),會(huì)讓代碼變得“啰嗦”。這時(shí),我們可以把這個(gè)實(shí)例,綁定到表單上。

注:說(shuō)模型對(duì)象,通常指 Product 這個(gè)模型,說(shuō)模型實(shí)例,指 @product。一些文檔上并不區(qū)分這種稱呼,個(gè)人覺(jué)得容易混淆。

3.2.4 把模型(Model)綁定到表單上

來(lái)看看我們的商品添加界面使用的表單吧,它在這里 app/views/products/_form.html.erb

<%= form_for @product, :html => { :class => 'form-horizontal' } do |f| %>

這里我們用了 form_for 這個(gè)方法,它可以將一個(gè)資源和表單綁定,這里我們將 controller 中的 @product 和它綁定。form_for 會(huì)判斷 @product 是否為一個(gè)新的實(shí)例(你可以看看 @product.new_record?),從而將 form 的地址指向 create 還是 update 方法,這是符合我們之前提到的 REST 風(fēng)格。

當(dāng)然,大多數(shù)瀏覽器是不支持PUT,PATCHDELETE 方法的,瀏覽器在提交表單時(shí),只會(huì)是 GETPOST,這時(shí),form_tag 會(huì)創(chuàng)建一個(gè)隱藏空間,來(lái)告訴 Rails 這是一個(gè)什么動(dòng)作。而 form_for 會(huì)根據(jù)實(shí)例,來(lái)自動(dòng)判斷。

<input name="_method" type="hidden" value="patch" />

在我們顯示商品屬性的時(shí)候,用到了 f.text_field :name 這個(gè)輔助方法,這樣,我們不用再為每一個(gè) text_field 去聲明這是哪個(gè)實(shí)例了。f 是一個(gè)表單構(gòu)造器(Form Builder)實(shí)例,你可以在 這里 看到更多它的介紹。

我們可以自己定義 FormBuilder,以節(jié)省更多的代碼,也可以使用 simple form,formtastic 這種 Gem。推薦 ruby-toolbox.com 這個(gè)網(wǎng)站,你可以發(fā)現(xiàn)其他的好用的 Gem。

3.2.5 注冊(cè)和登錄

現(xiàn)在,我們實(shí)現(xiàn)一個(gè)很重要的功能,注冊(cè)和登錄。我們不需要從頭實(shí)現(xiàn)它,因?yàn)槲覀冇?Rails 十大必備 Gem 中的第一位:Devise 可以選擇。

Gemfile 中增加

gem 'devise'

bundle install 之后,我們需要?jiǎng)?chuàng)建配置文件:用戶(User)

% rails generate devise:install User
create  config/initializers/devise.rb
create  config/locales/devise.en.yml
 ===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. If you are deploying on Heroku with Rails 3.2 only, you may want to set:

       config.assets.initialize_on_precompile = false

     On config/application.rb forcing your application to not access the DB
     or load models when precompiling your assets.

  5. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

之后,我們創(chuàng)建用戶(User)模型:

% rails generate devise User
      invoke  active_record
      create    db/migrate/20150224071758_devise_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      insert    app/models/user.rb
       route  devise_for :users

之后,我們創(chuàng)建用戶(User)需要的 views

% rails g devise:views
      invoke  Devise::Generators::SharedViewsGenerator
      create    app/views/users/shared
      create    app/views/users/shared/_links.html.erb
      invoke  form_for
      create    app/views/users/confirmations
      create    app/views/users/confirmations/new.html.erb
      create    app/views/users/passwords
      create    app/views/users/passwords/edit.html.erb
      create    app/views/users/passwords/new.html.erb
      create    app/views/users/registrations
      create    app/views/users/registrations/edit.html.erb
      create    app/views/users/registrations/new.html.erb
      create    app/views/users/sessions
      create    app/views/users/sessions/new.html.erb
      create    app/views/users/unlocks
      create    app/views/users/unlocks/new.html.erb
      invoke  erb
      create    app/views/users/mailer
      create    app/views/users/mailer/confirmation_instructions.html.erb
      create    app/views/users/mailer/reset_password_instructions.html.erb
      create    app/views/users/mailer/unlock_instructions.html.erb

最后,更新 db:

rake db:migrate

在使用注冊(cè)登錄功能前,我們修改一下布局頁(yè)面,增加幾個(gè)鏈接:

<% if user_signed_in? %>
  <li><%= link_to current_user.email, profile_path %></li>
  <li><%= link_to "退出", destroy_user_session_path, method: :delete %></li>
<% else %>
  <li><%= link_to "登錄", new_user_session_path %></li>
  <li><%= link_to "注冊(cè)", new_user_registration_path %></li>
<% end %>

現(xiàn)在,我們可以使用注冊(cè)登錄功能了,是不是很簡(jiǎn)單呢?

接下來(lái),我們對(duì) Devise 創(chuàng)建的頁(yè)面做一點(diǎn)修改,同時(shí)看看 Rails 如何實(shí)現(xiàn)表單的。

我們登錄界面在 app/views/users/sessions/new.html.erb,我們把它改一下,符合我們頁(yè)面風(fēng)格,具體如何使用 html 代碼,可以參考 http://bootswatch.com/simplex/。

本章的代碼在 這里,希望可以幫助大家理解表單和其使用。