Rails accetta_nested_attributes_for con f.fields_for e AJAX

Sono curioso di sapere come usare correttamente_nonesto_attributi_for e f.fields_for .

views / ordini / new.html.erb

      

Details

views / Order_Details / _details.html.erb

        $$$    →  | length:  | width:  | height:  | weight:   

controller / orders_controller.rb (sono abbastanza sicuro che questo sia sbagliato … qualsiasi aiuto qui sarebbe molto apprezzato)

 def create @order = Order.create(params[:order]) if @order.save flash[:success] = "Order #{@order.invoice} added!" redirect_to current_user else render 'orders/new' end end 

modelli / order.rb

 class Order < ActiveRecord::Base attr_accessible ..., :order_details_attributes has_many :order_details accepts_nested_attributes_for :order_details end 

L’unico modo in cui sono riuscito a rendere piacevole il partial è se in realtà chiamo fields_for come fields_for Order.new.order_details.build . Ma questo non crea affatto l’object nidificato. Devo usare f.fields_for nomenclature per creare l’ordine e OrderDetail. Posso solo costruirne uno, però. Qual è il mio prossimo numero.

Guarda come ci sono i pulsanti lì dentro? AJAXs rema nel modulo. Se fai clic su add line , ottengo

 NameError in Order_details#new Showing D:/Dropbox/Apps/rails_projects/erbv2/app/views/order_details/new.js.erb where line #3 raised: undefined local variable or method `f' for #<#:0x5cbd718> 

views / ordini / add_detail.js.erb

 $('#order_form tr.total').before("") 

Non so come definire f … Ho controllato Rails AJAX: Il mio partial ha bisogno di un’istanza di FormBuilder e pochi altri.

Qualche suggerimento su come dovrei gestirlo? Usando il codice che ho qui … sono stato in grado di creare un nuovo ordine, con un relativo order_details, ma il box_id non ha salvato, e il company_id non ha salvato. So che è un po ‘brutto, ma non so dove altro andare.

AGGIORNARE

itinerari:

 resources :orders do collection { get :add_detail } end this is way better than having a separate resource for the details. I didn't think of this before! 

Modulo HTML:

  f. ...  #first child  #add subsequent children  

Controller degli ordini:

 def add_detail @order = Order.build @boxes = Company.find(params[:company_id]).boxes @b = @boxes.first @ci = Time.now.to_i respond_with(@order, @boxes, @b, @ci) end 

_dettagli parziale

        $$$   

È ansible

C’è un tutorial molto, molto buono su questo qui: http://pikender.in/2013/04/20/child-forms-using-fields_for-through-ajax-rails-way/

Abbiamo recentemente implementato questo tipo di modulo su una delle nostre app di sviluppo. Se vai a goto e http://emailsystem.herokuapp.com , registrati (gratis) e fai clic su “Nuovo messaggio”. La parte “Sottoscrittori” utilizza questa tecnologia

A proposito, l’abbiamo fatto manualmente. Cocoon sembra davvero molto bello e sembra utilizzare gli stessi principi di noi. C’è anche un RailsCast , ma funziona solo per aggiunte singole (credo)


f.fields_for

Il modo in cui lo fai è usare una serie di partial che generano dynamicmente i campi di cui hai bisogno. Dal tuo codice sembra che tu abbia le basi in atto (il modulo funziona), quindi ora è il caso di build diversi componenti per gestire la richiesta AJAX:

  1. È necessario gestire AJAX sul controller (rotta + azione del controller)
  2. Devi mettere i tuoi file f.fields_for in partial (in modo che possano essere chiamati con Ajax)
  3. È necessario gestire la funzionalità di build nel modello

Gestire AJAX con il controller

In primo luogo, è necessario gestire le richieste Ajax nel controller

Per fare ciò, è necessario aggiungere un nuovo “endpoint” ai percorsi. Questo è nostro:

  resources :messages, :except => [:index, :destroy] do collection do get :add_subscriber end end 

L’azione del controller si traduce quindi in:

 #app/controllers/messages_controller.rb #Ajax Add Subscriber def add_subscriber @message = Message.build render "add_subscriber", :layout => false end 

Aggiungi i tuoi f.fields_for Into f.fields_for

Per gestire questo, è necessario inserire f.fields_for in f.fields_for . Ecco il codice sotto forma del nostro modulo:

 #app/views/resources/_message_subscriber_fields.html.erb < %= f.fields_for :message_subscribers, :child_index => child_index do |subscriber| %> < %= subscriber.collection_select(:subscriber_id, Subscriber.where(:user_id => current_user.id), :id, :name_with_email, include_blank: 'Subscribers') %> < % end %> #app/views/messages/add_subscriber.html.erb < %= form_for @message, :url => messages_path, :authenticity_token => false do |f| %> < %= render :partial => "resources/message_subscriber_fields", locals: {f: f, child_index: Time.now.to_i} %> < % end %> #app/views/messages/new.html.erb < % child_index = Time.now.to_i %> 
Subscribers
< %= render :partial => "message_subscriber_fields", locals: {f: f, child_index: child_index } %>

Estendi la tua funzionalità di costruzione al tuo modello

Per mantenere le cose asciutte, abbiamo appena creato una funzione di build nel modello, che possiamo chiamare ogni volta:

  #Build def self.build message = self.new message.message_subscribers.build message end 

CHILD_INDEX

Il tuo migliore amico qui è child_index

Se stai aggiungendo più campi, il grosso problema che avrai sarà quello di incrementare [id] del campo (questo era il difetto che abbiamo trovato con il tutorial di Ryan Bates)

Il modo in cui il primo tutorial che ho pubblicato ha risolto questo problema era impostare semplicemente child_index dei nuovi campi con Time.now.to_i . Questo imposta un ID univoco e poiché l’effettivo ID del nuovo campo è irrilevante, sarai in grado di aggiungere tutti i campi che vuoi


JQuery

  #Add Subscriber $ -> $(document).on "click", "#add_subscriber", (e) -> e.preventDefault(); #Ajax $.ajax url: '/messages/add_subscriber' success: (data) -> el_to_add = $(data).html() $('#subscribers').append(el_to_add) error: (data) -> alert "Sorry, There Was An Error!"