MultiModel forms sao um poderoso recurso oferecido pelo Rails desde a versao 2.3 - porem desconhecido de muitos programadores. Com eles, e possivel editar complexas hierarquias de objetos numa unica view. E uma situacao que nos deparamos com bastante frequencia:Editar Carrinho de Compras e Itens do CarrinhoDados de uma Pessoa e Informacoes de ContatoDados de um Usuario e Permissoes.Post num blog e suas Tags.e por ai vai. Este post e o primeiro de uma serie de quatro artigos, para ilustrar a utilizacao destes recursos:Parte 1: Nested Models - One-to-OneParte 2: Nested Models - One-to-ManyParte 3: Nested FormsParte 4: Nested Forms dinamicos usando Knockout.jsO codigo desta aplicacao de exemplo esta disponivel neste repositorio Github.Nested Models - One-to-OneSegue o modelo utilizado neste tutorial:Person has one UserAccountUserAccount has many Permissions (parte 2)Em nome da simplicidade, Person sera criado via scaffolding:rails g scaffold Person name:stringNeste ponto, pode-se rodar as migrations e iniciar o servidor de desenvolvimento:rake db:migraterails sE ja estara disponivel a tela - bastante rudimentar - para a edicao de Person:http://localhost:3000/peopleComo queremos editar UserAccount a partir do model Person, dispensaremos scaffold, sendo necessario criar o respectivo modelo:rails g model UserAccount person_id:integer username:string password:stringrake db:migratePor fim, resta configurar as validacoes e relacionamentos nos respectivos models.Nested One-to-OneA relacao entre os modelos Person e UserAccount e de um-para-um, sendo que UserAccount possui a chave estrangeira person_id (lado belongs_to):class Person < ActiveRecord::Base attr_accessible :name validates_presence_of :name has_one :user_accountendclass UserAccount < ActiveRecord::Base attr_accessible :password, :username validates_presence_of :username, :password belongs_to :personendPodemos usar o rails console para um teste inicial:$ rails c> p = Person.create name: "Jose da Silva"(0.1ms) begin transactionSQL (16.4ms) INSERT INTO "people" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [["created_at", Tue, 31 Jul 2012 05:57:41 UTC +00:00], ["name", "Jose da Silva"], ["updated_at", Tue, 31 Jul 2012 05:57:41 UTC +00:00]](59.6ms) commit transactionNo exemplo acima, foi criado um objeto Person, passando para o metodo create um hash contendo apenas o atributo name.O uso de nested models possibilita que a chamada create receba tambem os atributos username e password, para criar uma UserAccount simultaneamente ao objeto Person.class Person < ActiveRecord::Base attr_accessible :name, :user_account_attributes validates_presence_of :name has_one :user_account accepts_nested_attributes_for :user_accountend Note que e necessario tornar esses atributos acessiveis via mass-assignment, na lista attr_accessible.> p = Person.create name: "Jose da Silva", user_account_attributes: { username: "jsilva", password: "abc123" }(0.1ms) begin transaction(0.1ms) commit transaction(0.0ms) begin transactionSQL (6.1ms) INSERT INTO "people" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [["created_at", Tue, 31 Jul 2012 06:23:26 UTC +00:00], ["name", "Jose da Silva"], ["updated_at", Tue, 31 Jul 2012 06:23:26 UTC +00:00]]SQL (0.4ms) INSERT INTO "user_accounts" ("created_at", "password", "person_id", "updated_at", "username") VALUES (?, ?, ?, ?, ?) [["created_at", Tue, 31 Jul 2012 06:23:26 UTC +00:00], ["password", "abc123"], ["person_id", 5], ["updated_at", Tue, 31 Jul 2012 06:23:26 UTC +00:00], ["username", "jsilva"]](56.6ms) commit transactionValidacaoO leitor mais atento pode ter notado que UserAccount nao esta validando a presenca de Person. Isto deixa uma brecha no codigo, por permitir a criacao de uma UserAccount desassociada de uma pessoa:> UserAccount.create username: "joao", password: "abc123"(0.2ms) begin transactionSQL (1.4ms) INSERT INTO "user_accounts" ("created_at", "password", "person_id", "updated_at", "username") VALUES (?, ?, ?, ?, ?) [["created_at", Tue, 31 Jul 2012 06:25:34