以多部分形式将空文本字段作为空字符串(不为空)提交

Submitting an empty text field as an empty string, not null, in a multipart form

这发生在我的 Rails 应用程序中,但我不确定这是否是 Rails 的问题,或者我是否误解了多部分表单应该如何工作。

这是(类似的)我的表格:

<%= form_for @user do |f| %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>

User#name 有一个存在验证。如果我访问 users/1/edit,清空 'name' 文本字段的值,然后单击提交,则不会更新任何内容,因为存在验证失败。到目前为止,还不错。

但现在我已经为我的用户添加了一个 avatar 属性(使用回形针 gem 进行文件存储),因此我相应地更新了表单:

<%= form_for @user do |f| %>
  <%= f.text_field :name %>
  <%= f.file_field :avatar %>
  <%= f.submit %>
<% end %>

现在,如果我去编辑用户并为 name 提交空白值,验证不会失败。 User#name 保持之前的值,但更新似乎仍然成功(即我没有收到有关验证失败的错误消息,并且数据库中的 updated_at 时间戳已更新。)

仔细观察,似乎当我在表单中包含 file_field 时,提交空白文本字段时它会改变表单的行为(可能是由于 form_for 现在输出一个形式 enctype=-"multipart/form-data").

file_field 不存在时, 提交空白 name 会将这些参数发送到服务器:

{ "id" => 1, "user" => { "name: "" }

这会在控制器中产生类似 User.find(1).update_attributes(name: "") 的结果,这当然无法更新,因为 Rails 看到我们正在尝试将 'name' 更新为空字符串,并且验证失败。

存在时,提交:

{ "id" => 1, "user" => { }(加上关于头像文件的额外信息)

"name" 键根本不存在,所以控制器运行 User.find(1).update_attributes() 这当然通过了,因为没有更新可能无法通过验证。

这是错误还是功能?为什么将 enctype 更改为 multipart(假设这是问题的根源)会改变空白文本字段的行为方式? (我已经在 Chrome 和 FF 中对此进行了测试,fwiw。)如果这确实是预期的行为,我如何才能确保正确提交空白文本字段而不必在每个文本周围添加一堆乏味的样板字段?

(如果重要的话,我正在使用:Ruby 2.3.0,Rails 5.0.0.beta3,Paperclip 5.0.0.beta1,我已经在 Chrome 49 和 Firefox 45)

我认为你可以做类似的事情

updated_user = User.new(your_params) # The new attributes is set to a new object record    
target_user = User.find(params[:id]) # the user you want to update
target_user = updated_user

    if target_user.save?
    ..
    else
    .. 

由此将触发所有验证并且活动记录将具有所有新属性,如果名称为空,它将捕获它

以下强参数方法不会带回丢弃的 :name 参数,但它应该可以防止表单模仿成功提交:

private
  def user_params
    params.require(:user).permit(:name, :avatar)
  end

这可以作为私有方法插入到您的用户控制器下。然后只需在您的 Update 方法中调用 user_params。

我有同样的问题,更新 Rails 到最新版本修复了它。