在 Rails 中自动添加或删除给定范围内的日期数组

automatically add or delete an array of dates in a given range in Rails

这个问题让我很头疼。我正在制作一个约会应用程序,它在一个模型 (Project) 中保存日期范围,在另一个模型 (ProjectDate) 中保存可用日期。当用户创建项目时,他输入 :start_date 和 :end_date 日期来定义日期范围。关联的 project_dates 是在项目记录保存后创建的。

一切正常。

我无法开始工作的是当项目记录上的日期范围发生变化时自动创建或删除项目日期记录。

例如,如果我将范围从(1 月 10 日 - 1 月 15 日)更改为(1 月 8 日 - 1 月 13 日),我将需要自动为 1 月 8 日和 1 月 9 日创建 ProjectDate 记录并自动删除 1 月 15 日和 1 月 14 日的记录。

我尝试这样做的方法是将原始 start_date 和 end_date 存储在隐藏字段中,以便稍后在控制器中调用它们...下面是我的代码...任何帮助将不胜感激

型号

  class Project < ActiveRecord::Base
   has_many :project_dates, dependent: :destroy, inverse_of: :project
   accepts_nested_attributes_for :project_dates, allow_destroy: true

  class ProjectDates < ActiveRecord::Base
    belongs_to :project, inverse_of: :project_dates

Table 结构

Project table structure
  :id 
  :title (string)
  :start_date (date)
  :end_date(date)
  :status (boolean)

ProjectDates table structure
  :id 
  :project_id (integer)
  :schedule_date (date)
  :available (boolean)

形式

  <%= form_for @project, url: update_date_range_path(:p => @project.id) do |f| %>  

  <%= f.hidden_field :org_start, :value => @project.start_date %>
  <%= f.hidden_field :org_end, :value => @project.end_date %>
  <%=  f.text_field  :end_date %>
  <%=  f.text_field  :start_date%>

  <%= f.submit 'SAVE CHANGES' %>       

  <% end %>

控制器

def edit_date_range 
 @project = Project.find(params[:p])
end

def change_start_add 
 start_range.each do |changed_date|
   @project.project_dates.create!(schedule_date: changed_date, available: true)
 end
end


def update_date_range 
 @project = Project.find(params[:p])
 if @project.update_attributes
   if params[:project][:start_date] <  params[:project][:org_start] 
    start_range = params[:project][:org_start].to_date .. params[:project][:start_date].to_date
    :change_start_add 
   else
    start_range = params[:project][:start_date].to_date .. params[:project][:org_start].to_date 
    :change_start_remove
   end
  redirect_to  k1s3_path(:p => @project.id, :t => @project.template_id, :prt => @role.id)
 else
  redirect_to  k1_edit_date_range_path(:p => @project.id, :t => @project.template_id, :prt => @role.id)
 end
end

更新: 下面的答案回答了我的问题...但我想我会 post 我完成的代码,如果它对任何人有帮助的话:

型号

 after_update :add_and_remove_dates
def dates_in_date_range
  (self.start_date.to_date .. self.end_date.to_date)
end

def add_and_remove_dates
  dates_in_date_range.each do |date|
  ProjectDate.find_or_create_by(schedule_date: date, available: true)
  ProjectDate.where('schedule_date < ? OR schedule_date > ?', start_date, end_date).destroy_all

  end  
end

控制器

def update_date_range 
 @project = Project.find(params[:p])
   if @project.update_attributes(project_params)
    redirect_to  k1s3_path(:p => @project.id)
  else
   redirect_to  edit_date_range_path(:p => @project.id)
 end
end

你有 :change_start_add 这是一个符号,而不是一个函数。尝试:

if params[:project][:start_date] <  params[:project][:org_start] 
  start_range = params[:project][:org_start].to_date .. params[:project][:start_date].to_date
  change_start_add 
else
  start_range = params[:project][:start_date].to_date .. params[:project][:org_start].to_date 
  change_start_remove
end

这作为模型回调可能会更好。

project.rb

after_update :add_and_remove_dates

def add_and_remove_dates
  dates.where('schedule_date < ? OR schedule_date > ?', start_date, end_date).destroy_all
  dates_in_date_range.each do |date|
    dates.find_or_create_by(schedule_date: date, available: true)
  end  
end

def dates_in_date_range
  # returns an array of all the dates in the date range.
end