ruby-on-rails - 如何每第三个 missed_day 重新启动 current_level(3 次罢工!)?

标签 ruby-on-rails ruby model-view-controller checkbox integer

enter image description here

例如,如果用户处于第 4 级:第 50 天,他将被推回到第 45 天

  case n_days     
      when 0..9     # Would go back to 0
        1
      when 10..24   # Back to 10
        2
      when 25..44   # Back to 25
        3
      when 45..69   # Back to 45
        4
      when 70..99   # Back to 70
        5
      else
        "Mastery"
    end

然后假设他再次返回,这次是第 68 天,如果他再次勾选 3 missed_days,他将再次被推回到 >第 45 天:

enter image description here

_form(如上图所示):

<label id="<%= @habit.id %>" class="habit-id"> Missed: </label>
  <% @habit.levels.each_with_index do |level, index| %>
    <p>
      <label id="<%= level.id %>" class="level-id"> Level <%= index + 1 %>: </label>
      <%= check_box_tag nil, true, level.missed_days > 0, {class: "habit-check"} %>
      <%= check_box_tag nil, true, level.missed_days > 1, {class: "habit-check"} %>
      <%= check_box_tag nil, true, level.missed_days > 2, {class: "habit-check"} %>
    </p>
  <% end %>

习惯.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
          def committed_wdays
            committed.map do |day|    
              Date::DAYNAMES.index(day.titleize)
            end
          end

          def n_days
            ((date_started.to_date)..Date.today).count do |date| 
              committed_wdays.include? date.wday
            end - self.missed_days
          end     

      case n_days     
          when 0..9
            1
          when 10..24
            2
          when 25..44
            3
          when 45..69
            4
          when 70..99
            5
          else
            6
        end
    end
end

habit.js

$(document).ready(function() {
  var handleChange = function() {
    habit = $(this).parent().prev().attr("id");
    level = $('label', $(this).parent()).attr("id");
    if ($(this).is(":checked")) {
      $.ajax({
        url: "/habits/" + habit + "/levels/" + level + "/days_missed",
        method: "POST"
      });
    } else {
      $.ajax({
        url: "/habits/" + habit + "/levels/" + level + "/days_missed/1",
        method: "DELETE"
      });
    }
    if (!$('input[type="checkbox"]:not(:checked)', $(this).parent()).length) {
      /* this is just an example, you will have to ammend this */
      $(this).parent().append($('<input type="checkbox" class="habit-check">'));
      $(this).parent().append($('<input type="checkbox" class="habit-check">'));
      $(this).parent().append($('<input type="checkbox" class="habit-check">'));
      $(".habit-check").on('change',handleChange);
    }
  }
  $(".habit-check").on('change',handleChange);
});

days_missed_controller.rb

class DaysMissedController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]

  def create
    habit = Habit.find(params[:habit_id])
    habit.missed_days = habit.missed_days + 1
    habit.save!
    level = habit.levels.find(params[:level_id])
    level.missed_days = level.missed_days + 1
    level.save!
    head :ok # this returns an empty response with a 200 success status code
  end

  def destroy
    habit = Habit.find(params[:habit_id])
    habit.missed_days = habit.missed_days - 1
    habit.save
    level = habit.levels.find(params[:level_id])
    level.missed_days = level.missed_days - 1
    level.save!
    head :ok # this returns an empty response with a 200 success status code
  end
end

这是它的要点:https://gist.github.com/RallyWithGalli/c66dee6dfb9ab5d338c2

如果您需要代码、解释或图片,请告诉我 :)

最佳答案

这是我的解决方案:

您需要在错过 3 天的那一刻跟踪您失去的天数(您需要在级别中添加一个字段):

迁移文件.rb

class AddDaysLostToLevels < ActiveRecord::Migration
  def change
    add_column :levels, :days_lost, :integer,   default: 0
  end

结束

然后更改 Controller days_missed 以在您错过 3 天时重置并存储您重新开始级别时丢失的天数(在变量 days_lost 中):

class DaysMissedController < ApplicationController

  def create
    habit = Habit.find(params[:habit_id])
    habit.missed_days = habit.missed_days + 1
    habit.save!
    level = habit.levels.find(params[:level_id])
    level.missed_days = level.missed_days + 1
    if level.missed_days == 3
      level.missed_days = 0
      level.days_lost += habit.calculate_days_lost + 1
    end
    ...remain the same

现在我们需要在 habit.rb 中定义“calculate_days_lost”和“real_missed_days”方法。

请记住在 current_level 方法中使用 self.real_missed_days 而不是 self.missed_days:(它们是不同的,因为您可以重新开始一个级别)。新的 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 real_missed_days
     value = 0
     levels.each do |level|
       if level.missed_days != nil 
         value += level.missed_days + level.days_lost
       end  
     end
     value
  end

  def committed_wdays
   committed.map do |day|    
    Date::DAYNAMES.index(day.titleize)
   end
  end

  def n_days
    ((date_started.to_date)..Date.today).count do |date| 
      committed_wdays.include? date.wday
    end - self.real_missed_days
  end    

  def calculate_days_lost
    case n_days   
      when 0..9
        n_days
      when 10..24
        n_days-10
      when 25..44
        n_days-25
      when 45..69
        n_days-45
      when 70..99
        n_days-70
      else
        n_days-100
    end
  end

 def current_level
   return 0 unless date_started
   case n_days    
      when 0..9
        1
      when 10..24
        2
      when 25..44
        3
      when 45..69
        4
      when 70..99
        5
      else
        6
    end
  end

end

关于ruby-on-rails - 如何每第三个 missed_day 重新启动 current_level(3 次罢工!)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29990181/

相关文章:

ruby-on-rails - Rails 5 + Heroku : Assets are not loaded in production, 但适用于本地主机

ruby-on-rails - 从 Geocode 经纬度获取地址

java - 有关执行操作和使用具有多个 View 的单个模型的不确定性

ruby-on-rails - Heroku worker dyno 不断崩溃无法从 Resque 启动

ruby-on-rails - Rails 图像文档

ruby-on-rails - Rails中带有.SCSS的背景图像?

ruby - 在 ruby​​ 的哈希中找到最低和最高值

ruby-on-rails - Ruby on Rails 中的多级子域配置

xml - 原子提要中的自定义标签

php - 我的 Symfony 路由抛出 404?