如何在一组不同的模型中找到属性值的.max?

时间:2010-05-15 23:43:35

标签: ruby-on-rails sorting max

每个人:我也很乐意直接重构我发现的重复性,但是要给出一个如何工作的基线....

我为每个联系人提供一个广告系列,其中包含三种类型的模型:电子邮件,通话和信函。

当为特定联系人执行电子邮件(呼叫或信件)时,我有一个Contact_Email(_or_Call_or_Letter),它同时属于联系人和模型(Email_or_Call_or_Letter)。

每个Contact_Email例如配对都有:date_sent属性。每个Contact_Call和Contact_Letter都是如此。

如何找到最新的所有内容?

以下是我编写的代码,可以找到最新的电子邮件和我的调查结果重新输入Call和Letter的类似代码,但后来又坚持如何对所有这些代码执行.max:

  def last_email(contact)
    #get campaign the contact belongs to
    @campaign = Campaign.find_by_id(contact.campaign_id)

    @last_email = ContactEmail.find(:last, 
                        :conditions => "contact_id = #{contact.id}",
                        :order => "date_sent DESC")

    @last_call = ContactCall.find(:last, 
                        :conditions => "contact_id = #{contact.id}",
                        :order => "date_sent DESC")

    @last_letter = ContactLetter.find(:last, 
                        :conditions => "contact_id = #{contact.id}",
                        :order => "date_sent DESC")

    # how do I get the latest of all of these to display?

    @email_template = Email.find_by_id(@last_email.email_id)

    if @last_email.nil?
      return "no email sent"
    else
      return @last_email.date_sent.to_s(:long) + link_to('email was sent', @email_template)
    end
  end

问题1:凭借我所拥有的,我如何有效地找到@last_event,因为我可以找到每个联系人的最后一封电子邮件,最后一个电话和最后一封信?

问题2:如何删除我必须为每个模型编写的重复代码?

2 个答案:

答案 0 :(得分:1)

您是否在has_many中设置Contact个关联,参考其他模型?类似的东西:

class Contact < ActiveRecord::Base
  has_many :contact_emails
  has_many :contact_calls
  has_many :contact_letters
end

如果有,您可以在last_event模型上创建Contact方法:

def latest_event
  [contact_emails, contact_calls, contact_letters].map do |assoc|
    assoc.first(:order => 'date_sent DESC')
  end.compact.sort_by { |e| e.date_sent }.last
end

处理nil

使用latest_event方法时,如果没有关联记录,您将获得nil。有几种方法可以解决这个问题。第一个是先检查nil,例如:

contact.latest_event && contact.latest_event.date_sent

在Rails / Ruby的后期版本中,你也可以使用Object#try,如果它存在,它将调用该方法:

contact.latest_event.try(:date_sent)

我不想使用它,因为它不检查nil,但仅当对象可以响应方法时。如果您希望nil,如果对象是nil但是正在调用nil本身响应的方法,则会导致一些有趣的错误。

最后,我对简单案例的首选方法是使用提供Object#andand的{​​{3}} gem。这大大缩短了上述安全案例,并多次保存latest_event次呼叫:

contact.latest_event.andand.date_sent

date_sentnil和你。

对于调用to_s(:long)的示例用法,您可以使用&&andand

contact.latest_event.andand.date_sent.andand.to_s(:long)

contact.latest_event && contact.latest_event.date_sent.to_s(:long)

如果date_sent本身可能是nil,则第一个更安全。不使用andand,可以写成:

contact.latest_event &&
  contact.latest_event.date_sent &&
  contact.latest_event.date_sent.to_s(:long)
在我看来,这是相当复杂和笨拙的。我建议调查andand

答案 1 :(得分:0)

问题1:

只做

@last_event = [@last_letter, @last_email, @last_call].sort_by{|m| m.date_sent}.first

问题2:

这更有趣。这种情况取决于模型的确切外观,但您可能需要考虑此类方案的单表继承。