Nov 7 2011
Criando relacionamentos one-to-one no Rails
Sempre que criamos um sistema, precisamos criar relacionamentos entre tabelas. Os relacionamentos podem ser de alguns tipos:
- One to One
- One to Many
- Many to Many
Eu vou demostrar aqui como criar relacionamentos One to One. Para esse exemplo, vamos considerar que um usuário possui um perfil e um perfil só pode pertencer a um usuário.
Para começar, vamos criar nosso usuário.
rails g scaffold user name:string email:string
No nosso caso, não iremos precisar criar controller e views para o perfil. As informações contidas no perfil serão criadas no mesmo form que se cria as informações do usuário. Por isso, criaremos apenas um model para o perfil.
rails g model profile user_id:integer description:text
Neste caso, faremos o relacionamento adicionando o id do usuário na tabela do perfil. Vamos, agora, adicionar as migrações no banco.
rake db:migrate
Podemos começar a adicionar o código para criar nosso relacionamento. A primera coisa a se fazer é alterar os models para que eles saibam com quem estão se relacionando. No model do perfil, vamos dizer que ele pertence ao usuário.
#app/models/profile.rb class Profile < ActiveRecord::Base belongs_to :user end
O model do usuário vai ficar assim:
#app/models/user.rb class User < ActiveRecord::Base has_one :profile accepts_nested_attributes_for :profile end
Neste caso, precisamos adicionar a linha acceptsnestedattributesfor :profile_. O que ela faz é informar para o model que ele deve aceitar os atributos que são do perfil e salvá-los na tabela correspondente. Nested Attributes permitem que você salve os atributos de um filho através de seu pai. Exatamente o que estamos fazendo neste caso. No form de usuário, adicionaremos os campos do perfil e, no momento que submetermos, o perfil será salvo através do usuário. Ficará mais fácil de entender vendo como montaremos o form do usuário. Vamos a ele então.
#app/views/users/_form.html.erb <%= form_for(@user) do |f| %> ... <div class="field"> <%= f.fields_for :profile do |p| %> <%= p.label :description %><br/> <%= p.text_area :description %> <% end %> </div> ... <% end %>
Eu reduzi um pouco o arquivo para ficar mais fácil de visualizar o código que estamos adicionando. O f.fieldsfor :profile_ serve para adicionarmos os campos do perfil dentro do form do usuário. Foi por isso que adicionamos a linha do nestedattributes no model de usuário. Na segunda parte, passamos um bloco onde adicionaremos os campos do perfil que, no nosso caso, é apenas _description.
Precisamos fazer com que a descrição apareça na tela depois de criada. Por isso, a adicionaremos no show do usuário.
#app/views/users/show.html.erb ... <p> <b>Description:</b> <%= @user.profile.description %> </p>
Neste momento, se você iniciar o servidor e for olhar sua view, notará que o campo description ainda não está aparecendo; isto é porque ele ainda não foi “criado”. Então, precisamos fazer essa “criação”. Vamos alterar nosso controller para isso.
#app/controllers/users_controller.rb def new @user = User.new @user.build_profile end
A linha @user.buildprofile_ está dizendo para “construir”(não consigo pensar uma expressão melhor no momento
) um perfil para esse usuário.
Tudo pronto! Agora, quando você for criar um usuário novo, verá o campo description, que salvará as informações no local certo e com o relacionamento certo.
Apenas como informação adicional: remova o arquivo public/index.html e adicione no config/routes.rb a linha
root :to => 'users#index'
Isso é apenas para vocês não precisarem acessar /users todas a vezes que entrarem no sistema.
Você pode baixar o código fonte do exemplo no repositório blog-posts, no Github.