2009-12-04 9 views
11

Uczę się RoR i próbuję użyć accepts_nested_attributes_for i has_and_belongs_to_many do przesyłania informacji, które tradycyjnie byłyby dwiema formami. Czytałem na niektórych stronach, które są zgodne, niektóre witryny nie są kompatybilne, a niektóre strony nie wiedzą. Jako odniesienie używam Rails 2.3.4. Próbowałem modelowania moje rozwiązanie z samouczka Ryan's Scraps na nested modelsPróba użycia accepts_nested_attributes_for i has_and_belongs_to_many, ale tabela dołączeń nie jest wypełniana

Z tego, co próbowałem debugować, wydaje się, że mam dwa problemy, ale nie jestem pewien, dlaczego.

  1. Po przesłaniu formularza z modelami zagnieżdżonymi publikowana jest tylko część zagnieżdżonych informacji o modelu. I tylko dostać pierwsze pole, nie „n” inni użytkownik może wybrali
  2. jednolitego pola, która zostanie wysłana, nie są jakieś wiersze wstawione do tabeli sprzężenia, który został utworzony dla relacji HABTM.

Oto kawałek kodu i odpowiednie dzienniki dla mojego wstawiania próbie:

Prokuratora Model:

class Attorney < ActiveRecord::Base 
    has_and_belongs_to_many :associations 
    accepts_nested_attributes_for :associations, :reject_if => proc { |a| a['name'].blank? } 
end 

Stowarzyszenia Model:

class Association < ActiveRecord::Base 
    has_and_belongs_to_many :attorneys 
    accepts_nested_attributes_for :attorneys 
    validates_presence_of :name, :message => "Please enter an association name." 
end 

Rzeczników Kontroler:

def new 
    @attorney = Attorney.new 
    @attorney.associations.build 

    respond_to do |format| 
    format.html # new.html.erb 
    format.xml { render :xml => @attorney } 
    end 
end 

def create 
    @attorney = Attorney.new(params[:attorney]) 

    respond_to do |format| 
    if @attorney.save 
     flash[:notice] = 'Attorney was successfully created.' 
     format.html { redirect_to(@attorney) } 
     format.xml { render :xml => @attorney, :status => :created, :location => @attorney } 
    else 
     format.html { render :action => "new" } 
     format.xml { render :xml => @attorney.errors, :status => :unprocessable_entity } 
    end 
    end 
end 

adwokackie Nowy Widok:

<% form_for(@attorney, :html => {:multipart => true}) do |f| %> 
    <%= f.error_messages %> 
<%= f.label :"First name" %> 
<%= f.text_field :firstname %><br> 

<%= f.label :"Last Name" %> 
<%= f.text_field :lastname %><br> 

<%= f.label :"Attorney Type" %> 
<%= f.collection_select :member_type_id, MemberType.all, :id, :name %><br> 

<%= f.text_area :bio, :cols => 70, :rows => 20 %><br><br> 

<%= f.label :"Attorney Location" %> 
<%= f.collection_select :office_location_id, OfficeLocation.all, :id, :location %><br> 

<div id="associations"> 
     <%= render :partial => 'shared/membership' %> 
</div> 
<%= add_association_link "Add Association" %> 
    <%= f.submit 'Create' %> 
<% end %> 

Członkostwo Częściowa:

<div class="association"> 
    <% fields_for :associations do |assoc_form| %> 
    <%= assoc_form.collection_select(:association_id, Association.find(:all), :id, :name, :include_blank => true) %> 

<% = link_to_function "usunąć", "$ (this) .up ('stowarzyszenie'). Remove()". %> <% = link_to 'New Stowarzyszenie' new_association_path%> <% end%>

Prokurator Hel za link:

def add_association_link(name) 
    link_to_function name do |page| 
    page.insert_html :bottom, :associations, :partial => 'shared/membership', :object => AssociationsAttorneys.new 
    end 
end 

Dołącz Tabela migracji: przechwytywania

class CreateAssociationsAttorneys < ActiveRecord::Migration 
    def self.up 
    create_table :associations_attorneys do |t| 
     t.references :attorney, :null => false 
     t.references :association, :null => false 
     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :associations_attorneys 
    end 
end 

Log:

