最初我有:committed
天的工作时间非常漂亮,但是为了适应用户检查他是否错过了:committed
天的能力,稍微更改了模型我现在收到错误消息与:committed
:
undefined method to_date for nil:NilClass
第30行n_days = ((date_started.to_date)..Date.today).count { |date| committed_wdays.include? date.wday }
此代码来自习惯模型:
class Habit < ActiveRecord::Base
belongs_to :user
has_many :levels
has_many :days, through: :levels #for being able to access Habit.find(*).days
accepts_nested_attributes_for :levels, :days
before_save :set_level
acts_as_taggable
serialize :committed, Array
def evaluate(user)
levels.each { |level| level.evaluate }
user.missed_levels << levels.where(passed: false).ids
user.missed_days << days.where(missed: true).ids
user.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 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
这背后的逻辑是用户创造了他想要挑战的习惯。要达到“掌握”的习惯,他必须完成5个等级。每个级别都有一定数量的:committed
天必须在推进之前完成,如上所述n_days
。
用户在_form中提交他想要养成习惯的日子(周日至周六)。例如,他可以选择太阳,婚礼,坐着。然后,该应用只应根据非n_days
:missed
天计算:committed
(其中10天过去后会进入第二级)。
class Level < ActiveRecord::Base
belongs_to :habit
belongs_to :user
has_many :days
accepts_nested_attributes_for :days
def evaluate
if days.where(missed: true ).count == days_needed
update_attributes(passed: false)
else
update_attributes(passed: true)
end
end
end
class Day < ActiveRecord::Base
belongs_to :level
belongs_to :habit
end
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
def show
end
def new
@goal = current_user.goals.build
@habit = current_user.habits.build
@level = current_user.levels.build
3.times { @level.days.build }
end
def edit
end
def create
@habit = current_user.habits.build(habit_params)
@levels = @habit.levels
if @habit.evaluate(@user)
redirect_to @habit, notice: 'Habit was successfully created.'
else
@feed_items = []
render 'pages/home'
end
end
def update
if @habit.update(habit_params)
redirect_to @habit, notice: 'Habit was successfully updated.'
else
render action: 'edit'
end
end
def destroy
@habit.destroy
redirect_to habits_url
end
private
def set_habit
@habit = Habit.find(params[:id])
end
def correct_user
@habit = current_user.habits.find_by(id: params[:id])
redirect_to habits_path, notice: "Not authorized to edit this habit" if @habit.nil?
end
def habit_params
params.require(:habit).permit(
:user_id,
:level,
:left,
:date_started,
:trigger,
:target,
:positive,
:negative,
:tag_list,
:committed => [],
:levels_attributes => [
:passed,
:days_attributes => [
:missed,:level_id]])
end
end
<%= simple_form_for(@habit) do |f| %>
<%= f.error_notification %>
<div class="america">
<form>
<div class="committed">
<%= f.label "Committed to:" %>
<%= f.collection_check_boxes :committed, Date::DAYNAMES, :downcase, :to_s %>
</div>
<p>
<div class="date-group">
<label> Started: </label>
<%= f.date_select :date_started, :order => [:month, :day, :year], class: 'date-select' %>
</div>
</p>
<p>
<%= f.text_field :trigger, class: 'form-control', placeholder: 'Enter Trigger' %></p>
<p>
<%= f.text_field :tag_list, habit: @habit.tag_list.to_s.titleize, class: 'form-control', placeholder: 'Enter Action' %>
</p>
<p>
<%= f.text_field :target, class: 'form-control', placeholder: 'Enter Target' %>
</p>
<p>
<%= f.text_field :positive, class: 'form-control', placeholder: 'Enter Reward' %>
</p>
<% 5.times.each_with_index do |number, index| %>
<h1>Level <%= index + 1 %></h1>
<%= f.fields_for :levels do |level| %>
<%= level.fields_for :days do |day| %>
<%= day.label :missed %>
<%= day.check_box :missed %> <br/>
<% end %>
<% end %>
<% end %>
<div class="america2">
<%= button_tag(type: 'submit', class: "btn") do %>
<span class="glyphicon glyphicon-plus"></span>
<% end %>
<%= link_to habits_path, class: 'btn' do %>
<span class="glyphicon glyphicon-chevron-left"></span>
<% end %>
<%= link_to @habit, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn' do %>
<span class="glyphicon glyphicon-trash"></span>
<% end %>
</div>
</form>
</div>
<% end %>
<!-- Default bootstrap panel contents -->
<div id="valuations" class="panel panel-default">
<div class="panel-heading"><h4><b>HABITS</b></h4></div>
<!-- Table -->
<table>
<thead>
<tr>
<th>Level</th>
<th>Left</th>
<th>Strike</th>
<th>Trigger</th>
<th>Action</th>
<th>Target</th>
<th>Reward</th>
<th>Days</th>
</tr>
</thead>
<tbody>
<% @habits.each do |challenged| %>
<tr>
<td><%= challenged.level %></td>
<td><%= challenged.left %></td>
<td>
<%= link_to edit_habit_path(challenged) do %>
<%= [params[:missed]].flatten.length %>
<% end %></td>
<td><%= challenged.trigger %></td>
<td class="category">
<b><%= raw challenged.tag_list.map { |t| link_to t.titleize, taghabits_path(t) }.join(', ') %></b>
</td>
<td><%= challenged.target %></td>
<td><%= challenged.positive %></td>
<td class= "committed">
<%= challenged.committed.map { |d| d.titleize[0,3] }.join ', ' %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
非常感谢你的帮助!
这些代码中的一些来自这里的答案:How to integrate :missed days with :committed days in habits.rb?搞砸了这个答案:How to Make :level Change Based on :committed Days?
答案 0 :(得分:1)
似乎date_started
是您的Habit
模型的属性,可能是数据库列,date_started
中有NULL。打开你的Rails控制台,看看是否是这种情况:
Habit.where(date_started: nil).count
如果您希望date_started
永远不应为null,请添加验证以确保是这种情况。只要您测试将空值保存到该列的代码,验证错误就会指向您的错误。
另一方面,如果你想在date_started
中允许空值,那么重写你的levels
方法以允许它。