如何在我调用类似模型的Rails中创建此代码(帮助程序)DRY?

时间:2010-08-20 03:29:13

标签: ruby-on-rails models dry helper

最终目标是创建一个名为show_status(contact,event)的帮助器。

事件可以是任何对象,电子邮件,信件等。发送给联系人的电子邮件模板的组合是特定记录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

2 个答案:

答案 0 :(得分: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)

修改1

更好的方法是向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

用法:

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)

答案 1 :(得分:0)

将所有这些模型合并为一个,然后有一个属性来定义媒体类型,如电子邮件,电话,纸张等,而不是为每种类型设置不同的模型。

然后您可以将具有媒体类型的对象作为唯一参数传递,使用该对象,您可以访问media_object.contact的联系人以及可以用于搜索的media_object.media_type的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