2015-10-07 10 views
7

के साथ गतिशील रूप से जोड़े गए (नेस्टेड) ​​फॉर्म फ़ील्ड्स में child_index जोड़ना अद्यतन: मैं कई मॉडलों को शामिल किए गए नेस्टेड फॉर्म में फॉर्म फ़ील्ड जोड़ने/निकालने का प्रयास कर रहा हूं। मैंने रायन बेट्स द्वारा "डायनामिक फॉर्म" रेलवेकास्ट देखा है और मैंने का उपयोग करके this article पर संदर्भित किया है। उस लेख के बाद बच्चे_इंडेक्स को छोड़कर सब कुछ पूरी तरह से काम कर चुका है। Child_index केवल पहले :kid इनपुट फ़ील्ड (:name) और पहले :pet इनपुट फ़ील्ड (:name और :age) पर मौजूद है। फिर यह जोड़े जाने वाले क्षेत्रों के लिए एक प्रामाणिकता टोकन पर वापस चला जाता है।रेल 4: कोकून जेम

मैंने सभी जेएस और सहायक विधियों को हटा दिया है और इसके बजाय मैं जेएस में निर्मित कुछ कोकून विधियों का उपयोग कर रहा हूं।

मैंने समस्या को ठीक किया जहां "एड" पर क्लिक करने से application.html.erb फ़ाइल से = javascript_include_tag :cocoon को हटाकर एक के बजाय दो फ़ील्ड जोड़े जाएंगे।

मैंने jQuery जोड़ने और मददगार बनाने की कोशिश की है, लेकिन मुझे यकीन नहीं है कि मैंने कोड सही तरीके से दर्ज किया है।

class Parent < ActiveRecord::Base 

has_many :kids 
has_many :pets, through: :kids # <<<<<< ADDED KIDS USING 'through:' 

kid.rb फ़ाइल:

class Kid < ActiveRecord::Base 

belongs_to :parent 
has_many :pets 
accepts_nested_attributes_for :pets, reject_if: :all_blank, allow_destroy: true 
validates :name, presence: true 

pet.rb फ़ाइल

parent.rb फ़ाइल (मैं और अधिक स्पष्ट रिश्तों बनाने के लिए मॉडल वस्तुओं को बदल दिया है) :

class Pet < ActiveRecord::Base 

belongs_to :kid 

validates :name, presence: true 

validates :age, presence: true 

टी

<div class="nested-fields"> 
    <div class="pet-fields"> 
     <%= f.hidden_field :_destroy, class: 'removable' %> 
     <%= f.text_field :name, placeholder: 'Pet Name', id: 'pet-name-input' %> 
     <%= f.text_field :age, placeholder: 'Pet Age', id: 'pet-age-input' %> 
     <%= link_to_remove_association 'Remove Pet', f, id: 'remove_pet' %> 
    </div> 
    </div> 

उत्तर

7

जब:

<div class="nested-fields"> 

    <div class="kid-fields inline"> 
     <%= f.hidden_field :_destroy, class: 'removable' %> 
     <%= f.text_field :name, class: 'form-control', placeholder: 'Kid's Name', id: 'kid-input' %> 
     <div> 
     <%= link_to_remove_association 'Remove Kid', f %> 
     </div> 


     <%= f.fields_for :pets do |pet| %> 
     <%= render 'pet_fields', f: pet %> 
     <% end %> 
     </div>  
     <div> 
     <%= link_to_add_association "Add Pet", f, :pets, id: 'add_pet', 
      'data-association-insertion-method' => 'before' %> 
     </div> 
    </div> 

यह मेरा _pet_fields.rb फ़ाइल है:

<%= form_for @parent do |f| %> 
    <% if @parent.errors.any? %> 
    <div class="alert alert-danger"> 
    <h3><%= pluralize(@student.errors.count, 'Error') %>: </h3> 

     <ul> 
      <% @student.errors.full_messages.each do |msg| %> 
       <li><%= msg %></li> 
      <% end %> 
     </ul> 
    </div> 
