在控制器中保存记录后如何触发动作

时间:2019-07-17 13:59:57

标签: ruby-on-rails model-view-controller controller action

我有一个简单的应用程序,用户可以在其中创建projectstimetrackersbelong_toprojects基本上是时间戳。 timetrackers有一个start_time和一个end_time(两者均为:datetime),现在我想计算两个值之间的持续时间并将其保存到{float中的timespan中。

为此,我在set_timespan中有一个timetrackers_controller动作

  def set_timespan
    @job = Job.find(params[:job_id])
    @timetracker = Timetracker.find(params[:id])

    @timetracker.timespan = (@timetracker.end_time - @timetracker.start_time).round / 3600
  end

创建动作

  def create
    @job = Job.find(params[:job_id])
    @timetrackers = @job.timetrackers.new(timetracker_params)
    @timetrackers.user_id = current_user.id
    @timetrackers.job_id = @job.id
    #set_timespan


    respond_to do |format|
      if @timetrackers.save
        format.html { redirect_to @job, notice: 'Timestamps created successfully.' }
        format.json { render :show, status: :created, location: @job }
      else
        format.html { redirect_to new_timetracker_path, notice: "Please fill out the form." }
        format.json { render json: @job.errors, status: :unprocessable_entity }
      end
    end
  end

当我尝试在create之前的@timetrackers.save动作中拍摄动作时,出现Couldn't find Timetracker without an ID错误。我也被重定向到jobs/3/timetrackers。为什么找不到ID?如何正确触发控制器中的操作来计算时间跨度?以后我想总结一下时间跨度。

2 个答案:

答案 0 :(得分:1)

作为一个简单的解决方案,您仍然可以访问@timetrackers实例变量:

def set_timespan
  @job = Job.find(params[:job_id])

  @timetrackers.timespan = (@timetracker.end_time - @timetracker.start_time).round / 3600
end

我将更进一步,并完全删除该方法,因为@job也可用,并且只需在create动作中直接使用相关行即可:

def create
  # ...
  @timetrackers.job_id = @job.id
  # v here v
  @timetrackers.timespan = (@timetrackers.end_time - @timetrackers.start_time).round / 3600

  respond_to do |format|
  # ...
end

作为最终的,也许是理想的解决方案,您可以在Timespan模型中使用before_create回调:

# timespan.rb
before_create -> { self.timespan = (end_time - start_time).round / 3600 }

这样,您的timespan将在创建时自动设置。

答案 1 :(得分:0)

我意识到您已经有了一个喜欢的答案,但是...

另一种方法是修饰timetracker_params,以便使用诸如new_timetracker_attributes之类的方法包含所有适当的数据。也许是这样的:

  def create
    @job = Job.find(params[:job_id])
    @timetrackers = @job.timetrackers.new(new_timetracker_attributes)

    respond_to do |format|
      if @timetrackers.save
        format.html { redirect_to @job, notice: 'Timestamps created successfully.' }
        format.json { render :show, status: :created, location: @job }
      else
        format.html { redirect_to new_timetracker_path, notice: "Please fill out the form." }
        format.json { render json: @job.errors, status: :unprocessable_entity }
      end
    end
  end

private 

  def new_timetracker_attributes
    timetracker_params.merge(
      user_id:  current_user.id,
      timespan: ((end_time-start_time).round/3600)
    )
  end

  def timetracker_params
    params.require(:timetracker).permit(:start_time, :end_time)
  end

  def start_time
    timetracker_params[:start_time]
  end

  def end_time
    timetracker_params[:end_time]
  end

您可以通过多种方法来修饰timetracker_params,这只是一个主意。

重点是,您已将新实例属性的 all 全部设置在一个地方进行,而不是在应用程序的各个位置涂抹。 IMO,这使了解情况和调试是否呈梨形变得容易了一点。