У меня есть форма, которая содержит итерацию по массиву хэшей:
<% @user.profile["addresses"].each_with_index do |(k,v), i| %>
<%= render partial: 'users/form/addresses_fields', locals: { f: f, i: i } %>
<% end %>
Обратите внимание, что я не передаю 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 %>
, а затем увеличивать их с каждой итерацией, и проблема, конечно, сохраняется, так как теперь я уверен, в чем проблема.
Другие соображения: каждое поле, которое заполняет пользователь, остается идеально корректным после сбоя проверки, проблема связана с локальными переменными, в данном случае индексом 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:
Строка кода, которая не работает, выглядит следующим образом:
<%= text_field_tag "user[profile][addresses]["+i.to_s+"][street]", @user.profile["addresses"][i.to_s]["street"] %>
Когда страница изначально загружает форму, эта строка кода работает отлично. Но если проверка не пройдена, [i.to_s]
из @user.profile["addresses"][i.to_s]["street"]
становится неопределенным, и если я изменю его на [i]
без преобразования в строку, страница с ошибками проверки загрузится отлично!
Я думаю, что это просто проблема с тем, как Rails обрабатывает массив хэшей, потому что сначала он рассматривает каждый индекс массива как ключ подхэша, а затем, когда проверка не проходит, он рассматривает каждый индекс как номер индекса массива. , больше не ключ (не строка). Странный.