<% end %> 

    <div class="inline"> 
    <div> 
     <%= f.fields_for :kids do |kid| %> 
     <%= render 'kid_fields', f: kid %> 
     <% end %> 
      <div> 
      <%= link_to_add_association "Add Kid", f, :kids, id: 'add_kid', 
      'data-association-insertion-method' => 'before', 
      'data-association-insertion-traversal' => 'closest' %> 
      </div> 
     <% end %> 
    </div> 


    </div> 
     <div class="form-actions"> 
      <%= f.submit 'Create Parent', class: 'btn btn-primary' %> 
     </div> 

<% end %> 

यह मेरा _kid_fields.rb फ़ाइल है: उसकी मेरी _form.html.erb फ़ाइल है मैं "छात्र निकालें" पर क्लिक करता हूं, यह उस लिंक के ऊपर प्रत्येक फ़ील्ड को हटा देता है

यह आपके द्वारा अनुसरण किए जा रहे विशेष रेलस्कास्ट के साथ एक प्रसिद्ध मुद्दा है (यह पुराना है)। एक और here है:

enter image description here

समस्या fields_for references की child_index करने के लिए नीचे आता है।

प्रत्येक बार जब आप fields_for (जो आप उपरोक्त जावास्क्रिप्ट कार्यक्षमता के साथ प्रतिलिपि बना रहे हैं) का उपयोग करते हैं, तो यह id को बनाए गए फ़ील्ड के प्रत्येक सेट में असाइन करता है। विभिन्न गुणों को अलग करने के लिए idsparams में उपयोग किया जाता है; उन्हें प्रत्येक फ़ील्ड को HTML "id" property के रूप में भी सौंपा गया है।

इस प्रकार, आपके पास समस्या यह है कि जब भी आप एक नया फ़ील्ड जोड़ते हैं तो आप child_index को अपडेट नहीं कर रहे हैं, वे सभी समान हैं।और चूंकि आपका link_to_add_fields सहायक जेएस अपडेट नहीं करता है (आईई आपको बिल्कुल उसी child_index के साथ फ़ील्ड जोड़ने की अनुमति देता है), इसका मतलब है कि जब भी आप किसी फ़ील्ड को "हटा दें", तो यह उन सभी का चयन करेगा। child_index (मैं आप नीचे दिए गए एक स्पष्टीकरण दे देंगे)


इस के लिए ठीक स्थापित करने के लिए है।

मैं ईमानदार होने के लिए अपने पुराने सामान को चुनने के बजाय आपको नया कोड देना चाहता हूं। एक बुलाया Cocoon बहुत लोकप्रिय है, हालांकि नहीं एक "प्लग एंड प्ले" समाधान - Rails accepts_nested_attributes_for with f.fields_for and AJAX

जवाहरात जो आपके लिए यह कर रहे हैं:

मैं इस यहाँ (हालांकि यह एक छोटे से पॉलिश किया जा सकता है) के बारे में लिखा कई लोग सोचते हैं कि यह है।

बहरहाल, यह यह सब काम करता है पता करने के लिए, भले ही आप Cocoon की तरह कुछ का उपयोग करने के निकलूँ सबसे अच्छा है ...


fields_for

समाधान समझने के लिए, आप याद रखना चाहिए कि रेल बनाता है एचटीएमएल रूपों।

आप इसे शायद जानते हैं; कई नहीं करते हैं।

यह महत्वपूर्ण है क्योंकि जब आपको लगता है एचटीएमएल रूपों सभी बाधाओं एचटीएमएल द्वारा लगाए गए का पालन करने के लिए है कि, आप समझ जाएगा कि रेल जादूगर लोगों का एक बहुत लगता है ऐसा नहीं लगता है।

#app/models/student.rb 
class Student < ActiveRecord::Base 
    has_many :teachers 
    accepts_nested_attributes_for :teachers #-> this is to PASS data, not receive 
end 

#app/models/teacher.rb 
class Teacher < ActiveRecord::Base 
    belongs_to :student 
end 

कुछ नोट करना महत्वपूर्ण है कि आपके accepts_nested_attributes_forमाता पिता मॉडल पर होना चाहिए:

एक "नेस्टेड" बनाने के लिए करें जिस तरह से ( बिना जोड़ें/निकालें) कार्यक्षमता इस प्रकार है। यही कारण है, मॉडल आप के लिए डेटा गुजर रहे हैं (नहीं एक डेटा प्राप्त):

नेस्टेड गुण आप माता-पिता

#app/controllers/students_controller.rb 
class StudentsController < ApplicationController 
    def new 
     @student = Student.new 
     @student.teachers.build #-> you have to build the associative object 
    end 

    def create 
     @student = Student.new student_params 
     @student.save 
    end 

    private 

    def student_params 
     params.require(:student).permit(:x, :y, teachers_attributes: [:z]) 
    end 
end 

इन के साथ के माध्यम से जुड़े रिकॉर्ड पर विशेषताओं को सहेजने की अनुमति

#app/views/students/new.html.erb 
<%= form_for @student do |f| %> 
    <%= f.fields_for :teachers |teacher| %> 
     <% # this will replicate for as many times as you've "built" a new teacher object %> 
     <%= teacher.text_field ... %> 
    <% end %> 
    <%= f.submit %> 
<% end %> 

यह एक स्टेशन है: वस्तुओं बनाया गया है, तो आप उन्हें अपने रूप में उपयोग कर सकें ndard फॉर्म जो आपके नियंत्रक को डेटा भेज देगा, और उसके बाद आपके मॉडल पर। मॉडल में accepts_nested_attributes_for विधि आश्रित विशेषताओं को आश्रित गुणों को पास करेगी।

-

इस से कोई लेना देना सबसे अच्छी बात एकत्रित फ़ील्ड ऊपर कोड बनाता है के लिए id को ध्यान में रखना है। मेरे पास हाथ पर कोई उदाहरण नहीं है; यह आपको दिखाना चाहिए कि नेस्टेड फ़ील्ड में teachers_attributes[0][name] आदि जैसे नाम हैं।

ध्यान देने योग्य महत्वपूर्ण बात यह है कि [0] - यह child_index है जो आपको आवश्यक कार्यक्षमता में एक महत्वपूर्ण भूमिका निभाता है।


गतिशील

अब गतिशील फार्म के लिए।

पहला भाग अपेक्षाकृत सरल है ... को हटाकर एक फ़ील्ड इसे डीओएम से हटाने का मामला है। हम उस के लिए child_index

#app/models/Student.rb 
class Student < ActiveRecord::Base 
    def self.build #-> non essential; only used to free up controller code 
     student = self.new 
     student.teachers.build 
     student 
    end 
end 

#app/controllers/students_controller.rb 
class StudentsController < ApplicationController 
    def new 
     @student = Student.build 
    end 

    def add_teacher 
     @student = Student.build 
     render "add_teacher", layout: false 
    end 

    def create 
     @student = Student.new student_params 
     @student.save 
    end 

    private 

    def student_params 
     params.require(:student).permit(:x, :y, teachers_attributes: [:z]) 
    end 
end 
विचारों के लिए

अब (ध्यान दें कि आप partials में अपने फार्म को विभाजित करने के लिए है) का उपयोग कर सकते हैं, इसलिए हम पहले पता करने के लिए बच्चे के सूचकांक सेट करने का तरीका आदि आदि आदि की जरूरत है ...:

#app/views/students/new.html.erb 
<%= form_for @student do |f| %> 
    <%= f.text_field :name %> 
    <%= render "teacher_fields", locals: {f: f} %> 
    <%= link_to "Add", "#", id: :add_teacher %> 
    <%= f.submit %> 
<% end %> 

#app/views/_teacher_fields.html.erb 
<%= f.fields_for :teachers, child_index: Time.now.to_i do |teacher| %> 
    <%= teacher.text_field ....... %> 
    <%= link_to "Remove", "#", id: :remove_teacher, data: {i: child_index} %> 
<% end %> 

#app/views/add_teacher.html.erb 
<%= form_for @student, authenticity_token: false do |f| %> 
    <%= render partial "teacher_fields", locals: {f:f} 
<% end %> 

