我试图避免因NilClass而导致的NoMethod错误。我的代码如下所示:
@branded, @nonbranded, @unknown, @affiliate, @social, @referral, @paid, @direct, @email = [], [], [], [], [], [], [], [], []
count = 0
while count < 6
date = SDLW + count
#TODO There has to be a better way than this.
branded_check = Metric.first(start_date: date, end_date: date, source: 'branded')
nonbranded_check = Metric.first(start_date: date, end_date: date, source: 'nonbranded')
unknown_check = Metric.first(start_date: date, end_date: date, source: 'unknown')
affiliate_check = Metric.first(start_date: date, end_date: date, source: 'affiliate')
social_check = Metric.first(start_date: date, end_date: date, source: 'social')
referral_check = Metric.first(start_date: date, end_date: date, source: 'referral')
paid_check = Metric.first(start_date: date, end_date: date, source: 'paid')
direct_check = Metric.first(start_date: date, end_date: date, source: 'direct')
email_check = Metric.first(start_date: date, end_date: date, source: 'email')
branded_check = branded_check.nil? ? 0 : branded_check.visits
nonbranded_check = nonbranded_check.nil? ? 0 : nonbranded_check.visits
unknown_check = unknown_check.nil? ? 0 : unknown_check.visits
affiliate_check = affiliate_check.nil? ? 0 : affiliate_check.visits
social_check = social_check.nil? ? 0 : social_check.visits
referral_check = referral_check.nil? ? 0 : referral_check.visits
paid_check = paid_check.nil? ? 0 : paid_check.visits
direct_check = direct_check.nil? ? 0 : direct_check.visits
email_check = email_check.nil? ? 0 : email_check.visits
@branded << branded_check
@nonbranded << nonbranded_check
@unknown << unknown_check
@affiliate << affiliate_check
@social << social_check
@referral << referral_check
@paid << paid_check
@direct << direct_check
@email << email_check
count += 1
end
我确信必须有一种更清洁,更简洁的方法来做到这一点。尽管谷歌搜索和阅读我无法弄清楚。关于如何重构的任何想法都将非常感激。
答案 0 :(得分:3)
当然,创建一种避免重复的方法
def visits(tag, date)
check = Metric.first(start_date: date, end_date: date, source: tag)
check.present? ? check.visits : 0 # or 'check.nil? ? 0 : check.visits' if you prefer
end
在您的方法中
count = 0
while count < 6
date = SDLW + count
@branded << visits('branded', date)
@nonbranded << visits('nonbranded', date)
...
count += 1
end
答案 1 :(得分:2)
让我们在一个块中调用Metric.first
并使用instance_variable_set
设置实例变量。
['branded', 'nonbranded', ...].each do |source|
visits = 0.upto(5).map do |count|
date = SDLW + count
metric = Metric.first(start_date: date, end_date: date, source: source)
if metric.nil? then 0 else metric.visits end
end
instance_variable_set "@#{source}".to_sym, visits
end
答案 2 :(得分:1)
除了其他解决方案之外,while循环可以替换为:
(SDLW...SDLW+6).each do |date|
# date = SDLW + count #This line is superfluous
@branded << visits('branded', date)
#or one of the other solutions
#etc
# count += 1 # remove this line
end
答案 3 :(得分:0)
我只为一个来源做过例如。
@branded, @nonbranded, @unknown, @affiliate, @social, @referral, @paid, @direct, @email = [], [], [], [], [], [], [], [], []
class Metric < ActiveRecord::Base
scope :dates, lambda { |start_date, end_date| where(:start_date => start_date, :end_date => end_date) }
scope :branded, lambda { where(:source => "branded") }
# ... other scopes
end
# ...
6.times do |count|
date = SDLW + count
by_date = Metric.dates(date, date)
@branded << by_date.branded.try(:visits).to_i
# ... other sources
end
<强>更新强>:
使用来自Jan solution和Dave Newton请求的instance_variable_set
想法重构解决方案。
6.times do |count|
date = SDLW + count
[:branded, :nonbranded, :unknown, :affiliate, :social, :referral, :paid, :direct, :email].each do |source|
instance_variable_set :"@#{source}", [] unless instance_variable_get :"@#{source}"
visits = Metric.first(start_date: date, end_date: date, source: source).try(:visits).to_i
instance_variable_set :"@#{source}", instance_variable_get(:"@#{source}").push(visits)
end
end