There are 5 levels.
Each level has a certain amount of days in it that must pass before the habit can move up to the next level (as broken down by n_days
):
case n_days
when 0..9
1
when 10..24
2
when 25..44
3 #Level 3
when 45..69
4
when 70..99
5
else
"Mastery"
end
end
How can we call the n_days
from the present level in the habits index with something like <%= habit.current_level.n_days.count_off_from_zero_to_show %>
?
For example, if we are specifically at 50
on level 3 it would show Day 5 in the habits index.
habit.rb
class Habit < ActiveRecord::Base
belongs_to :user
has_many :comments, as: :commentable
has_many :levels
serialize :committed, Array
validates :date_started, presence: true
before_save :current_level
acts_as_taggable
scope :private_submit, -> { where(private_submit: true) }
scope :public_submit, -> { where(private_submit: false) }
attr_accessor :missed_one, :missed_two, :missed_three
def save_with_current_level
self.levels.build
self.levels.build
self.levels.build
self.levels.build
self.levels.build
self.save
end
def self.committed_for_today
today_name = Date::DAYNAMES[Date.today.wday].downcase
ids = all.select { |h| h.committed.include? today_name }.map(&:id)
where(id: ids)
end
def current_level_strike
levels[current_level - 1] # remember arrays indexes start at 0
end
def current_level
return 0 unless date_started
committed_wdays = committed.map { |day| Date::DAYNAMES.index(day.titleize) }
n_days = ((date_started.to_date)..Date.today).count { |date| committed_wdays.include? date.wday } - self.missed_days
case n_days
when 0..9
1
when 10..24
2
when 25..44
3
when 45..69
4
when 70..99
5
else
"Mastery"
end
end
end
level.rb
class Level < ActiveRecord::Base
belongs_to :habit
end
schema
create_table "habits", force: true do |t|
t.integer "missed_days", default: 0
t.text "committed"
t.integer "days_lost", default: 0
t.datetime "date_started"
t.string "trigger"
t.string "target"
t.string "reward"
t.boolean "private_submit"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "order"
end
add_index "habits", ["user_id", "created_at"], name: "index_habits_on_user_id_and_created_at"
add_index "habits", ["user_id"], name: "index_habits_on_user_id"
create_table "levels", force: true do |t|
t.integer "habit_id"
t.integer "days_lost", default: 0
t.integer "missed_days", default: 0
t.integer "current_level"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "levels", ["habit_id"], name: "index_levels_on_habit_id"
The Gist of it: https://gist.github.com/RallyWithGalli/c66dee6dfb9ab5d338c2
In your
current_level
method you've got two lines of logic that ultimately represent the value ofn_days
. If you want to reuse that value outside of that method or case statement, you should either store the value in an instance variable, or move the logic into another method. If the logic is only important to this class, then I might make it a private method.The private methods can be further refined, but hopefully this gives you an idea of how you might continue to extract the shared logic.