Rubocop声称有太多“如果”的陈述

时间:2017-12-28 02:14:19

标签: ruby rubocop

我正在使用Rubocop测量我的Rails应用程序的代码。这是我的代码:

def ratings_treatment
    if @rating.advertise_id
      advertise = Advertise.find(advertise_id)
      rating_average(advertise)
    elsif @rating.product_id
      product = Product.find(product_id)
      rating_average(product)
    elsif @rating.combo_id
      combo = Combo.find(combo_id)
      rating_average(combo)
    else
      establishment = Establishment.find(@rating.establishment_id)
      rating_average(establishment)
    end   
end

它没有通过关于if的测试。据称,if语句太多了。

我想过将代码拆分成一些检查器方法,但是想知道是否有更好的方法来获得良好的指标并仍然编写好的代码。

3 个答案:

答案 0 :(得分:2)

我认为您可以使用switch语句为rating_average分配参数:

def ratings_treatment
  average = case
            when @rating.advertise_id then Advertise.find(advertise_id)
            when @rating.product_id   then Product.find(product_id)
            when @rating.combo_id     then Combo.find(combo_id)
            else Establishment.find(@rating.establishment_id)
            end
  rating_average average
end

虽然Rubocop会抱怨

  

Style / EmptyCaseCondition:不要使用空案例条件,而是使用   一个if表达式

您还可以简化if表达式:

def ratings_treatment
  average = if @rating.advertise_id
              Advertise.find advertise_id
            elsif @rating.product_id
              Product.find product_id
            elsif @rating.combo_id
              Combo.find combo_id
            else
              Establishment.find @rating.establishment_id
            end
  rating_average average
end

答案 1 :(得分:2)

如果您的@rating设置了关联,那么您可以说:

def ratings_treatment
  obj = @rating.advertise || @rating.product || @rating.combo || @rating.establishment
  rating_average(obj)
end

甚至:

def ratings_treatment
  rating_average(@rating.advertise || @rating.product || @rating.combo || @rating.establishment)
end

或者可能是某种奇特的东西(而且仅仅是四个分支的过度杀戮):

def ratings_treatment
  rating_average(
    %w[advertise product combo establishment].lazy.map { |m| @rating.send(m) }.find(&:present?)
  )
end

或者甚至可能:

def rated_object
  to_result = ->(m) { @rating.send(m) }
  %w[advertise product combo establishment]
    .lazy
    .map(&to_result)
    .find(&:present?)
end

def ratings_treatment
  rating_average(rated_object)
end  

我甚至建议上面的rated_object方法确实应该是@rating上的方法。您应该可以询问评级的评级,而无需手动旋转所有可能性。

你甚至可以将lazy.map...内容修补到Enumerable,如果你想要Enumerable中表现得像e.m1 || e.m2 || e.m3 || ...(在那里,那样做)的东西一直到短路。

我不知道Rubocop会对这些恶作剧做些什么。

答案 2 :(得分:0)

这是一种典型的违反风格的案例,它具有更深层次的根本原因,即建模问题。在您的情况下,看起来您实际想要实现的是polymorphic association。如果您将Rating更改为:

# app/models/rating.rb
class Rating < ApplicationRecord
  belongs_to :rateable, polymorphic: true
end

您可以将Rating与任意数量的内容相关联,只需将其添加到关联的另一端即可:

# app/models/product.rb
class Product < ApplicationRecord
  has_many :pictures, as: :rateable
end

您的原始方法,如果它甚至需要,将变为:

def ratings_treatment
  rating_average(@rating.rateable) 
end