2012-10-23 2 views
0

J'ai un modèle polymorphe appelé adresse. Ce que j'essaye de réaliser est de havy beaucoup d'adresses liées à d'autres modèles (par exemple l'utilisateur), mais les emploie toujours comme s'il y avait un seul, et essaye de les distinguer par type.has_one choisir parmi plusieurs baser sur le paramètre

Mon projet a été conçu pour utiliser une seule adresse, donc j'ai beaucoup de morceaux de code comme User.first.address ou User.first.address=... dont je ne peux rien faire.

est ici sorte d'exemple:

|id|addressable_type|addressable_id| type | street | 
    1|User   |1    | first | Foo 
    2|User   |1    | second | Bar 
    3|User   |1    | NULL | Other 

Et ce que je veux faire est:

User.find(1).address(:second) 

qui doit retourner <Address street:"Bar">,

User.find(1).address 

qui devrait revenir <Address street:"Other">, mais User.find(1).addresses devrait retourner la collection d'objets.

Je travaille avec un morceau de code pour ajouter le comportement d'adresse à mes modèles:

module Ext::Models::Addressable 

def self.included(mod) 
    super 
    mod.class_eval do 
     def self.acts_as_addressable   
     include InstanceMethods 

     # Use has_many :delete_all for better performance 
     has_many :addresses, :as => :addressable, :dependent => :delete_all 
     has_one :address, :as => :addressable 
     end 
    end 
end 

module InstanceMethods 
      # I tried with this, but this doesn't even allow me to start rails becauses raises "there is no address method" 
    def address_with_type(type = nil) 
     if type 
      self.addresses.find(:first, :conditions => ["type = ?", type.to_s]) 
     else 
      address_without_type 
     end 
    end 
    alias_method_chain :address, :type 
end 
end 

J'utilise Rails et Ruby 1.9.2 2.3.14.

Si cela est possible, j'aimerais aussi savoir quelle est la meilleure façon de créer de nouvelles adresses pour un modèle donné (disons User).

Merci d'avance.

Solution

Je PRECISEE toutes les possibilités, et actuellement en projet, il n'y a que deux types d'adresses. J'ai été capable de simplifier beaucoup mon approche. Actuellement, mon self.included ressemble:

has_many :addresses, :as => :addressable, :dependent => :delete_all 
has_one :address, :as => :addressable, :conditions => {:type => nil} 
has_one :foo_address, :class_name => 'Address', :as => :addressable, :conditions => {:type => "foo"} 

Et maintenant, je suis en mesure de construire de nouveaux objets comme celui-ci: user.build_address(:street => "abc") et user.build_foo_address(:street => "def"), ce qui est exacly ce que je dois.

Répondre

0

Je serais un peu prudent sur la substitution de comportement par défaut et attendu de cette façon. Y at-il une raison que vous ne pouvez pas laisser user.address être?

Je ne suis pas sûr de ce que les problèmes que vous résolvez mais peut-être que vous pourriez faire quelque chose comme:

class User < ActiveRecord::Base 
    has_many :addresses, :as => :addressable, :dependent => :delete_all 

    def address(only_type = "primary") 
    addresses.find_first("type" => only_type) 
    end 

    def address=(addr) 
    addresses.delete address 
    addresses << addr.update_attribute("type", "primary") 
    end 

    def build_address(attr) 
    addresses.delete address 
    addresses.build attr.merge("type" => "primary") 
    end 

    def create_address(attr) 
    addresses.delete address 
    addresses.create attr.merge("type" => "primary") 
    end 
end 

Je ne l'ai pas testé ce code et je ne suis pas familier avec 2 rails plus si il suffit de l'utiliser comme source d'inspiration. Vous pouvez l'inclure dans des méta pour le moduler. Btw, si vous utilisez "type" vous obtenez STI, pas sûr si c'est ce que vous voulez.

+0

Merci pour votre réponse, mais j'ai réussi à résoudre le problème par une approche différente. J'ai mis à jour ma question avec un nouveau code. – blid

Questions connexes