Reset zagnieżdżonych formularzy w przypadku błędu walidacji

Witam!
mam problem (miejmy nadzieje, że bardzo prosty do okiełznania) z fields_for. Chodzi o to, że w wypadku zaistnienia błędu w walidacji, formularz zagnieżdżony resetuje swoje wartości do tych sprzed kliknięcia przycisku “Save”.

Jako przykład przygotowałem prostą aplikację, której kod dostępny jest tutaj: https://github.com/mbajur/wicked-form-reset-example (instrukcja obsługi w readme). Dla ułatwienia, poniżej znajdują się podstawowe elementy tej aplikacji:

users_controller.rb

class UsersController < ActionController::Base
  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])

    respond_to do |format|
      if @user.update_attributes(params["user"])
        format.html { redirect_to edit_user_path(@user), notice: 'User saved.' }
      else
        format.html { render action: :edit }
      end
    end
  end
end

users/edit.html.erb

<%= form_for @user do |f| %>

  <% # ..... %>

  <h3>Assets</h3>

    <%= f.fields_for :assets, f.object.assets.first_type do |ff| %>
    <%= ff.hidden_field :asset_type %>
    <%= ff.label :value, 'Asset value:' %>
    <br>
    <%= ff.text_field :value %>
  <% end %>

  <% # ..... %>

  <hr>

  <%= f.submit %>

<% end %>

Z góry dzięki za pomoc : )

Na pewno jedną z przyczyn jest to, że używasz scope w tym miejscu f.fields_for :assets, f.object.assets.first_type. Zobacz w logach, przy renderowaniu widoku najprawdopodobniej assetsy są tworzone na nowo. Zamiast scope użyj metody klasy.

Mógł byś to rozwinąć? Próbowałem już tylu sposobów, że kiedy czytam takie zdanie, to na myśl przychodzi mi conajmniej 5 rozwiązań (z których, jak dotąd żadne mi nie zadziałało) : )

zrobiłem PR

1 Like

Wow, super! Ogromne dzięki! : ) Tylko mam jeszcze jeden problem w związku z tym tematem. Cały szum kręci się wokół tego, iż tworzę stronę z ogromnym formularzem. Wypełnienie go zajmuje użytkownikowi średnio godzinę. Wykorzystuje przy nim gema nested_form. Problem aktualnie polega na tym, że jeśli użytkownik popełni jakiś błąd, to cały formularz zostaje zresetowany do pierwotnej wersji czyli jeśli jest on wypełniany pierwszy raz, to w wypadku błędnego wypełnienia jakiegoś pola wszystko zostaje skasowane.

Z początku myślałem, że jeśli uporam się z problemem z mojego pierwszego posta, to wszelakie rozwiązania do obsługi dynamicznych nested_fields również zadziałają ale niestety nic z tego. Masz (/macie) może jakiś pomysł jak to rozwiązać i czy to w ogóle możliwe? Jedyne co przychodzi mi do głowy jako “pewniak” to walidacja w jquery ale wolał bym zrobić to porządnie już od podstaw.

ps. analogiczne pytanie zadałem kiedyś na stackoverflow, więc jeśli masz tam konto @sledzias, to zapraszam do odpowiedzi: http://stackoverflow.com/questions/19491291/fields-for-reset-on-validation-error

ps2. Zaktualizowałem repo z pierwszego posta, dodałem nested_form.

@mbajur zrezygnuj z zagnieżdżonych formularzy. Zrób osobną klasę dla formularza wykorzystującą ActiveModel. Logika niewiele się rozrośnie, ale za to będziesz miał pełną kontrole nad wysyłanymi i przekazywanymi danymi.

Ok. Udało mi się rozwiązać problem. Prawdopodobnie mój sposób jest dosyć niepoprawny ale przynajmniej działa a klient jest szczęśliwy. Commit: https://github.com/mbajur/wicked-form-reset-example/commit/39ae40d897ea5e581bfc5b6c09300e6fe51edd32

W skrócie

stworzyłem sobie asocjacje dla każdego typu assets

# app/models/user.rb
has_many :assets_first_type, class_name: 'Asset', conditions: { asset_type: 1 }
has_many :assets_second_type, class_name: 'Asset', conditions: { asset_type: 2 }
has_many :assets_third_type, class_name: 'Asset', conditions: { asset_type: 3 }

I wykorzystałem je w formularzu

= f.fields_for :assets_first_type do |ff|
  = ff.label :value, 'Asset value:'
  br
  = ff.text_field :value

p= f.link_to_add "Add asset of type 1", :assets_first_type

@wafcio nie ukrywam, że sposób, który opisałeś jest mi kompletnie obcy ale poczytam o tym :wink: