2010-08-20 2 views
2

L'objectif final est de créer un assistant trouvé à la fin appelé show_status (contact, événement).Comment puis-je faire ce code (assistant) DRY dans Rails où j'appelle modèles similaires?

L'événement peut être n'importe quel objet, Email, Letter, etc. La combinaison d'un modèle d'e-mail envoyé à un contact est un enregistrement spécifique ContactEmail. Parce que chaque événement a un modèle correspondant différent, je dois faire le .find sur, j'ai la duplication. Il doit y avoir un meilleur moyen!

def show_email_status(contact, email) 

    @contact_email = ContactEmail.find(:first, :conditions => {:contact_id => contact.id, :email_id => email.id }) 

    if ! @contact_email.nil? 
     return @contact_email.status.to_s + " (" + @contact_email.date_sent.to_s + ")" 
    else 
     return "no status" 
    end 
    end 

    def show_call_status(contact, call) 

    @contact_call = ContactCall.find(:first, :conditions => {:contact_id => contact.id, 
                   :call_id => call.id }) 
    if ! @contact_call.nil? 
     return "sent " + @contact_call.date_sent.to_s(:long) 
    else 
     return "no status" 
    end 
    end 

    def show_letter_status(contact, letter) 

    @contact_letter = ContactLetter.find(:first, :conditions => {:contact_id => contact.id, 
                   :letter_id => letter.id }) 
    if ! @contact_letter.nil? 
     return "sent " + @contact_letter.date_sent.to_s(:long) 
    else 
     return "no status" 
    end 
    end 

    def show_voicemail_status(contact, voicemail) 

    @contact_event = ContactEvent.find(:first, :conditions => {:contact_id => contact.id, 
                   :event_id => voicemail.id, 
                   :type => "voicemail"}) 
    if ! @contact_event.nil? 
     return "sent " + @contact_event.date_sent.to_s(:long) 
    else 
     return "no status" 
    end 
    end 

    def show_postalcard_status(contact, postalcard) 

    @contact_postalcard = ContactPostalcard.find(:first, :conditions => {:contact_id => contact.id, 
                   :postalcard_id => postalcard.id }) 
    if ! @contact_postalcard.nil? 
     return "sent " + @contact_postalcard.date_sent.to_s(:long) 
    else 
     return "no status" 
    end 
    end 

    def show_status(contact, call_or_email_or_letter_or_voicemail) 

    model_name = call_or_email_or_letter_or_voicemail.class.name.tableize.singularize 
    send "show_#{model_name}_status", contact, call_or_email_or_letter_or_voicemail 
    end 

Répondre

4

Essayez ceci:

def show_status(contact, target) 
    target_class= target.class.name 
    target_id = target_class.foreign_key.to_sym 
    klass  = "Contact#{target_class}".constantize 

    r = klass.first(:conditions => {:contact_id => contact.id, 
       target_id => target.id}) 

    return "no status" unless r 

    # If you want to treat ContactEmail differently then use the next line 
    #return "#{r.status} (#{r.date_sent})" if target.is_a?(ContactEmail) 

    "sent (#{r.date_sent.to_s(:long)})" 
end 

Utilisation:

contact = Contact.find(..) 
email = Email.find(..) 
letter = Letter.find(..) 
call = Call.find(..) 

show_status(contact, email) 
show_status(contact, letter) 
show_status(contact, call) 

Modifier 1

Une meilleure approche est d'ajouter une méthode pour le modèle de contact.

class Contact < ActiveRecord::Base 
    # assuming you have following associations 
    has_many :contact_emails 
    has_many :contact_calls 
    has_many :contact_letters 
    # etc.. 


    def communication_status target 
    target_class= target.class.name 
    target_id = target_class.foreign_key.to_sym 
    assoc_name = "contact_#{target_class.tableize}" 
    r = send(assoc_name).send("find_by_#{target_id}", target.id) 
    return "no status" unless r 
    "sent (#{r.date_sent.to_s(:long)})" 
    end 

end 

Utilisation:

contact = Contact.find(..) 
email = Email.find(..) 
letter = Letter.find(..) 
call = Call.find(..) 

contact.communication_status(email) 
contact.communication_status(email) 
contact.communication_status(letter) 
contact.communication_status(call) 
+0

Ah, c'est intéressant ... J'essayais de penser à la façon de faire cela, mais vous passez l'actif spécifique dans ... cela pourrait le faire ... laissez-moi jouer avec elle .... – Angela

+0

Cette deuxième méthode. ... où cherche-t-il le contact_id correspondant? On dirait qu'il passe par la table de contact_emails (par exemple) et qu'il cherche juste sur l'email.id ... correspondant ... mais qu'en est-il de contact_id? – Angela

+0

Il est implicite car nous utilisons une recherche dans les associations. Si vous vérifiez le fichier journal, vous verrez que SQL exécuté a le contact_id. –

0

Combiner tous les modèles en un seul et un attribut qui définit le type de médias tels que le courrier électronique, téléphone, papier, etc au lieu d'avoir un modèle différent pour chaque type.

Ensuite, vous pouvez passer l'objet qui aura un type de média comme seul paramètre et avec cet objet vous pouvez accéder au contact avec media_object.contact et le type de média avec media_object.media_type que vous pouvez utiliser pour rechercher l'utilisateur et le type de média .

def show_media_object(mo) 
    options = {conditions = ['media_type = ? AND contact_id = ?', 
           mo.media_type, mo.contact_id]} 
    if @media_type = MediaObject.find(:first, options) 
     "sent " + @mo.updated_at 
    else 
     "Sorry, your SOL" 
    end 
end 
+0

Je pensais le faire en tant que STI, mais les contrôleurs sont si différents, par souci de simplicité, je voulais les garder comme des modèles distincts. – Angela

Questions connexes