在控制器中保存记录后如何触发动作
How to trigger an action after saving record in controller
我有一个简单的应用程序,用户可以在其中创建 projects
和 timetrackers
,其中 belong_to
和 projects
基本上是时间戳。 timetrackers
有一个 start_time
和一个 end_time
(均为 :datetime),现在我想计算两个值之间的持续时间并将其保存到 timespan
中,即 :float。
为此,我在 timetrackers_controller
中执行了 set_timespan
操作
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
当我尝试在 @timetrackers.save
之前的 create
动作中拍摄动作时,出现 Couldn't find Timetracker without an ID
错误。我也被重定向到 jobs/3/timetrackers
。为什么找不到 ID,我如何才能在我的控制器中正确触发一个动作来计算时间跨度?稍后我想总结一下时间跨度。
您仍然可以访问 @timetrackers
实例变量,作为一个简单的解决方案:
def set_timespan
@job = Job.find(params[:job_id])
@timetrackers.timespan = (@timetracker.end_time - @timetracker.start_time).round / 3600
end
我会更进一步,完全删除该方法,因为 @job
也可用,只需在创建操作中直接使用相关行:
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
将在创建时自动设置。
我知道你已经有了喜欢的答案,但是...
另一种方法是修饰您的 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
的方法有很多种,这只是其中一种方法。
重点是,您的新实例属性的 所有 设置在 一个地方 而不是散布在不同的地方在你的应用程序中。 IMO,它让我们更容易理解正在发生的事情,并在事情出现问题时进行调试。
我有一个简单的应用程序,用户可以在其中创建 projects
和 timetrackers
,其中 belong_to
和 projects
基本上是时间戳。 timetrackers
有一个 start_time
和一个 end_time
(均为 :datetime),现在我想计算两个值之间的持续时间并将其保存到 timespan
中,即 :float。
为此,我在 timetrackers_controller
set_timespan
操作
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
当我尝试在 @timetrackers.save
之前的 create
动作中拍摄动作时,出现 Couldn't find Timetracker without an ID
错误。我也被重定向到 jobs/3/timetrackers
。为什么找不到 ID,我如何才能在我的控制器中正确触发一个动作来计算时间跨度?稍后我想总结一下时间跨度。
您仍然可以访问 @timetrackers
实例变量,作为一个简单的解决方案:
def set_timespan
@job = Job.find(params[:job_id])
@timetrackers.timespan = (@timetracker.end_time - @timetracker.start_time).round / 3600
end
我会更进一步,完全删除该方法,因为 @job
也可用,只需在创建操作中直接使用相关行:
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
将在创建时自动设置。
我知道你已经有了喜欢的答案,但是...
另一种方法是修饰您的 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
的方法有很多种,这只是其中一种方法。
重点是,您的新实例属性的 所有 设置在 一个地方 而不是散布在不同的地方在你的应用程序中。 IMO,它让我们更容易理解正在发生的事情,并在事情出现问题时进行调试。