Reputation: 147
This must be a common need but I can't seem to find a definitive answer on the most rubyesque way. I need to create a fairly complex algorithm to dynamically calculate course grades in a rails 4.1 app.
Specifically, I have a model, "course", and whenever an instance of it is displayed in the view, I want to dynamically calculate the current grade (a decimal value, calculated from many course.field values) and display it as a letter value using a switch/case. My assumption was that I could do this in the controller (but it almost seems like it's complex enough to warrant it's own -- module? In C++ I would create a class). At the same time, since it is created dynamically, it seemed like bad form to create a current_grade field for it in the model, so it's not one I can pass back and forth as one of the allowable params (that I know of-- can one pass a variable in the params that is not represented in the db?).
In my initial research I see suggestions of hidden_field_tags and helper_methods and all_helpers and modules and global modules and more. Under time pressure, I dread beginning down the wrong path. Which is the better approach? Or a good high level doc for reference?
As an example, here is one view in which I would like to calculate current grade, compare it to desired grade, and display accordingly.
# index.html.erb
<% @courses.each do |course| %>
<li>
<%= my_algorithm_to_calculate_curr_grade(many course.fields used to caluculate)
<= course.desired_grade ? "set li to <Color: red>" : "set li to <Color: green>" %>
<%= course.course_name %>
Current Calculation: <%= display_results_of_previous_calculation %>
(Goal: <%= course.desired_grade %>)
<%= link_to 'Show', course %>
<%= link_to 'Edit', edit_course_path(course) %>
<%= link_to 'Drop Course Without Penalty', course, method: :delete, data: { confirm: 'Are you sure?' } %>
</li>
<% end %>
Upvotes: 0
Views: 502
Reputation: 9278
It's hard to tell from your question if course.fields
are attributes of Course or different model(s). If all the fields are Course attributes, I would put it as an instance method on Course.
class Course < ActiveRecord::Base
def calculated_grade
# fun algorithm
end
end
If course.fields need to be loaded from the database, I'd probably go with a Plain Old Ruby Object (PORO), maybe call it CourseGradeCalculator (put it in app/models, why not? It's business logic)
class CourseGradeCalculator
attr_reader :course, :fields, :grade
def initialize(course, fields)
@course = course
@fields = fields
@grade = calculate_grade
end
private
def calculate_grade
# fun algorithm
end
end
# controller
@course = Course.preload(:fields).find(params[:id]
# view
CourseGradeCalculator.new(@course, @course.fields)
Upvotes: 1