【问题标题】:Submitting an empty text field as an empty string, not null, in a multipart form以多部分形式将空文本字段作为空字符串提交,而不是 null
【发布时间】:2016-07-29 20:13:30
【问题描述】:

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

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

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

User#name 具有存在验证。如果我访问users/1/edit,清空“名称”文本字段的值,然后单击提交,没有任何更新,因为存在验证失败。到目前为止,一切顺利。

但现在我已经为我的用户添加了一个 avatar 属性(使用 Paperclip 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" =&gt; 1, "user" =&gt; { "name: "" }

这会导致控制器中出现User.find(1).update_attributes(name: "") 之类的内容,这当然无法更新,因为 Rails 看到我们正在尝试将 'name' 更新为空白字符串并且验证失败。

当它存在时,它会被提交:

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

“名称”键根本不存在,因此控制器运行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 中进行了测试)

【问题讨论】:

  • 奇怪,我无法重现您描述的行为。在我的情况下(尽管是 Rails 4.2),无论表单编码类型如何,空白名称总是作为空字符串发送:"name" =&gt; ""。也许您可以在 Rails 4 上尝试相同的代码,以发现 Rails 5 的行为变化(甚至是错误)?
  • 另外,请参阅我认为需要的my edit,以便问题真正有意义,如果我误解了你,请回复它。
  • 是的,您的编辑是正确的。感谢您发现我的错误。

标签: html ruby-on-rails forms multipartform-data enctype


【解决方案1】:

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

【讨论】:

  • 是的,我使用的是 Rails 5.0.0 的 beta 版本之一。升级到 RC 似乎解决了它。
【解决方案2】:

以下强参数方法不会带回已删除的 :name 参数,但应防止表单模仿成功提交:

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

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

【讨论】:

  • 这不能回答我的问题。我已经有一个用于强参数的_params 方法。
【解决方案3】:

我认为你可以这样做

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
    .. 

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

【讨论】:

  • 不起作用。您的前三行在功能上等同于target_user = User.new(your_params),它将创建一个新用户,而不是更新现有用户 - 问题不在于User 无法捕获空白名称,问题在于params[:user][:name] 是空白的首先(不存在密钥:name)。
  • 是的,现在我明白了,听起来很奇怪,您是否尝试过像carrierwave 之类的其他宝石并且发生了相同的行为?
猜你喜欢
  • 1970-01-01
  • 2021-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-07
  • 2011-08-04
  • 1970-01-01
相关资源
最近更新 更多