2010-07-26 5 views
2

J'ai un attribut nom du modèle Person.Ruby on Rails: compose l'attribut du modèle à partir des attributs virtuels

Je veux utiliser forme html avec des champs: prenom et nom:

<%= f.text_field first_name%> 
<%= f.text_field surname%> 

Et je veux composer ces attributs virtuels pour modéliser l'attribut nom.

Quelle est la meilleure façon de le faire?

J'ai essayé d'utiliser composed_of, mais a échoué ...

class Person < ActiveRecord::Base 
    composed_of :name, :class_name => 'Name', :mapping => %w(name output_name) 
end 

class Name 
    attr_reader :output_name 
    def initialize(first_name, surname) 
    @output_name = first_name + surname 
    end 
end 

@person.attributes= {"name(1s)" => 'Alex', "name(2s)" => 'Bolduin' } 
@person.name.should == 'Alex Bolduin' 

expected: "Alex Bolduin", 
got: #<Name:0x000000049d4c08 @output_name="Alex Bolduin"> (using ==) 

J'utilise Ruby on Rails 3, mais je pense que la solution est similaire pour Rails 3 et Rails 2.3

Répondre

7

Vous devriez être en mesure de faire une colonne à faire semblant de faire quelque chose comme ceci dans le modèle:

class Person < ActiveRecord::Base 
    def name 
     "#{self.first_name} #{self.surname}" 
    end 

    def name=(fullname) 
     first,last = fullname.split(' ') # or some smarter way to split 
     self.first_name = first 
     self.surname = last 
    end 
end 

Il doit être accessible de la même manière que toute autre colonne, et quand vous essayez de définir name il appellera simplement les méthodes de setter pour first_name et surname.


Si vous voulez faire le contraire, vous pouvez toujours utiliser la même astuce:

class Person < ActiveRecord::Base 
    def first_name 
     name.split(' ')[0] 
    end 

    def surname 
     name.split(' ')[1] 
    end 

    def first_name=(first) 
     name = [first, name.split(' ')[1]].join(' ') 
    end 

    def surname=(sname) 
     name = [name.split(' ')[0], sname].join(' ') 
    end 

end 

La seule chose potentiellement mal à ce sujet est que la manipulation de chaîne se produit une fois pour chaque lecture et deux fois pour chaque écrire. Vous pourriez aussi prendre les choses dans le contrôleur en ajoutant quelque chose comme ceci pour créer/mettre à jour avant @person.save:

@person.name = [first_name, surname].join(' ') 
+0

Je veux faire des choses en face, je veux prenom = et nom = faire nom composé – petRUShka

+1

donc le nom composite est celui stocké dans la base de données? – Karl

+0

oui, seulement le nom. – petRUShka