Processing AttorneysController#new (for 127.0.0.1 at 2009-12-04 08:16:19) [GET] 
Rendering template within layouts/default 
Rendering attorneys/new 
    [4;35;1mMemberType Load (0.4ms)[0m [0mSELECT * FROM "member_types" [0m 
    [4;36;1mOfficeLocation Load (18.6ms)[0m [0;1mSELECT * FROM "office_locations" [0m 
    [4;35;1mAssociation Load (0.6ms)[0m [0mSELECT * FROM "associations" [0m 
Rendered shared/_membership (3.5ms) 
    [4;36;1mCACHE (0.0ms)[0m [0;1mSELECT * FROM "associations" [0m 
Rendered shared/_membership (1.5ms) 
Rendered shared/_nav (0.6ms) 
Rendered shared/_footer (0.1ms) 
Completed in 149ms (View: 114, DB: 20) | 200 OK [http://localhost/attorneys/new] 

Processing ApplicationController#index (for 127.0.0.1 at 2009-12-04 08:16:19) [GET] 

Processing AttorneysController#create (for 127.0.0.1 at 2009-12-04 08:16:57) [POST] 
    Parameters: {"commit"=>"Create", "authenticity_token"=>"Jh7aMCcOY7jUu/D1YtiCswg2n6iwqnS98VnVn46psp0=", "associations"=>{"association_id"=>"3"}, "attorney"=>{"birthstate"=>"Alabama", "office_location_id"=>"1", "birthdate"=>"December 3, 2009", "birthcity"=>"Test", "middlename"=>"Test", "lastname"=>"Testing", "image_temp"=>"", "member_type_id"=>"2", "firstname"=>"Test", "bio"=>"testing testing testing", "suffix"=>"", "email"=>"[email protected]"}} 
    [4;35;1mAttorney Load (15.6ms)[0m [0mSELECT "attorneys".id FROM "attorneys" WHERE ("attorneys"."email" = '[email protected]') LIMIT 1[0m 
    [4;36;1mAttorney Create (0.8ms)[0m [0;1mINSERT INTO "attorneys" ("birthstate", "created_at", "birthdate", "office_location_id", "birthcity", "updated_at", "middlename", "lastname", "firstname", "member_type_id", "suffix", "bio", "image", "email") VALUES('Alabama', '2009-12-04 15:16:57', 'December 3, 2009', 1, 'Test', '2009-12-04 15:16:57', 'Test', 'Testing', 'Test', 2, '', 'testing testing testing', NULL, '[email protected]')[0m 
Redirected to http://localhost:3000/attorneys/11 
Completed in 150ms (DB: 16) | 302 Found [http://localhost/attorneys] 

widzę, że stowarzyszenia "=> {" association_id "=>" 3" } go otrzymuje tylko ostatnie z wielu skojarzeń, które miałem dla danej osoby i nie tworzy żadnych wpisów w tabeli łączenia. Gdzie mój kod mógł pójść nie tak?

Odpowiedz

27

Macie problemy tutaj, niestety jeden z nich jest maskowany przez drugą.

Oba problemy wynikają z tej części zdania:

<div class="association"> 
    <% fields_for :associations do |assoc_form| %> 
    <%= assoc_form.collection_select(:association_id, Association.find(:all), 
     :id, :name, :include_blank => true) %> 

Problem 1: pan zrozumiał co accept_nested_fields_for robi.

accepts_nested_fields_for służy do tworzenia i modyfikowania powiązanych obiektów w formularzu. Może być używany do wypełniania tabeli łączenia, co jest typem tego, co próbujesz zrobić. Jednak użycie accepts_nested_fields_for do wypełnienia tabeli łączenia jest niemożliwe w przypadku relacji HABTM. Dobrym wykorzystaniem accepts_nested_fields_for byłoby, gdybyś chciał stworzyć nowe Stowarzyszenie, które będzie połączone z nowym adwokatem. Lub jeśli masz model łączenia bogatego, który wymaga dodatkowych informacji dla każdego rekordu.

Problem 2: Nie łączysz pól w tym formularzu z formularzem pełnomocnika. Które jest konieczne do użycia accepts_nested_fields_for.

Ustaliliśmy już, że accepts_nested_fields_for nie jest tym, czego potrzebujesz, aby to osiągnąć, ale nadal nie kojarzysz pola wyboru association_id z formularzem. Z tego powodu ustawiono params [association] [association_id], a nie params [adwokat] [association] [association_id].

Problem 3: Struktura formularza jest nieprawidłowa dla tego, co wygląda na próbę osiągnięcia.

Jest zbyt wiele rzeczy, które wymagają korekty w celu prawidłowego rozwiązania problemu. Lepiej sprawdź się na stronie complex-forms-example repository. Jest to działający przykład accepts_nested_attributes_for, nie zajmuje się żadnymi relacjami HABTM, ale powinien nauczyć cię wszystkiego, co musisz wiedzieć. Skorygowany kod poniżej to 90% tego, czego potrzebujesz. Powyższe złożone formularze-przykłady podpowiedzą Ci, co powinieneś wiedzieć, aby wypełnić puste pola add_association_link i create_association_link.

Korekta obejmuje następujące etapy:

  1. Tworzenie dołączyć model i zmienić stosunek do a ma wiele przez jeden, przyjmując zagnieżdżonych atrybuty modelu przyłączyć.
  2. Dokonaj drobnej regulacji w kontrolerze pod względem budowania rzeczy.
  3. Przekaż obiekt konstruktora formularzy do częściowego.
  4. Przepisz formularz w częściowej, dlatego koncentruje się na nowo utworzonym modelu łączenia.

Można to osiągnąć, wprowadzając następujące zmiany.

class Attorney < ActiveRecord::Base 
    has_many :attorney_associations 
    has_many :associations, :through => :attorney_associations 

    accepts_nested_attributes_for :attorney_associations, :reject_if => proc { |a| 
    a['association_id'].blank? } 
    accepts_nested_attributes_for :associations, :reject_if => proc {|a| 
    a['name'].blank?} 
end 

class AttorneyAssociations < ActiveRecord::Base 
    belongs_to :attorney 
    belongs_to :association 
end 

Prokurator Kontroler:

def new 
    @attorney = Attorney.new 
    @attorney.associations.build 
    @attorney.attorney_associations.build 


    respond_to do |format| 
    format.html # new.html.erb 
    format.xml { render :xml => @attorney } 
    end 
end 

Nowy prokurator Widok:

<% form_for(@attorney, :html => {:multipart => true}) do |f| %> 
    <%= f.error_messages %> 
<%= f.label :"First name" %> 
<%= f.text_field :firstname %><br> 

<%= f.label :"Last Name" %> 
<%= f.text_field :lastname %><br> 

<%= f.label :"Attorney Type" %> 
<%= f.collection_select :member_type_id, MemberType.all, :id, :name %><br> 

<%= f.text_area :bio, :cols => 70, :rows => 20 %><br><br> 

<%= f.label :"Attorney Location" %> 
<%= f.collection_select :office_location_id, OfficeLocation.all, :id, :location %><br> 

<div id="associations"> 
    <% f.fields_for :attorney_association do |aa_form| %> 
    <%= render :partial => 'attorney_association', :locals => {:f => aa_form} %> 
    <% end %> 
    <%= add_association_link "Add Another Existing Association" %> 
    <% f.fields_for :associations do |assoc_form| %> 
    <%= render :partial => 'attorney', :locals => {:f => assoc_form} %>  
    <%= create_association_link, "Create a New Association for this Attorney" %> 
</div> 



<%= f.submit 'Create' %> 
<% end %> 

jestem przy założeniu, że add_association_link jest javascript pomocnik, który tworzy link do sklonować pusty przykład tego, co było członkostwo częściowe. create_association_link to obiekt zastępczy dla podobnego pomocnika, który doda częściowe dla nowego powiązania.

Prokurator Stowarzyszenie Częściowa:

<div class="attorney_association"> 
    <%= f.collection_select(:association_id, Association.find(:all), 
     :id, :name, :include_blank => true) %> 
    <%= link_to_function "remove", "$(this).up('.attorney_association').remove()" %> 
    </div> 

Stowarzyszenie Częściowa:

<div class="association"> 
    <%= f.label_for :name %> 
    <%= f.text_field :name %> 
    <%= link_to_function "remove", "$(this).up('.attorney_association').remove()" %> 
    </div> 
+0

Zmieniając widok, aby przekazać w formie 'f', teraz jestem coraz błąd: niezdefiniowane metoda 'association_id 'dla # w tym wierszu w częściowym: <% = assoc_form.collection_select (: association_id, Association.find (: all),: id ,: name,: include_blank => true)%>. Jakieś pomysły? – davidstites

+0

Wygląda na to, że przeoczyłem wiele innych problemów, które się pojawiały. Zaktualizowałem rozwiązanie, aby również rozwiązać te problemy. – EmFi

+0

więc pracowałem nad tym przez kilka tygodni i nadal mam problemy. kiedy próbuje zrzec się częściowej adwokatury, narzekając, że nie wie, co to jest "f" ... myślałem, że obiekt formularza został przekazany z hashiem: locals? – davidstites

Powiązane problemy