views:

63

answers:

2

The end goal is to create a helper found at the end called show_status(contact,event).

Event can be any object, Email, Letter, etcetera. The combination of an Email template sent to a Contact is a specific record ContactEmail. Because each event has a different corresponding Model I need to do the .find on, I have duplication. There must be a better way!

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
A: 

Combine all those models into one and then have an attribute that defines the type of media such as email, phone, paper, etc instead of having a different model for each type.

Then you can pass the object which will have a media type as the only parameter and with that object you can access the contact with media_object.contact and the media_type with media_object.media_type which you can use to search for the user and the type of media.

 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
Sam
I thought of doing that as STI but the controllers are so different, for simplicity sake, I wanted to keep them as separate models.
Angela
+4  A: 

Try this:

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

Usage:

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

A better approach is to add a method to the Contact model.

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

Usage:

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)
KandadaBoggu
ah, that's interesting...I was trying to think about how to do that, but you pass the specific asset in...this might do it...let me play with it....
Angela
This second method....where is it searching for the matching contact_id? It looks like it is going through the table of contact_emails (for example) and just searching on the corresponding email.id...but what about contact_id?
Angela
It is implicit as we are using a lookup through associations. If you check the log file, you will see that SQL executed has the contact_id.
KandadaBoggu