验证失败后表单不会保留局部变量
Form won't retain local variables after validation fails
我有一个表单,其中包含对哈希数组的迭代:
<% @user.profile["addresses"].each_with_index do |(k,v), i| %>
<%= render partial: 'users/form/addresses_fields', locals: { f: f, i: i } %>
<% end %>
请注意,我没有通过 locals 传递 k 和 v,因为我使用的是表单辅助标签,我只需要使用索引,例如:
<%= 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 %>
然后随着每次迭代递增,当然问题仍然存在,因为现在我确定问题出在哪里。
其他注意事项:用户填写的每个字段在验证失败时都保持完全正常,问题出在局部变量上,在这种情况下,[=18 的索引=]
如何解决这个问题? user.profile
是 JSONB 数据类型列。
我确信这是或将成为一个常见问题,因为现在越来越多的人使用 JSON 和 JSONB 数据类型列来处理模型的嵌套属性,而无需构建其他几个型号。
Other relevant code:
控制器:
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
I think I found what's happening using BYEBUG gem:
失败的代码行如下:
<%= text_field_tag "user[profile][addresses]["+i.to_s+"][street]", @user.profile["addresses"][i.to_s]["street"] %>
当页面最初加载表单时,该行代码运行良好。但是,如果验证失败,@user.profile["addresses"][i.to_s]["street"]
中的 [i.to_s]
将变得未定义,如果我将其更改为 [i]
而不将其转换为字符串,则包含验证错误的页面可以完美加载!
我认为这只是Rails处理哈希数组的方式有问题,因为它首先将数组的每个索引视为子哈希的键,然后当验证失败时,它考虑每个索引作为数组的索引号,不再是键(不是字符串)。奇怪。
为了解决这个问题,我只是在任何表单输入之前添加了以下内容:
<% if @user.profile["addresses"][i.to_s] != nil %>
<% i = i.to_s %>
<% else %>
<% i = i %>
<% end %>
我有一个表单,其中包含对哈希数组的迭代:
<% @user.profile["addresses"].each_with_index do |(k,v), i| %>
<%= render partial: 'users/form/addresses_fields', locals: { f: f, i: i } %>
<% end %>
请注意,我没有通过 locals 传递 k 和 v,因为我使用的是表单辅助标签,我只需要使用索引,例如:
<%= 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 %>
然后随着每次迭代递增,当然问题仍然存在,因为现在我确定问题出在哪里。
其他注意事项:用户填写的每个字段在验证失败时都保持完全正常,问题出在局部变量上,在这种情况下,[=18 的索引=]
如何解决这个问题? user.profile
是 JSONB 数据类型列。
我确信这是或将成为一个常见问题,因为现在越来越多的人使用 JSON 和 JSONB 数据类型列来处理模型的嵌套属性,而无需构建其他几个型号。
Other relevant code:
控制器:
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
I think I found what's happening using BYEBUG gem:
失败的代码行如下:
<%= text_field_tag "user[profile][addresses]["+i.to_s+"][street]", @user.profile["addresses"][i.to_s]["street"] %>
当页面最初加载表单时,该行代码运行良好。但是,如果验证失败,@user.profile["addresses"][i.to_s]["street"]
中的 [i.to_s]
将变得未定义,如果我将其更改为 [i]
而不将其转换为字符串,则包含验证错误的页面可以完美加载!
我认为这只是Rails处理哈希数组的方式有问题,因为它首先将数组的每个索引视为子哈希的键,然后当验证失败时,它考虑每个索引作为数组的索引号,不再是键(不是字符串)。奇怪。
为了解决这个问题,我只是在任何表单输入之前添加了以下内容:
<% if @user.profile["addresses"][i.to_s] != nil %>
<% i = i.to_s %>
<% else %>
<% i = i %>
<% end %>