Rails表单:从基础开始教程

258 阅读5分钟

要求

使用的工具:Rails 6.1.3, Ruby 3

什么是表单?

网络表单不是Rails的概念,表单是一种向服务器发送数据的方式。有许多其他的方式来实现这一点,但使用<form> 标签意味着使用标准的方式来发送数据。它意味着出色的设备支持、出色的可访问性、浏览器支持等等。

这很有效。没有Rails。不需要任何JavaScript。浏览器本身就能够向一个(其他)URL提交数据。

那么,为什么还需要Rails呢?

乍一看,我们不需要Rails来向服务器发送任何数据。

但是,为了避免多余的、容易出错的复制/粘贴,Rails自带的帮助器会自动生成上述表单,再加上.NET技术,就可以把数据发送到服务器。

  • 为了安全起见,还要加上 authenticity_token。
  • 一致的类和ID。
  • 一致的 "名称 "标签
  • 一旦按下提交按钮,就可以禁用它(通过名为Rails-ujs的JavaScript库)。
  • 其他好东西。

Rails有一些帮助工具来构建表单。

  • form_for (softly deprecated)
  • form_tag (已被弃用)
  • form_with (新标准)

你可能会在旧的 gem 或 Rails 项目中遇到form_forform_tag,但form_with现在是新的标准。因此,对于任何新项目,你唯一需要关心的助手就是form_with

现在让我们看看Rails是如何处理上面这个简单的表单的。

<# This is what you write in your Rails template file #>  
  <%= form_with scope: "book", url: "/books" do |form| %>  
  <%= form.text_field :title %>  
  <%= form.submit "Create" %>  
<% end %>  
  
<# This is the generated HTML you can view in your browser #>  
<form class="new_book" id="new_book" action="/books" method="post">  
  <input name="utf8" type="hidden" value="✓">  
  <input type="hidden" name="authenticity_token" value="…">  
  <input type="text" name="book[title]" id="book_title">  
  <input type="submit" name="commit" value="Create" data-disable-with="Create">  
</form>  

从这里你可以注意到。

  • Rails "强制 "使用标准的utf8编码,以便在服务器端正确解码你的表单字段。
  • 默认使用的REST方法是POST,(表单标签中的属性method="post" )。
  • 为了安全起见,有一个隐藏的认证令牌字段。
  • 文本字段的 "name "和 "id "已经为你写好了。
  • 提交字段有一个名字("commit"),以便处理有多个提交按钮的情况。
  • 提交字段已经有一个 "data-disable-with",它将被Rails-ujs使用,一旦按下提交按钮就会失效。
  • 避免多次提交是必要的,想想你的客户按了 "pay "按钮的情况,这个用户可能不想多次付款......

在没有Rails助手的情况下使用表单是很乏味和危险的

教程从头开始

$> rails new myform --minimal  
$> cd myform  

在app/controllers/welcome_controller.rb内部

class WelcomeController < ApplicationController  
  
# welcome_path GET /welcome  
# root_path GET /  
def index  
end  
  
# update_book_path POST /welcome/update_book  
def update_book  
end  
  
end  
  

在app/views/welcome/index.html.erb里面

<h1>Welcome ! This is a tutorial about Rails forms</h1>  
  
<%= form_with scope: "book", url: update_book_path, method: :put do |form| %>  
  <%= form.text_field :title %>  
  <%= form.submit "Create" %>  
<% end %>  

在config/routes.rb里面

Rails.application.routes.draw do  
  get "/welcome", to: "welcome#index"  
  put "/welcome/update_book", to: "welcome#update_book", as: 'update_book'  
    
  root "welcome#index"  
end  

现在运行

$> bin/rails server  

并打开你的浏览器,http://localhost:3000

Rendered form

渲染的表单

当你在Rails环境中处理表单时,我建议总是打开Chrome开发工具控制台,以查看DOM树中发生的事情。

也许你会看到一些惊喜。在这里,我们可以看到的是 。

  • 与本教程的第一部分相比,这个Rails版本以另一种方式处理UTF8。我不知道这是否与Rails或Rails-ujs版本有关,但注意到这一点是有点好笑的。对于开发者来说,这并没有改变什么,但同样,在没有Rails助手的情况下管理表单是一种负担。

  • 请注意app/views/welcome/index.html.erb 里面的method: :put 。为了配合routes.rb 里面的VERB。最后,这个put 方法是在表单的一个隐藏字段里面。可能是因为大多数浏览器只知道GET数据和POST数据,但无法使用其他动词,如DELETE或PUT或PATCH。

  • 其他一切行为都如上所述。

向服务器发送数据

在Chrome开发工具中,打开网络标签。然后,在表单里面输入任何书的名字,并点击按钮提交表单。

Chrome devtools form submit

Chrome开发工具的表单提交

我们可以看到,有4个参数被发送到了服务器:_method, authenticity_token, book[title], commit

现在打开你的终端。

Terminal parameters

终端参数

只有3个参数,_method已经消失了,因为Rails用它来计算哪个控制器的方法是目标。

所以Rails已经为我们调用了正确的方法:WelcomeController#update_book。

在 "params "对象中传递3个参数(可以被控制器的任何方法使用)。

  • authenticity_token (我从来没有用过这种情况)
  • commit (如果我们有多个提交按钮,但这不是我们的情况)
  • book (有用的有效载荷)

用默认值预先填入表单

用 "Rails方式 "来预填充表单的值是使用一个Model,它是一个与数据库混合的对象。

如果你已经有一些编码经验,这听起来是错误的。事实上,许多教程并不建议这样做。相反,你可以使用一个普通的Model,没有映射到数据库,名为 "表单对象"。我很快会就这个问题单独写一篇博客文章,因为这个教程已经够厚了:)

现在你只需要知道,在Rails中这样做是可能的,而且它为Rails表单带来了更大的魔力(即更短的代码)。

解压缩发送的数据

在app/controllers/welcome_controller.rb里面。

class WelcomeController < ApplicationController  
  
# welcome_path GET /welcome  
# root_path GET /  
def index  
end  
  
# update_book_path POST /welcome/update_book  
def update_book  
p ''  
p '--- extracted params are ---'  
p book_params # will output {"title" => "gatsby"}  
p ''  
end  
  
def book_params  
params.require(:book).permit(:title).to_h  
end  
  
end  

现在把 "gatsby "放到表单中,然后提交按钮。

下面是控制台中打印的内容。

Unpacked form

解压后的表单

正如你所看到的,这次并没有什么神奇的地方。更糟的是,你必须处理 "强参数",这是为了安全起见,但却很烦人,因为它们增加了很多冗长的语言。

结论

  • 虽然 "web表单 "是一个众所周知的、古老的、成熟的web标准,与Rails无关,但在Rails环境中不建议在没有任何辅助工具的情况下使用它。视图和控制器一起工作以确保安全、编码和路由。

  • "form_with "是新的统一标准。"form_tag "和 "form_for "已被废弃--但出于兼容性的考虑而保留。

  • Rails根据 "scope: "键自动映射字段名,另一种方法是用 "model: "键注入一个 "表单对象",我们将在后面看到如何操作。

  • 另一种方法没有什么神奇之处:一旦表单被提交,在处理提交的数据之前,你必须在控制器中逐一提取、授权和读取参数。