I have a Model called Report, and this model contains a column report_type which stores a string value. A Report is associated to a User. Each type of Report is worth a point value. I have a model concern that I want to use to loop through a User's reports and calculate that users points. I have a constant in the concern that knows the report_type point mapping, but am struggling to realize the most efficient way to loop through a user's reports and calculate their points. This is what I have thus far. The points method at the bottom is where I am unsure of how to proceed. I suspect there is a simple method I can use instead of looping through the object verbosely each time points is called.
I am also open to architecting this differently if there is an overall better approach.
module PointsConcern
extend ActiveSupport::Concern
included do
before_action :set_current_user
end
REP_TYPES = {
PUSH_UP => 1,
AIR_SQUAT = >1,
BAR_DIP => 1,
BENCH_DIP => 0.5,
CHIN_UP => 1.5,
PULL_UP => 2,
HANDSTAND_PUSH_UP => 3,
BACK_EXTENSIONS => 1,
MOUNTAIN_CLIMBER => 0.5,
BURPEE => 1.5
}
def set_current_user
if session[:user_id]
@current_user = User.find(session[:user_id])
end
end
def reports
@reports = Reports.where(user_id: @current_user.user_id)
end
def points
points = 0
@reports.each do |r|
r.report_type # What do?
end
end
end
CodePudding user response:
I'd start by making it so that a report itself can tell how many points it's worth. You can do this either using single-table inheritance, or by adding a mapping inside the base Report class. See example below:
class Report
def points
case report_type
when "push_up" then 1
when "air_squat" then 1
when "bar_dip" then 1
when "bench_dip" then 0.5
when "chin_up" then 1.5
when "pull_up" then 2
when "handstand_push_up" then 3
when "back_extensions" then 1,
when "mountain_climber" then 0.5
when "burpee" then 1.5
end
end
You could also use a hash where the report type is the key and the points the value, with the same result.
Now, summing the points is trivial:
Report.where(user_id: @current_user.user_id).sum(&:points)
CodePudding user response:
I recommend you to redesign it in the following way:
- create 2 enums in the Report model
report_typeas string &report_scoreas float, enums should look like this:
enum report_type: {
PUSH_UP: 'PUSH_UP',
AIR_SQUAT: 'AIR_SQUAT',
BAR_DIP: 'BAR_DIP',
...
}
enum report_score: {
PUSH_UP_SCORE: 1,
AIR_SQUAT_SCORE: 1,
BAR_DIP_SCORE: 1,
...
}
In this case, to create a new record you need to do the following
Report.create(report_type: params[:report_type], report_score: "#{params[:report_type]}_SCORE")
And to calculate the score of user's reports, you need to do something like that:
user.reports.sum(:report_score)
