Rails - 有更好的方法来写这个吗?寻找重构建议

时间:2015-01-15 18:44:48

标签: ruby-on-rails ruby

在我有限的知识中,我不知道如何在不将志愿者作为状态方法的参数的情况下写出来。这通常不会成为问题,除非我需要所有不规范的志愿者。然后我必须循环遍历Volunteers.all并根据状态方法评估每个。我觉得这里的开销太大了。

Class Volunteer < ActiveRecord::Base

  has_many :reports

  def status(volunteer)
    case
    when volunteer.reports.nought.where(:report_month => Report_range.months(6)).count > 5
        return 'inactive'
    when volunteer.reports.nought.where(:report_month => Report_range.months(6)).count >= 3
        return 'irregular'
    else
        return 'active'
    end
  end
end


class Report < ActiveRecord::Base
  belongs_to :volunteer
  scope :nought, -> {where("hours IS NULL") || where("hours: 0")}
end

module Report_range
  def self.months(range)
   Volunteer.first.reports.order("report_month desc").limit(range).pluck(:report_month)
  end
end

提前感谢您帮助一个菜鸟!

4 个答案:

答案 0 :(得分:1)

def status(volunteer)
  case
  when volunteer.reports.nought.where(:report_month => Report_range.months(6)).count > 5
    return 'inactive'
  when volunteer.reports.nought.where(:report_month => Report_range.months(6)).count >= 3
    return 'irregular'
  else
    return 'active'
  end
end

您不需要通过志愿者,因为您在已经可以直接访问报告的志愿者实例上调用方法状态。所以上面变成了:

def status
  case
  when reports.nought.where(:report_month => Report_range.months(6)).count > 5
    return 'inactive'
  when reports.nought.where(:report_month => Report_range.months(6)).count >= 3
    return 'irregular'
  else
    return 'active'
  end
end

此外,您正在运行两次计数查询,这不是最佳选择。我建议:

def status
  number_of_reports = reports.nought.where(:report_month => Report_range.months(6)).count
  case
  when number_of_reports > 5
    return 'inactive'
  when  number_of_reports >= 3
    return 'irregular'
  else
    return 'active'
  end
end

最后,案例会返回匹配值,因此您不需要返回。

def status
  number_of_reports = reports.nought.where(:report_month => Report_range.months(6)).count
  case
  when number_of_reports > 5
    'inactive'
  when  number_of_reports >= 3
    'irregular'
  else
    'active'
  end
end

还有更多,但这是一个开始。

答案 1 :(得分:1)

我做这样的事情:

class Volunteer < ActiveRecord::Base

  has_many :reports

  def status
    if number_of_recent_nought_reports > 5
      'inactice'
    elsif number_of_recent_nought_reports >= 3
      'irregular'
    else
      'active'
    end
  end

  private

  def number_of_recent_nought_reports
    # You could move the where call to scope in your `Report` class.
    @recent_nought_reports ||= reports.nought.where(:report_month => Report_range.months(6)).count
  end
end

答案 2 :(得分:1)

您也可以将其指定为使用@ Magnuss&#39;代码作为基点

class Volunteer < ActiveRecord::Base

  has_many :reports

  STATUSES = {(0..2) => 'active', (3..5) => 'irregular'}

  def status
    STATUSES.find(->{['inactive']}){|range,_| range === number_of_recent_nought_reports}.pop 
  end

  private

   def number_of_recent_nought_reports
     # You could move the where call to scope in your `Report` class.
     @recent_nought_reports ||= reports.nought.last_n_months(6).count
  end
end

class Report < ActiveRecord::Base
  belongs_to :volunteer
  scope :nought, -> {where("hours IS NULL") || where("hours: 0")}
  scope :last_n_months, ->(months){ where(:report_month => Report_range.months(months)) }
end

通过在您认为合适时重新定义STATUSES,我可以更灵活地添加更多状态。

这样做的第一个结果是number_of_recent_nought_reportsSTATUSES中定义的范围内,如果它超出任何范围['inactive'],则返回pop { {1}}仅提取状态。

我还将report_month范围移至Report last_n_months

答案 3 :(得分:0)

你可以写:

def status(volunteer)
  case volunteer.reports
                .nought
                .where(:report_month => Report_range.months(6))
                .count
  when (6..Float::INFINITY) then 'inactive'
  when (3..5)               then 'irregular'
  else                           'active'
end