如何修复level.rb使用:承诺的日子?

时间:2015-03-08 23:45:50

标签: ruby-on-rails ruby date integer undefined

最初我有: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:" %>&nbsp;
      <%= 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?

1 个答案:

答案 0 :(得分:1)

似乎date_started是您的Habit模型的属性,可能是数据库列,date_started中有NULL。打开你的Rails控制台,看看是否是这种情况:

Habit.where(date_started: nil).count

如果您希望date_started永远不应为null,请添加验证以确保是这种情况。只要您测试将空值保存到该列的代码,验证错误就会指向您的错误。

另一方面,如果你想在date_started中允许空值,那么重写你的levels方法以允许它。