Mój problem polega na tym, że napotkaliśmy ograniczenia dotyczące accepts_nested_attributes_for, więc muszę wymyślić, jak samodzielnie powielić tę funkcję, aby uzyskać większą elastyczność. (Zobacz poniżej, co dokładnie mnie zawiesza.) Moje pytanie brzmi: Jak powinna wyglądać moja forma, kontroler i modele, jeśli chcę je usprawniać i zwiększać accepts_nested_attributes_for? Prawdziwą sztuczką jest to, że muszę mieć możliwość aktualizacji zarówno istniejących, jak i nowych modeli, z istniejącymi powiązaniami/atrybutami.Railsy - Jak zarządzać zagnieżdżonymi atrybutami bez użycia accepts_nested_attributes_for?
Buduję aplikację korzystającą z zagnieżdżonych formularzy. Początkowo użyłem tego RailsCast jako wzorca (leveraging accepts_nested_attributes_for): Railscast 196: Nested Model Form.
Moja aplikacja to listy kontrolne zawierające zadania (zadania) i pozwalam użytkownikowi zaktualizować listę kontrolną (nazwisko, opis) oraz dodać/usunąć powiązane zadania w jednym formularzu. Działa to dobrze, ale napotykam problemy, gdy włączam to do innego aspektu mojej aplikacji: historii poprzez wersjonowanie.
Duża część mojej aplikacji polega na tym, że muszę zapisywać informacje historyczne dotyczące moich modeli i skojarzeń. Zakończyłem przetasowanie własnej wersji (here to moje pytanie, w którym opisuję mój proces decyzyjny/rozważania), a duża część to przepływ pracy, w którym muszę utworzyć nową wersję starej rzeczy, wprowadzać aktualizacje do nowej wersji , zarchiwizuj starą wersję. Jest to niewidoczne dla użytkownika, który postrzega to doświadczenie jako proste aktualizowanie modelu za pomocą interfejsu użytkownika.
Code - modele
#checklist.rb
class Checklist < ActiveRecord::Base
has_many :jobs, :through => :checklists_jobs
accepts_nested_attributes_for :jobs, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
end
#job.rb
class Job < ActiveRecord::Base
has_many :checklists, :through => :checklists_jobs
end
Code - aktualna forma (UWAGA: @jobs jest zdefiniowany jako niezarchiwizowane pracy dla tej listy kontrolnej w edycji akcji kontrolera listy kontrolne, tak jest @checklist)
<%= simple_form_for @checklist, :html => { :class => 'form-inline' } do |f| %>
<fieldset>
<legend><%= controller.action_name.capitalize %> Checklist</legend><br>
<%= f.input :name, :input_html => { :rows => 1 }, :placeholder => 'Name the Checklist...', :class => 'autoresizer' %>
<%= f.input :description, :input_html => { :rows => 3 }, :placeholder => 'Optional description...', :class => 'autoresizer' %>
<legend>Jobs on this Checklist - [Name] [Description]</legend>
<%= f.fields_for :jobs, @jobs, :html => { :class => 'form-inline' } do |j| %>
<%= render "job_fields_disabled", :j => j %>
<% end %>
</br>
<p><%= link_to_add_fields "+", f, :jobs %></p>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to 'Cancel', checklists_path, :class => 'btn' %>
</div>
</fieldset>
<% end %>
Code - snippet from checklists_controller.rb # Aktualizacja
def update
@oldChecklist = Checklist.find(params[:id])
# Do some checks to determine if we need to do the new copy/archive stuff
@newChecklist = @oldChecklist.dup
@newChecklist.parent_id = (@oldChecklist.parent_id == 0) ? @oldChecklist.id : @oldChecklist.parent_id
@newChecklist.predecessor_id = @oldChecklist.id
@newChecklist.version = (@oldChecklist.version + 1)
@newChecklist.save
# Now I've got a new checklist that looks like the old one (with some updated versioning info).
# For the jobs associated with the old checklist, do some similar archiving and creating new versions IN THE JOIN TABLE
@oldChecklist.checklists_jobs.archived_state(:false).each do |u|
x = u.dup
x.checklist_id = @newChecklist.id
x.save
u.archive
u.save
end
# Now the new checklist's join table entries look like the old checklist's entries did
# BEFORE the form was submitted; but I want to update the NEW Checklist so it reflects
# the updates made in the form that was submitted.
# Part of the params[:checklist] has is "jobs_attributes", which is handled by
# accepts_nested_attributes_for. The problem is I can't really manipulate that hash very
# well, and I can't do a direct update with those attributes on my NEW model (as I'm
# trying in the next line) due to a built-in limitation.
@newChecklist.update_attributes(params[:checklist])
I tu właśnie biegnę nto accepts_nested_attributes_for ograniczenia (jest to dobrze udokumentowane here. Otrzymuję komunikat "Nie można znaleźć modelu 1 z identyfikatorem = X dla modelu 2 z ID = Y", który jest zasadniczo taki sam jak zaprojektowany.
Jak więc utworzyć wiele modeli zagnieżdżonych i dodać/usunąć je w formularzu modelu macierzystego, podobnego do tego, co akceptuje_nested_attributes_do, ale czy mogę to zrobić samodzielnie?
Opcje, które widziałem - są jednym z tych najlepszych? Prawdziwa sztuczka polega na tym, że muszę mieć możliwość aktualizacji zarówno istniejących, jak i nowych modeli z istniejącymi powiązaniami/atrybutami. Nie mogę ich połączyć, więc po prostu je nazwę.
Redtape (na github) Virtus (również github)
Dzięki za pomoc!
Jeśli to rozwiązałeś, byłbym bardzo zainteresowany obejrzeniem twojego rozwiązania. –
Mario, rozwiązałem to, a mój kod został opublikowany poniżej. To nie jest świetny kod, ale jeśli walczysz z czymś podobnym, może to da ci kilka pomysłów. Wszelkie pytania, po prostu komentarz tutaj lub na moją odpowiedź, a ja postaram się wyjaśnić, czy mogę. – JoshDoody