我怎么能干这个代码并清理我的模型?

Shp*_*ord 1 refactoring ruby-on-rails dry ruby-on-rails-3

我有一个Number模型的以下两种方法.

def track
  number = sanitize(tracking)

  case determine_type(number)
  when 'UPS'
    tracker = ups.track(:tracking_number => number)
    self.carrier              = Carrier.where(:name => 'UPS').first
    self.service              = tracker.service_type
    self.destination_country  = tracker.destination_country
    self.destination_state    = tracker.destination_state
    self.destination_city     = tracker.destination_city
    self.origin_country       = tracker.origin_country
    self.origin_state         = tracker.origin_state
    self.origin_city          = tracker.origin_city
    self.signature            = tracker.signature_name
    self.scheduled_delivery   = tracker.scheduled_delivery_date
    self.weight               = tracker.weight

    tracker.events.each do |event|
      new_event             = Event.new
      new_event.number      = self
      new_event.city        = event.city
      new_event.state       = event.state
      new_event.postalcode  = event.postal_code if event.postal_code
      new_event.country     = event.country
      new_event.status      = event.name
      new_event.status_code = event.type
      new_event.occured_at  = event.occurred_at

      new_event.save
    end
  end

  save
end

def update_number

  case determine_type(number)
  when 'UPS'
    tracker = ups.track(:tracking_number => tracking)
    self.carrier              = Carrier.where(:name => 'UPS').first
    self.service              = tracker.service_type
    self.destination_country  = tracker.destination_country
    self.destination_state    = tracker.destination_state
    self.destination_city     = tracker.destination_city
    self.origin_country       = tracker.origin_country
    self.origin_state         = tracker.origin_state
    self.origin_city          = tracker.origin_city
    self.signature            = tracker.signature_name
    self.scheduled_delivery   = tracker.scheduled_delivery_date
    self.weight               = tracker.weight

    last_event = self.events.ordered.first.occured_at

    tracker.events.each do |event|
      if last_event and (event.occurred_at > last_event)
        new_event             = Event.new
        new_event.number      = self
        new_event.city        = event.city
        new_event.state       = event.state
        new_event.postalcode  = event.postal_code if event.postal_code
        new_event.country     = event.country
        new_event.status      = event.name
        new_event.status_code = event.type
        new_event.occured_at  = event.occurred_at

        new_event.save
      end
    end
  end
  save
end
Run Code Online (Sandbox Code Playgroud)

如您所见,许多代码都是重复的.当我开始添加十几个其他运营商(联邦快递,USPS,DHL等)时,问题就变成......我的Number模型变得庞大而且毛茸茸.

track和之间的唯一真正区别update_number是,update_number作为if事件的比较,检查来自运营商的事件是否比我在数据库中存储的最新事件更新,使用该if last_event and (event.occurred_at > last_event)行.

那么我该如何清理这些代码,这样我的模型就不会那么胖呢?

rto*_*res 5

我建议的几件事:

  1. 看看战略模式,即使Ruby没有接口,但它会给你一些关于如何更好地设计这个功能的想法(谷歌的战略模式为Ruby找到替代品).基本上,您希望有单独的类来处理switch case语句并在运行时调用适当的类.
  2. 尝试将跟踪器处理代码与事件处理代码分开.例如,我会考虑将每个跟踪器事件的事件创建/保存逻辑移动到一个单独的类(如果有的话,甚至移动到Tracker实体).

希望这可以帮助.