LuanDantas
6/24/2018 - 11:36 AM

Atributos Aninhados

Atributos Aninhados

Muitas vezes, em um único formulário queremos adicionar records em mais de uma tabela, e isso pode ser um grande problema se não soubermos usar atributos aninhados dentro do Rails.

Para fazer isso, precisamos preparar nosso Model, nossa Controler e por fim a view.

No model, faremos o seguinte em nosso código:

Preparando o Model

class Contact < ApplicationRecord

  accepts_nested_attributes_for :address

end

Adicionaremos a linha de código acima, que basicamente informa ao model para aceitar atributos aninhados do model de "endereços".

Também podemos passar parâmetros, tais como validar em caso de campos vazios ou permitir a exclusão desses dados relacionais também.

class Contact < ApplicationRecord

  accepts_nested_attributes_for :phones, reject_if: :all_blank, allow_destroy: true

end

Preparando o Controller

Agora, precisamos informar aos nossos controllers que aceitamos os fields de "contact". Iremos fazer isso modificamos nosso método "contact_params"

class ContactsController < ApplicationController

  def contact_params
    params.required(:contact).permit(:name
      address_attributes: [:street, :number, :neighborhood]
    )
  end

end

Dessa maneira nosso controller fica preparado para receber parâmetros de outros modelos se necessário.

E também precisamos adicionar o código abaixo na nossa action new, para que nossa view possa exibir os novos campos quando necessário:

class ContactsController < ApplicationController

  def new
    @contact = Contact.new
    @contact.build_address
  end

end

Preparando a View

Em nossa view, além de toda a regra padrão, utilizaremos um helper para delimitar os campos oriundos de outro modeo:

<%= form_for @contact do |f| %>
  
  <%= f.fields_for :address do |a| %>
    <div>
      <%= a.label :street %>
      <%= a.text_field :street %>
    </div>
    <div>
      <%= a.label :number %>
      <%= a.text_field :number %>
    </div>
    <div>
      <%= a.label :neighborhood %>
      <%= a.text_field :neighborhood %>
    </div>
  <% end %>
  
<% end %>

Utilizando o helper "fields_for" seguido do modelo ":address", resolvemos nosso problema na view.

E por último...

E por último é importante que façamos uma coisa, quando temos um "address" que belongs_to "contact", nós só conseguimos criar um endereço se já existir um contato no banco de dados para ele ter um relacinamento, certo? Porém como estaremos no ato de criação de um novo contato e ao mesmo tempo de um endereço, o contato ainda não foi salvo no banco e o mesmo ainda não possui um ID. Então para isso, será necessário fazermos o seguinte.

No nosso modelo de "Address" faremos a seguinte mudança:

class Address < ApplicationRecord
  belongs_to :contact, required: false
end

Adiciona "required: false", ele ignora a obrigatioriedade de ter um ID no momento do cadastro, e fará o cadastro corretamente e posteriormente a atribuição do ID recém cadastrado.