2010-08-20 2 views
2

Конечной целью является создание помощника, найденного в конце, называемого show_status (контакт, событие).Как я могу сделать этот код (помощник) DRY в Rails, где я звоню в похожие модели?

Событие может быть любым объектом, электронной почтой, письмом и т. Д. Сочетание шаблона электронной почты, отправленного контакту, является конкретной записью ContactEmail. Поскольку у каждого события есть другая соответствующая модель, мне нужно сделать .find, у меня есть дублирование. Должен быть лучший способ!

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 

ответ

4

Попробуйте это:

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 

Использование:

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

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

Edit 1

Лучший подход заключается в добавлении метод контактной модели.

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 

Использование:

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

ах, это интересно ... Я пытался подумать о том, как это сделать, но вы передаете конкретный актив ... это может сделать это ... позвольте мне поиграть с ним .... – Angela

+0

Этот второй метод. ... где он ищет подходящий contact_id? Похоже, что он просматривает таблицу contact_emails (например) и просто выполняет поиск по соответствующему email.id ... но как насчет contact_id? – Angela

+0

Это подразумевается, поскольку мы используем поиск через ассоциации. Если вы проверите файл журнала, вы увидите, что SQL-код имеет контакт_ид. –

0

Объединить все эти модели в одно и то есть атрибут, который определяет тип носителя, такие как электронная почта, телефон, бумага и т.д., вместо того, чтобы иметь другую модель для каждого типа.

Затем вы можете передать объект, который будет иметь тип носителя в качестве единственного параметра, и с этим объектом вы можете получить доступ к контакту с помощью media_object.contact и media_type с media_object.media_type, который вы можете использовать для поиска пользователя и типа носителя ,

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

Я думал, что делать, что, как STI, но контроллеры настолько различны, для простоты, я хотел бы сохранить их как отдельные модели. – Angela

Смежные вопросы