यह आप के लिए विभिन्न रूपों आदि, fields_for सहित प्रस्तुत करना चाहिए। child_index: Time.now.to_i पर ध्यान दें - यह प्रत्येक fields_for के लिए एक अद्वितीय आईडी सेट करता है, जो आपको आवश्यकतानुसार प्रत्येक फ़ील्ड के बीच अंतर करने की इजाजत देता है।

इस गतिशील तो जे एस करने के लिए नीचे आता है बनाना:

#config/routes.rb 
resources :students do 
    get :add_teacher, on: :collection #-> url.com/students/get_teacher 
end 

हमें एक Ajax अनुरोध (एक नए क्षेत्र पाने के लिए) भेजने के लिए अनुमति देता है इस मार्ग का उपयोग करना:

#app/assets/javascripts/.....coffee 
$ -> 

    #Add Teacher 
    $(document).on "click", "#add_teacher", (e) -> 
     e.preventDefault(); 

     #Ajax 
     $.ajax 
     url: '/students/add_teacher' 
     success: (data) -> 
      el_to_add = $(data).html() 
      $('#subscribers').append(el_to_add) 
     error: (data) -> 
      alert "Sorry, There Was An Error!" 

    #Remove Teacher 
    $(document).on "click", "#remove_teacher", (e) -> 
     e.preventDefault(); 

     id = $(this).data("i") 
     $("input#" + i).remove() 
+1

चाहेंगे मैं कक्षा के लिए वही काम करता हूं जैसा मैंने शिक्षक के लिए किया था? मेरे पास कुछ हद तक काम कर रहा है, हालांकि मुझे _do_ को कहीं भी एक बच्चे_इंडेक्स शामिल करने की आवश्यकता है क्योंकि मुझे लगता है कि यह सिर्फ आईडी की बजाय प्रामाणिकता टोकन असाइन कर रहा है। – BB123

+0

तो मैंने [इस उदाहरण] का पालन किया है [https://hackhands.com/building-has_many-model-relationship-form-cocoon/) [कोकून जेम] का उपयोग करके (https://github.com/nathanvda/cocoon) और जब भी मैं "जोड़ें" लिंक पर क्लिक करता हूं, सिवाय इसके कि सबकुछ ठीक से काम कर रहा है, यह सिर्फ एक के बजाय दो फ़ील्ड जोड़ता है। मुझे लगता है कि यह मेरे नियंत्रक के साथ कुछ हो रहा है लेकिन मुझे यकीन नहीं है। मैं किसी भी जेएस या हेल्पर विधियों का उपयोग नहीं कर रहा हूं। मेरी मुख्य चिंता यह है कि खेतों में मुझे एक बच्चा नहीं दे रहा है। इसके बजाय यह मुझे अभी भी दे रहा है जो मुझे लगता है कि एक प्रामाणिकता टोकन (यादृच्छिक संख्याओं का एक गुच्छा) है। @richpeck – BB123

+0

यह संभवतः एक टर्बोलिंक समस्या होगी। पृष्ठ को रीफ्रेश करने का प्रयास करें और इसे दोबारा करने का प्रयास करें - अगर यह दो अनुरोध भेजना जारी रखता है, तो हमें आपके जेएस बाइंडिंग का पता लगाना होगा –

-1
add this in your js.coffe file 
$(document).on 'click', 'form .remove_', (event) -> 
$(this).prev('input[type=hidden]').val('1') 
$(this).closest('fieldset').hide() 
event.preventDefault() 

$(document).on 'click', 'form .add_teacher', (event) -> 
event.preventDefault() 
time = new Date().getTime() 
regexp = new RegExp($(this).data('id'), 'g') 
$(this).before($(this).data('fields').replace(regexp, time)) 
+0

सुझाए गए समय के लिए यादृच्छिक संख्या जोड़नी चाहिए, आपको समस्या को ठीक करने के लिए समाधान और मुख्य रूप से तर्क को लागू करने के तरीके को समझाने की आवश्यकता है। न केवल कॉपी और पेस्ट कोड। https://github.com/ryanb/railscasts-episodes/blob/master/episode-196/revised/questionnaire-after/app/assets/javascripts/surveys.js.coffee –

संबंधित मुद्दे