Il mio problema è che ho incontrato limitazioni di accept_nested_attributes_for, quindi ho bisogno di capire come replicare questa funzionalità da solo per avere maggiore flessibilità. (Vedi sotto per esattamente cosa mi sta impiccando.) Quindi la mia domanda è: quale dovrebbe essere il mio modulo, controller e modelli se voglio mimmic e augment accept_nested_attributes_for? Il vero trucco è che devo essere in grado di aggiornare sia i nuovi modelli esistenti che quelli esistenti con associazioni/attributi.Rails - Come gestire gli attributi nidificati senza utilizzare accept_nested_attributes_for?
Sto costruendo un'app che utilizza moduli annidati. Inizialmente ho usato questo RailsCast come progetto (sfruttando accept_nested_attributes_for): Railscast 196: Nested Model Form.
La mia app è liste di controllo con lavori (attività), e sto permettendo all'utente di aggiornare la lista di controllo (nome, descrizione) e aggiungere/rimuovere lavori associati in un unico modulo. Funziona bene, ma mi imbatto in problemi quando lo incorporo in un altro aspetto della mia app: la cronologia tramite il controllo delle versioni.
Gran parte della mia app è che ho bisogno di registrare informazioni storiche per i miei modelli e associazioni. Ho finito con il mio sistema di versioning (here è la mia domanda in cui descrivo il mio processo/considerazioni decisionali), e gran parte di questo è un flusso di lavoro in cui ho bisogno di creare una nuova versione di una cosa vecchia, apportare aggiornamenti alla nuova versione , archivia la vecchia versione. Questo è invisibile all'utente, che vede l'esperienza semplicemente aggiornando un modello attraverso l'interfaccia utente.
Code - modelli
#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
Codice - forma attuale (NOTA: @jobs è definito come i lavori non archiviati per questa lista di controllo nel regolatore liste di controllo Modifica azione, così è @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 %>
Codice: snippet from checklists_controller.rb # Aggiornamento
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])
E questo è dove corro nto il accept_nested_attributes_for limitation (è documentato abbastanza bene here. Ottengo l'eccezione "Impossibile trovare Model1 con ID = X per Model2 con ID = Y", che è fondamentalmente come progettato.
Quindi, come posso creare più modelli nidificati e aggiungerli/rimuoverli sul modulo del modello principale in modo simile a ciò che accetta_nested_attributes_for fa, ma da solo?
Le opzioni che ho visto sono tra le migliori? Il vero trucco è che devo essere in grado di aggiornare sia i nuovi modelli esistenti che quelli esistenti con associazioni/attributi. Non riesco a collegarli, quindi li chiamerò semplicemente.
Redtape (su GitHub) Virtus (anche github)
Grazie per il vostro aiuto!
Se l'hai risolto sarei molto interessato a vedere la tua soluzione. –
Mario, l'ho risolto e ho pubblicato il mio codice qui sotto. Non è un grande codice, ma se stai lottando con qualcosa di simile, forse ti darà qualche idea. Qualsiasi domanda, basta commentare qui o sulla mia risposta e cercherò di chiarire se posso. – JoshDoody