Rails 2.2: Atualizando uma associação através de sua foreign key

29 de outubro de 2008  |  Rails 2.2  | 

Não sei dizer se isto é um bug ou não, mas na minha opinião isto representa um problema. Veja o código abaixo, onde tento alterar a conta de um usuário usando sua foreign key em um projeto Rails 2.1 ou anterior:

class User < ActiveRecord::Base
  belongs_to :account
end

user = User.first
# => #<User id: 1, login: "admin", account_id: 1>

user.account
# => #<Account id: 1, name: "My Account">

user.account_id = 2
# => 2

user.account
# => #<Account id: 1, name: "My Account">

Note que estou alterando a conta do usuário, mas a associação não foi atualizada. Mesmo depois de salvar o objeto user, se ele não for recarregado, a associação continuará mostrando a conta errada.

No Rails 2.2 este problema foi corrigido, veja:

class Comment < ActiveRecord::Base
  belongs_to :post
end

comment = Comment.first
# => #<Comment id: 1>

>> comment.post
# => #<Post id: 1>

>> comment.post_id = 2
# => 2

>> comment.post
# => #<Post id: 2>

Veja que ao alterar o post por meio de sua foreign key, automaticamente a associação foi atualizada.


Todos os exemplos dados aqui funcionarão somente no Ruby on Rails 2.2 ou superior. Você pode encontrar mais detalhes sobre esta e outras novidades do Rails 2.2 no e-book “Ruby on Rails – O que há de novo?“.



7 Comentários


  1. e no segundo exemplo, caso o post numero 2 não existisse, ele retornaria nil?

  2. Muito bom, eu já perdi um tempo com esse mesmo problema, e era no mínimo irritante.

  3. Boa pergunta Thiago!

    Se você informar um id que não existe ele funcionará como era no passado, sem atualizar a associação.

  4. ola Carlos,

    eu particularmente, gosto muito do activerecord, mas isse tipo de coisa me deixa muito triste pois mata completamente a POO, na minha opnião o atributo
    post_id não deveria esta presente para escrita em comment, por que?
    encapsulamento,o que gostariamos de fazer é trocar o objeto post não o “post_id”,bem de qualquer forma excelente dica e desculpa pelo “purismo OO”.

  5. O problema Bruno é que imagine uma atualização em campos de ids muitas vezes é necessária. Com quando selecionamos um item em uma drop_down_list e depois precisamos atualizar o registro.

  6. beleza carlos,
    se o item selecionado, puder ser recuperado como comentario no controller,
    então uma abordagem seria:

    item_selecionado.change_post(new_post)
    
    # codigo do change_post em Comment...
    def change_post(other_post)
      @post_id = other_post.id
      save!
    end

    dado que itemselecionado aqui é um comment e new_post foi recuperado de algum lugar ( banco, parametros etc) a vantagem disso é que fica claro sua intenção de mudar o “dono” do objeto além de manter o encapsulamento.

    quero deixar claro que isso é apenas uma maneira mais OO apenas,até porque certo e errado em alguns casos são bem subjetivos, sempre depende da situação e do problema em questão.

    grande abraço

    Bruno

Deixe um comentário