How can I have a single helper work on different models passed to it?
I am probably going to need to refactor in two steps since I'm still developing the project and learning the use-cases as I go along since it is to scratch my own itch. I have three models: Letters, Calls, Emails. They have some similarilty, but I anticipate they also will have some different attributes as you can tell from their description.
Ideally I could refactor them as Events, with a type as Letters, Calls, Emails, but didn't know how to extend subclasses.
My immediate need is this: I have a helper which checks on the status of whether an email (for example) was sent to a specific contact:
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
end
end
I realized that I, of course, want to know the status for whether a call was made to a contact as well, so I wrote:
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 @contact_call.status
end
end
I would love to be able to just have a single helper show_status where I can say show_status(contact,call) or show_status(contact,email) and it would know whether to look for the object @contact_call or @contact_email.
Yes, it would be easier if it were just @contact_event, but I want to do a small refactoring while I get the program up and running, and this would make the ability to do a history for a given contact much easier.
Thanks!
NOTE: Current开发者_C百科ly I have status as an attribute of contact_email, contact_call, etc. Contact_email only gets created when the email is sent, so there is not contact_email if an email hasn't been sent, and I need to know that the status is "unsent"...
Assuming from the example, that your associations look like this:
class Contact
has_many :emails, :through => :contact_emails
has_many :calls, :through => :contact_calls
end
and status is an attribute on ContactEmail / ContactCall, but you need a status for Email / Call object, then (based on Kandada answer here):
class Contact
def event_status(event)
event_type = event.class.name
foreign_key = ("%s_id" % event_type.downcase).to_sym
assoc = "Contact#{event_type}".tableize
contact_event = send(:assoc).first(:conditions => {foreign_key => event.id})
contact_event.try(:status)
end
end
You can move the helper to the Contact
model.
class Contact < ActiveRecord::Base
has_many :contact_emails
has_many :contact_calls
has_many :contact_letters
def event_status event
assoc_name = "Contact#{event.class.name}".pluralize.underscore
foreign_key = "%s_id" % event.class.name.underscore
ce = send(assoc_name).first(:conditions => {foreign_key => event.id})
ce ? ce.status : nil
end
end
Now you can get the status as follows:
contact.event_status(email1)
contact.event_status(letter2)
contact.event_status(call12)
This alleviates the need for different helpers. One method to address different events.
Since you already have show_call_status and show_email_status, you can write a third show_letter_status.
Then use this:
def show_status(contact, call_or_email_or_letter)
model_name = call_or_email_or_letter.class.name.tableize.singularize
send "show_#{model_name}_status", contact, call_or_email_or_letter
end
精彩评论