Reputation: 1287
In my limited knowledge I dont know how to write this without passing the volunteer as an argument to the status method. Which normally wouldnt be an issue, except when I need all irregular volunteers. Then I have to loop through Volunteers.all and evaluate each against the status method. I feel like the overhead here is too great.
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
Thanks in advance for helping a noob!
Upvotes: 0
Views: 86
Reputation: 29588
You could also specify it as using @Magnuss' code as a base point
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
This allows more flexibility in my opinion for adding more statuses by just redefining STATUSES
as you see fit.
What this does is find the first result where the number_of_recent_nought_reports
is in a range defined in STATUSES
in the event that it falls outside of any of the ranges ['inactive']
is returned then pop
pulls out just the status.
I also moved the report_month scope to Report
as last_n_months
.
Upvotes: 1
Reputation: 110745
You could write:
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
Upvotes: 0
Reputation: 3743
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
You don't need to pass the volunteer because you are calling the method status on an instance of Volunteer that already has direct access to reports. So the above becomes:
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
Additionally, you are running the count query two times which is not optimal. I suggest:
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
Finally the case returns the matching value so you don't need the returns.
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
There is more but that is a start.
Upvotes: 1
Reputation: 2310
I'd do something like this:
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
Upvotes: 1