我正在创建一个用户跟踪他们的积极习惯的应用。
为了让追踪积极的习惯变得更有趣,我将其分解为等级,特别是5个等级。
每个级别都有一定的:committed
天与之关联(case n_days
)。
如果用户在_form <%= f.check_box :missedone %>
中关闭了3x框,则应重新启动。我们如何才能为:missedone
,:missedtwo
,:missedthree
,:missedfour
,:missedfive
开展此工作?
:committed
天是用户说他会做出积极习惯的日子。
例如,我{J}运行周一至周五:committed
。因此,如果我错过了周一至周五的一天,那么错过的只会被检查。
class Habit < ActiveRecord::Base
belongs_to :user
before_save :set_level
acts_as_taggable
serialize :committed, Array
def self.comitted_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 levels
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 }
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
private
def set_level
self.level = levels
end
end
习惯/ _form.html.erb
<label> Missed: </label>
<div>
<label> Level 1: </label>
<%= f.check_box :missedone %>
<%= f.check_box :missedone %>
<%= f.check_box :missedone %>
</div>
<div>
<label> Level 2: </label>
<%= f.check_box :missedtwo %>
<%= f.check_box :missedtwo %>
<%= f.check_box :missedtwo %>
</div>
<div>
<label> Level 3: </label>
<%= f.check_box :missedthree %>
<%= f.check_box :missedthree %>
<%= f.check_box :missedthree %>
</div>
<div>
<label> Level 4: </label>
<%= f.check_box :missedfour %>
<%= f.check_box :missedfour %>
<%= f.check_box :missedfour %>
</div>
<div>
<label> Level 5: </label>
<%= f.check_box :missedfive %>
<%= f.check_box :missedfive %>
<%= f.check_box :missedfive %>
</div>
habits_controller.rb
class HabitsController < ApplicationController
before_action :set_habit, only: [:show, :edit, :update, :destroy]
before_action :logged_in_user, only: [:create, :destroy]
def index
if params[:tag]
@habits = Habit.tagged_with(params[:tag])
else
@habits = Habit.all.order("date_started DESC")
@habits = current_user.habits
end
end
private
def habit_params
params.require(:habit).permit(:missedone, :missedtwo, :missedthree, :missedfour, :missedfive, :left, :level, :date_started, :trigger, :target, :positive, :negative, :tag_list, :committed => [])
end
end
_create_habits.rb
class CreateHabits < ActiveRecord::Migration
def change
create_table :habits do |t|
t.integer :missedone
t.integer :missedtwo
t.integer :missedthree
t.integer :missedfour
t.integer :missedfive
t.integer :level #broken down via n_days
t.text :committed
t.datetime :date_started
t.string :trigger
t.string :target
t.string :positive
t.string :negative
t.references :user, index: true
t.timestamps null: false
end
add_foreign_key :habits, :users
add_index :habits, [:user_id, :created_at]
end
end
我一直在试图弄清楚这个答案,所以任何帮助都会非常受欢迎。
答案 0 :(得分:0)
很抱歉这样说,但我不明白这样做的意义。你最终会在模型中找到与状态相关的逻辑(实际上它就是你现在拥有的,以及导致所有问题的原因)。
无论如何,要回答你的问题,首先是你做错了(我认为无论如何)。为了使它工作,你必须重新开始一些事情。
在你的情况下,我会选择state_machine gem。这样你就可以摆脱状态转换逻辑。你必须在你的课程中映射那些,但它会以这种方式更具可读性和可维护性。
使用状态机,您可能会根据您的习惯映射不同的状态,例如level0
,[...],level5
和master
,然后只定义转换条件。< / p>
例如,假设您的模型中有committed_count
和missed_count
个字段。
从level0
到level1
的条件是:
committed_count > level1_go_up_const
从level1
到level0
的条件是:
missed_count
&gt; level1_go_down_const`
等等其他级别。是的,您应该将这些数字提取为常数,甚至更好地作为变量提取(因此用户可以在设置中对其进行自定义。
在每次改变时,你的习惯应该试图降低它的状态。如果那是不可能的(没有足够的错过天数)那么它会试图推进它的状态。如果那是不可能的(没有足够的承诺天数),那么就不会发生与状态相关的事情。另一方面,如果这是可能的,那么它就会进入状态。并且每个状态更改都应该将已提交和未命中的值更改为零,以便下一个/上一个状态可以跟踪它自己的限制并且表现得足够好。
通过这种方式,你可以 - 当基础工作时 - 在其上添加一些糖,而不会做一些magic
不可读(对于任何其他人)操作,switch / cases和mystic if语句,以便制作其他你现在将需要或需要的东西 - 比如检查过去几天是否错过,如果他们没有被检查为既未错过,也没有为某些活动类型添加某种周计划(可能应由用户编辑)。等等。
为了实现这一目标,你还应该考虑引入更多小而有意义的私人方法,因为在不久的将来你不会记得发生了什么。