处理rails中的多个IF

时间:2014-10-16 19:03:43

标签: ruby-on-rails ruby

我在模型上有以下代码,但是我很想找到一种方法来重构它,使其变得更小,更整洁。我也喜欢只在状态字段实际发生变化的情况下运行它。有人能指出我正确的方向。这是rails 3 BTW。

它的作用是查看名为subscription的模型上的“state”字段,如果它从一个条件更改为另一个条件,则在salesforce中进行更新。我正在寻找一种优化此代码的方法。

  after_save :update_salesforce

  def update_salesforce
    if self.state_changed? && salesforce_client
      salesforce_client.materialize("Opportunity")

      o = Opportunity.find_by_breatheHR_id__c(self.subscriber_id)
      if o
        old_state = self.state_was
        new_state = self.state
        #update salesforce when accounts go active
        if (old_state =='trial' || old_state == 'suspended') && new_state =='active'
          o.update_attribute(:Stage__c, "Active Account")
        end
        #update salesforce when accounts go active
        if old_state =='trial' && new_state =='suspended'
          o.update_attribute(:Stage__c, "Trial Suspended")
        end
        #update salesforce when accounts go active
        if old_state =='active' && new_state =='suspended'
          o.update_attribute(:Stage__c, "Account Suspended")
        end
        #update salesforce when accounts go active
        if old_state =='active' && new_state =='inactive'
          o.update_attribute(:Stage__c, "Account Cancelled")
        end
        #update salesforce when accounts go active
        if old_state =='trial' && new_state =='inactive'
          o.update_attribute(:Stage__c, "Trial Cancelled")
        end
      end_of_day
    end
  end

仅运行它,我试过

after_save :update_salesforce, :if => self.state_changed?

但此时并不承认“自我”。

2 个答案:

答案 0 :(得分:1)

以下是您可以应用的几种重构:

删除不必要的self

每次只需要设置值时,您不需要编写self,否则Ruby将创建一个局部变量而不是调用setter方法。在您的情况下,self的所有出现都是多余的,只是添加噪音。

拼合嵌套条件

您需要摆脱不必要的嵌套,它使代码更容易阅读和理解。一般来说,当前提条件失败时,您可以提前返回。例如:

def update_salesforce
  if state_changed? && salesforce_client
    o = Opportunity.find_by_breatheHR_id__c(subscriber_id)
    if o
      # perform hard work
    end
  end
end

# becomes

def update_salesforce
  return unless state_changed? && salesforce_client

  o = Opportunity.find_by_breatheHR_id__c(subscriber_id)
  return unless o

  # perform hard work
end

使用ActiveRecord的:if选项

在检查状态是否已更改的特殊情况下,您可以使用:if回调中的after_save选项。你非常接近,但你需要提供方法名称作为符号,或使用proc。对于像这样的简单情况,您可以使用符号形式:

after_save :update_salesforce, :if => :state_changed?

使用语句修饰符

另一种情况也很特殊,因为你可以使用语句修饰符return来标记行尾的or。这实际上是or的预期用途,而您应该始终使用||进行布尔运算。转型是

x = do_something
return unless x

# becomes

x = do_something or return

用散列访问替换重复条件

当您查看该方法时,大多数行会一遍又一遍地重复,只有轻微的变化。您可以做的是将状态转换逻辑提取到单独的方法中。在这种方法中,你可以拉出一个技巧并将变化的状态放入一个哈希值,从中选择适当的值。键是表示转换的数组,值是Stage__c字段的新值。返回nil时,不得更新Stage__c。例如:

def new_stage_from_state_transition(old_state, new_state)
  {
    ['suspended', 'active'   ] => 'Active Account',
    ['trial'    , 'active'   ] => 'Active Account',
    ['trial'    , 'suspended'] => 'Trial Suspended',
    ['active'   , 'suspended'] => 'Account Suspended',
    ['active'   , 'inactive' ] => 'Account Cancelled',
    ['trial'    , 'inactive' ] => 'Trial Cancelled'
  }[[old_state, new_state]]
end

把所有东西放在一起

所有这些都会产生更清晰,重复性更低的代码:

after_save :update_salesforce, :if => :state_changed?

def update_salesforce
  return unless salesforce_client
  o = Opportunity.find_by_breatheHR_id__c(subscriber_id) or return
  new_stage = new_stage_from_state_transition(state_was, state) or return
  o.update_attribute(:Stage__c, new_stage)
end

def new_stage_from_state_transition(old_state, new_state)
  {
    ['suspended', 'active'   ] => 'Active Account',
    ['trial'    , 'active'   ] => 'Active Account',
    ['trial'    , 'suspended'] => 'Trial Suspended',
    ['active'   , 'suspended'] => 'Account Suspended',
    ['active'   , 'inactive' ] => 'Account Cancelled',
    ['trial'    , 'inactive' ] => 'Trial Cancelled'
  }[[old_state, new_state]]
end

答案 1 :(得分:0)

#update salesforce when accounts go active
if new_state =='active'
  o.update_attribute(:Stage__c, "Active Account")
else
  what = old_state == 'active' ? "Account" : "Trial"
  change = new_state == 'inactive' ? "Canceled" : "Suspended"
  o.update_attribute(:Stage__c, "#{what} #{change}" )
end