Zagnieżdżony formularz railsów z has_many: przez, jak edytować atrybuty modelu łączenia?

103

Jak edytować atrybuty modelu łączenia przy użyciu accepts_nested_attributes_for?

Mam 3 modele: tematy i artykuły połączone przez łączników

class Topic < ActiveRecord::Base
  has_many :linkers
  has_many :articles, :through => :linkers, :foreign_key => :article_id
  accepts_nested_attributes_for :articles
end
class Article < ActiveRecord::Base
  has_many :linkers
  has_many :topics, :through => :linkers, :foreign_key => :topic_id
end
class Linker < ActiveRecord::Base
  #this is the join model, has extra attributes like "relevance"
  belongs_to :topic
  belongs_to :article
end

Kiedy więc buduję artykuł w „nowej” akcji kontrolera tematów ...

@topic.articles.build

... i utwórz zagnieżdżony formularz w topic / new.html.erb ...

<% form_for(@topic) do |topic_form| %>
  ...fields...
  <% topic_form.fields_for :articles do |article_form| %>
    ...fields...

... Railsy automatycznie tworzą konsolidator, co jest świetne. A teraz moje pytanie: mój model Linkera również ma atrybuty, które chcę zmienić za pomocą formularza „nowy temat”. Jednak linker, który Railsy automatycznie tworzy, ma wartości zerowe dla wszystkich swoich atrybutów z wyjątkiem topic_id i article_id. Jak mogę umieścić pola dla tych innych atrybutów linkera w formularzu „nowego tematu”, aby nie wychodziły zera?

Arcolye
źródło
3
Próbuję zrobić to samo, co ty, tylko w nowej / utwórz akcję ... Zastanawiam się, czy możesz udostępnić swoje akcje kontrolera. Chcę utworzyć Userza Accountpomocą a Relationshipjako linker... ale nie mogę dowiedzieć się, jak mają wyglądać nowe i tworzone działania ... czy miałbyś coś przeciwko?
Mohamad

Odpowiedzi:

90

Zrozumiałem odpowiedź. Sztuczka była taka:

@topic.linkers.build.build_article

To buduje konsolidatory, a następnie tworzy artykuł dla każdego konsolidatora. Tak więc w modelach:
topic.rb potrzebuje accepts_nested_attributes_for :linkers
linker.rbaccepts_nested_attributes_for :article

Następnie w formie:

<%= form_for(@topic) do |topic_form| %>
  ...fields...
  <%= topic_form.fields_for :linkers do |linker_form| %>
    ...linker fields...
    <%= linker_form.fields_for :article do |article_form| %>
      ...article fields...
Arcolye
źródło
13
Daj mi znać, czy to było pomocne
Arcolye,
13
Aktualizacja Rails 3: form_for i field_for potrzebują <% =%> zamiast <
%%
Dodałbym odwrotne znaczniki kodu wokół dwóch accepts_nested_attributes_for linii, które dodałeś. Wielokrotnie tęskniłem za tą informacją, po prostu skanując kod - po dokładnym przeczytaniu złapałem brakujący szczegół i rozwiązałem mój problem. Dzięki!
TJ Schuck
2
szczerze mówiąc, jest to rodzaj pełnego przykładu, którego potrzebują przewodnicy rubyonrails.org.
ahnbizcad
Wizualna klarowność naprawdę dużo pomaga, TJ Schuck.
ahnbizcad
6

Kiedy formularz wygenerowany przez Railsy zostanie przesłany do Railsów controller#action, paramsbędzie miał strukturę podobną do tej (dodano niektóre zmyślone atrybuty):

params = {
  "topic" => {
    "name"                => "Ruby on Rails' Nested Attributes",
    "linkers_attributes"  => {
      "0" => {
        "is_active"           => false,
        "article_attributes"  => {
          "title"       => "Deeply Nested Attributes",
          "description" => "How Ruby on Rails implements nested attributes."
        }
      }
    }
  }
}

Zwróć uwagę, jak linkers_attributeswłaściwie jest indeksowany zero Hashz Stringkluczami, a nie Array? Dzieje się tak, ponieważ klucze pól formularza wysyłane do serwera wyglądają następująco:

topic[name]
topic[linkers_attributes][0][is_active]
topic[linkers_attributes][0][article_attributes][title]

Tworzenie rekordu jest teraz tak proste, jak:

TopicController < ApplicationController
  def create
    @topic = Topic.create!(params[:topic])
  end
end
Daniel Doezema
źródło
Nie jestem pewien, ale myślę, że zostało to przyjęte przez cały czasaccepts_nested_attributes_for
Arcolye
2
@Arcolye - Znalezienie tych informacji w Internecie dla takiego stowarzyszenia było wtedy bardzo uciążliwe - może moje google-fu było tego dnia wyłączone. Chciałem przynajmniej udokumentować to tutaj, jako mój współpracownik i po prostu założyłem, że railsy przekonwertowały linked_attributes na tablicę, zamiast na indeksowany hash zero. Miejmy nadzieję, że ta ciekawostka pomoże komuś w przyszłości :)
Daniel Doezema
3

Szybka GOTCHA do korzystania z has_one w Twoim rozwiązaniu. Po prostu skopiuję wklej odpowiedź udzieloną przez użytkownika KandadaBoggu w tym wątku .


buildPodpis metoda jest różna dla has_onei has_manystowarzyszenia.

class User < ActiveRecord::Base
  has_one :profile
  has_many :messages
end

Składnia kompilacji dla has_manyasocjacji:

user.messages.build

Składnia kompilacji dla has_oneasocjacji:

user.build_profile  # this will work

user.profile.build  # this will throw error

Przeczytaj dokumentacjęhas_one stowarzyszenia, aby uzyskać więcej informacji.

8bithero
źródło