【问题标题】:How can I make this code (helper) DRY in Rails where I am calling similar Models?如何在我调用类似模型的 Rails 中使此代码(帮助程序)干燥?
【发布时间】:2010-08-20 03:29:12
【问题描述】:

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

【问题讨论】:

    标签: ruby-on-rails models dry helper


    【解决方案1】:

    试试这个:

    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)
    

    【讨论】:

    • 啊,这很有趣...我正试图考虑如何做到这一点,但是您将特定资产传入...这可能会做到...让我玩它.. ..
    • 第二种方法....它在哪里搜索匹配的contact_id?看起来它正在遍历contact_emails 表(例如)并仅搜索相应的email.id ......但是contact_id 呢?
    • 这是隐含的,因为我们使用的是通过关联进行查找。如果您检查日志文件,您将看到执行的 SQL 具有contact_id。
    【解决方案2】:

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

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

    【讨论】:

    • 我曾想过将其作为 STI,但控制器是如此不同,为简单起见,我想将它们保留为单独的模型。
    猜你喜欢
    • 1970-01-01
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多