验证失败后,表单不会保留局部变量

时间:2017-03-20 22:20:08

标签: ruby-on-rails jsonb

我有一个Form,其中包含一个Hashes数组的迭代:

<% @user.profile["addresses"].each_with_index do |(k,v), i| %>
    <%= render partial: 'users/form/addresses_fields', locals: { f: f, i: i } %>
<% end %>

请注意,我没有传递k和v通过locals因为我正在使用表单助手标记,而我只需要使用索引,例如:

<%= label_tag "user[profile][addresses]["+i.to_s+"][street]", "Street" %>
<%= text_field_tag "user[profile][addresses]["+i.to_s+"][street]" %>

提交后,只要验证失败,并且控制器重新呈现视图,我就会Name Error显示undefined local variable or method 'i' for #<#<Class:0x007fc53e26b690>:0x007fc53f5ba688>

这是否意味着在验证失败后重新呈现视图时Rails没有考虑嵌入或本地定义的变量?

我也尝试在视图中定义变量,如<% i = 0 %>,然后在每次迭代时递增,当然问题仍然存在,因为现在我确定问题是什么。

其他注意事项:用户填写的每个字段在验证失败时保留完全正常,问题在于局部变量,在这种情况下,是each_with_index的索引

如何解决此问题? user.profile是一个JSONB数据类型列。

我确信这是一个常见的问题,因为现在越来越多的人使用JSON和JSONB数据类型列来处理模型的嵌套属性,而不必构建其他几个模型。

  

其他相关代码:

控制器:

def update
  if @user.custom_update_attributes(user_params)
    flash[:success] = "Updated!"
    redirect_to current_user
  else
    render 'edit'
  end
end

模型方法:

def custom_update_attributes(params)
    name = params["profile"]["name"]
    gender = params["profile"]["gender"]
    birthday = params["profile"]["birthday"]
    phone = params["profile"]["phone"]
    addresses = params["profile"]["addresses"]

    self.profile["name"] = name
    self.profile["gender"] = gender
    self.profile["birthday"] = birthday
    self.profile["phone"] = phone

    #addresses
    updated_addresses = {}
    i = 0
    unless addresses.blank?
      addresses.each do |key, val|
        if val["_destroy"] == "1"
          #pass
        else
          #add
          updated_addresses[i] = val.except("_destroy")
          i = i + 1
        end
      end
    end
    self.profile["addresses"] = updated_addresses

    self.profile_will_change!
    self.save
  end
  

我想我发现使用BYEBUG gem发生了什么:

失败的代码行如下:

<%= text_field_tag "user[profile][addresses]["+i.to_s+"][street]", @user.profile["addresses"][i.to_s]["street"] %>

当页面最初加载表单时,该行代码完全正常。但是,如果验证失败,来自[i.to_s]的{​​{1}}未定义,如果我将其更改为@user.profile["addresses"][i.to_s]["street"]而未将其转换为字符串,则具有验证错误的页面加载完全正常!

我认为这只是Rails如何处理哈希数组的一个问题,因为最初它将数组的每个索引都视为子哈希的关键,然后当验证失败时,它将每个索引视为索引号数组,而不是一个键(不是一个字符串)。怪异。

1 个答案:

答案 0 :(得分:0)

要解决这个问题,我只是在任何表单输入之前添加了以下内容:

<% if @user.profile["addresses"][i.to_s] != nil %>
  <% i = i.to_s %>
<% else %>
  <% i = i %>
<% end %>