如何在 Rails 中调用类似模型时使此代码(帮助程序)干燥?

发布于 2024-09-15 13:59:38 字数 2362 浏览 10 评论 0原文

最终目标是创建一个名为 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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凉薄对峙 2024-09-22 13:59:38

试试这个:

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)

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)
最佳男配角 2024-09-22 13:59:38

将所有这些模型合并为一个,然后拥有一个定义媒体类型(例如电子邮件、电话、纸张等)的属性,而不是为每种类型使用不同的模型。

然后,您可以传递将媒体类型作为唯一参数的对象,并且使用该对象,您可以使用 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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文