Problemy z nested_model_forms

Chciałbym dodać do Usera zarządzanie jego emailami. (Każdy user może mieć email domowy, z pracy, inny) oraz jeden z tych emaili powinien być oznaczony jako główny.

Mamy zatem taki układ modeli:

[code=ruby]class Profile < ActiveRecord::Base
attr_accessible :available_at, :person_id, :person_attributes
belongs_to :person
accepts_nested_attributes_for :person
delegate :first_name, :last_name, to: :person
end

class Person < ActiveRecord::Base
attr_accessible :title, :emails_attributes

has_one :profile
has_many :emails, class_name: ‘ContactType::Email’

accepts_nested_attributes_for :emails, allow_destroy: true
end

class ContactType::Email < ActiveRecord::Base
EMAIL_TYPE = { work: 0, private: 1, other: 2 }

attr_accessible :email_type, :address, :person_id

belongs_to :person

def email_type
EMAIL_TYPE.key(read_attribute(:email_type))
end

def email_type=(t)
write_attribute(:email_type, EMAIL_TYPE[t.to_sym])
end
end[/code]
W jaki sposób uzyskalibyście możliwość dodawania emaili z poziomu formularza profiles/_form.html ?

= simple_form_for(@profile) do |form| = render 'person_form', f: form = render 'profile_form', f: form = render 'contact_type_form', f: form = form.button :submit
Jest tutaj jakby podwójne zagnieżdżenie. Próbuję to zrobić z dedykowanym Railscastem ale bez sukcesów.

Najnowszy railscast pokazuje inne podejście, może Ci podpasuje lepiej? http://railscasts.com/episodes/416-form-objects

Widziałem właśnie, jednak chciałbym spróbować użyć jednak nested forms, bo będę miał dużo wiecej takich modeli jak Email.

Tym bardziej powininieś się zainteresować innym podejsciem. nested form są bardzo upierdliwe, ciężkie do ogarnięcia i testowania. Inna sprawa podejście railsów, czyli pchanie wszystkiego co się tylko da do modeli, jest bardzo staroświeckie.

Lepiej AR traktować jako worek na dane i całą logikę biznesować, w tym zapisywanie do kilku kolumn na raz, implementować w osobnych klasach.

Tak jak Ci Lucassus napisał.
Zauważ że Twoje modele AR, choć małe, już zawierają spore pomieszanie odpowiedzialności:

  1. persystencja danych i relacje między modelami (ActiveRecord::Base, belongs_to)
  2. dekorowanie i udostępnianie w czytelnej formie konkretnych pól (email_type)
  3. autoryzację: poziomy dostępu do atrybutów (attr_accessible)
  4. dozwoloną strukturę formularzy w widoku (accepts_nested_attributes_for)

Podejrzewam że już niedługo zaczniesz w tym modelu definiować metody i strukturę odpowiedzi dla API.

Rozplątanie tego wykonuje się przez, odpowiednio

  1. nic, od tego właśnie jest AR
  2. prezentery (zalecane!) lub helpery
  3. strong_parameters
  4. form objects

A jak będziesz miał “dużo więcej takich modeli jak Email”, to aż prosi się o wydzielenie tego fragmentu odpowiedzialności do modułu i form objects które obsłużą po prostu dowolną klasę miksującą ten moduł :slight_smile: