Rails正确使用除非与运算符一起使用

时间:2014-08-03 12:35:08

标签: ruby ruby-on-rails-3 operators

我有一个Rails 3.2.18应用程序,我试图通过以下方式将Twilio通知发送到医疗手机的更新操作:

 unless @call.call_status == "close" && @call.unit_ids.empty?

如果呼叫状态设置为关闭,则表示呼叫已关闭,并且不需要通过ActionMailer或我的send_sms私有方法发送通知。此外,如果unit_ids为空(单位数组),也不会发出邮件或短信警报。

这里发生了什么。如果呼叫是打开的并且我没有分配单位(unit_ids为空)并且我更新了呼叫,它将绕过动作邮件程序,但它仍然尝试触发send_sms并为@ call.units.first.incharge引发一个nilclass异常因为阵列中不存在军医/充气器。现在如果我在第一个中嵌入另一个除非语句(参见第二个示例工作,如果call_status == close和unit_ids.empty,它将不会触发邮件程序或send_sms?

calls_controller.rb(不工作)

def update
    parse_times!
    @call = Call.find(params[:id])

    respond_to do |format|
      if @call.update_attributes(params[:call])
        unless (@call.call_status == "close" && @call.unit_ids.empty?)
          send_sms

        @call.send_mail(:update_call)

        end
        format.html { redirect_to @call, notice: "Call #{@call.incident_number} was successfully updated.".html_safe }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @call.errors, status: :unprocessable_entity }
      end
    end
  end

private
def send_sms
    account_sid = 'AACCCCCC'
    auth_token = 'ATttttt'
    @client = Twilio::REST::Client.new account_sid, auth_token
    @client.account.messages.create(
       :from => '2814084444',
       :to => @call.units.first.incharge.medic_phone,
       :body => "incident_number #{@call.incident_number} patient name #{@call.patient_name}"
      )
    @client.account.messages.create(
      :from => '2814084444',
       :to => @call.units.first.attendant.medic_phone,
       :body => "incident_number #{@call.incident_number} patient name #{@call.patient_name}"
      )
  end
end

calls_controller.rb(工作)

def update
    parse_times!
    @call = Call.find(params[:id])

    respond_to do |format|
      if @call.update_attributes(params[:call])
        unless @call.call_status == "close"
          unless  @call.unit_ids.empty?
          send_sms
        end

        @call.send_mail(:update_call)

        end
        format.html { redirect_to @call, notice: "Call #{@call.incident_number} was successfully updated.".html_safe }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @call.errors, status: :unprocessable_entity }
      end
    end
  end

  def send_sms
    account_sid = 'ACCCCCC'
    auth_token = 'atttt'
    @client = Twilio::REST::Client.new account_sid, auth_token
    @client.account.messages.create(
       :from => '2814084444',
       :to => @call.units.first.incharge.medic_phone,
       :body => "incident_number #{@call.incident_number} patient name #{@call.patient_name}"
      )
    @client.account.messages.create(
      :from => '2814084444',
       :to => @call.units.first.attendant.medic_phone,
       :body => "incident_number #{@call.incident_number} patient name #{@call.patient_name}"
      )
  end

将除非语句嵌套为正确的方法,或者我能以某种方式将&&运营商除非。也许我的语法在第一个(非工作)示例中是错误的。我在这里显然遗漏了一些东西,所以提供的任何帮助都会受到赞赏。

更新:08/03 / 14-08:03

似乎如果我使用||运算符我不会引发nilclass异常,并且mailer和send_sms会触发,除非调用状态为close或者调用unit_ids为空。

 unless (@call.call_status == "close" || @call.unit_ids.empty?)
          send_sms
          @call.send_mail(:update_call)
        end

这是否有意义,或者我应该尝试使用&&操作

1 个答案:

答案 0 :(得分:3)

正如您所正确观察到的,嵌套两个条件等同于将条件与&&组合。由于unless ...if ! ...相同("如果不是"),您也可以写:

if !(@call.call_status == "close") && !(@call.unit_ids.empty?)
  # ...
end

De Morgan's Law告诉我们!a && !b!(a || b)相同:

if !(@call.call_status == "close" || @call.unit_ids.empty?)
  # ...
end

当然,我们可以用if !代替unless

unless @call.call_status == "close" || @call.unit_ids.empty?
  # ...
end

虽然我建议您使用复杂条件的if,因为这通常更容易阅读和理解。我们再次开始消除unless

if !(@call.call_status == "close") && !(@call.unit_ids.empty?)
  # ...
end

然后,我们重新制定&&左右部分,以便不再需要!。在这种情况下,我们可以将==更改为!=。我们也可以将empty?更改为any?,但如果数组仅包含nil和/或false值,则会出现问题。如果您确定这种情况从未发生过,那么您也可以使用x.any?代替! x.empty?

if @call.call_status != "close" && !@call.unit_ids.empty?
  # ...
end

# If you are 100% sure that @call.unit_ids _never_ contains nil or false values,
# you can use x.any? instead of !x.empty?

if @call.call_status != "close" && @call.unit_ids.any?
  # ...
end