嵌套表单问题并同时发布到两个关联表
Issue with nested forms and posting simultaneously to two associated tables
所以我现在已经尝试从不同的资源中提取多个小时来完成这项工作。我确定我可以用一种非常丑陋的方式将其与多个创建一起破解,但我确定有一种简单的方法可以做到这一点。
我正在尝试创建一个简单的时间和任务跟踪器。我有一个时间跟踪器 table 记录任务的开始和结束时间以及任务 ID。
有一个关联的 table,其中包含任务的标题和详细信息。
当我尝试.save 时!它
它放弃保存ActiveRecord::RecordInvalid(验证失败:任务必须存在):
逻辑似乎是它应该首先尝试创建创建 ID 的任务详细信息(标题和详细信息),然后它应该创建 timerecord(timetracker) 记录并将任务 ID 包含在 task_id时间记录栏。但是根据错误,猜测这不会发生。
感谢任何帮助我完成这项工作或指出我做错事的正确方向。
##########
编辑 发帖后,我意识到一个任务可以有多个时间记录,因为用户可以停止并重新启动同一个任务,该任务会创建具有相同任务 ID 的新记录。我已将任务模型从 has_one 更改为 has_many。
###########
这是两个模型
class Timerecord < ApplicationRecord
belongs_to :task
end
class Task < ApplicationRecord
#has_one :timerecord #this has been changed to
has_many :timerecord
accepts_nested_attributes_for :timerecord
end
在我的 Timetracker 控制器中#new & #create & private
def new
@timetracker = Timerecord.new
@timetracker.build_task
end
def create
@timetracker = Timerecord.new(timetracker_params)
if @timetracker.save
flash[:notice] = "Time Tracker Started"
redirect_to timetracker_index_path
end
end
private #at the tail of permit you will see including the task attribute title
def timetracker_params
params.require(:timerecord).permit(:user_id, :agency_id, :client_id, :task_id, :is_billable, :time_start, :time_end, :manual_input_hours, :timerecordgroup_id, :is_paused, :service_type_id, task_attributes: [:title])
end
和表格
<%= form_with(model: @timetracker, url: timetracker_index_path, local: true) do |f| %>
... a bunch of fields for @timetracker
<%#= fields_for :task, @timetracker.task do |t| %>
<%#= t.text_field :title, class: "form-control shadow-sm", placeholder: "Title" %>
<%# end %>
... more fields for timetracker
<% end %>
首先,您必须知道哪个模型嵌套在另一个模型中,以及您要在哪个模型上调用 save
方法。
由于您的模型是:
class Timerecord < ApplicationRecord
belongs_to :task
end
class Task < ApplicationRecord
#has_one :timerecord #this has been changed to
has_many :timerecord
accepts_nested_attributes_for :timerecord
end
您应该在 Task
模型上调用 save
(这也会节省 timerecord
)而不是在 TimeRecord
模型上,因为您的 Task
模型是接受 TimeRecord
模型的嵌套属性的模型,而不是相反的模型。
你的控制器应该看起来像这样:
def create
@timetracker = Task.new(task_params)
if @timetracker.save
flash[:notice] = "Time Tracker Started"
redirect_to timetracker_index_path
end
end
private
def task_params
params.require(:task).permit(#your permitted params for task, timetracker_attributes: [:title])
end
如果您注意到,您的 Task
模型接受 timetracker
的嵌套属性,因此您应该允许 timetracker_attributes
而不是 task_attributes
。
很容易知道您应该允许哪些嵌套参数,只需查看您的模型并查看 accept_nested_attributes_for
指的是哪个模型,然后在末尾添加 _attributes。
查看 accept_nested_attributes_for
文档,应该会有帮助
https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
不是这样的答案,只是一些建议,可以为您指明正确的方向,因为您的实施存在很多问题。
你不需要accepts_nested_attributes_for :timerecord
在任务中,因为您在 creating/editing 任务时没有创建时间记录。
您不需要在 TimerecordController 中为任务要求嵌套属性
表单应该有一个 hidden_field 表示 :task_id - 这就是您收到错误的主要原因。
但是您没有时间记录的关联任务,因此您还需要在生成新时间记录时分配它。您的 TimerecordController 新操作应该类似于:
def new
@timetracker = Timerecord.new
@timetracker.task_id = params[:task_id]
end
- 这意味着您还需要确保将 task_id 发送到新操作,例如
new_timerecord_path(task_id: my_task_instance.id)
所以我现在已经尝试从不同的资源中提取多个小时来完成这项工作。我确定我可以用一种非常丑陋的方式将其与多个创建一起破解,但我确定有一种简单的方法可以做到这一点。
我正在尝试创建一个简单的时间和任务跟踪器。我有一个时间跟踪器 table 记录任务的开始和结束时间以及任务 ID。
有一个关联的 table,其中包含任务的标题和详细信息。
当我尝试.save 时!它
它放弃保存ActiveRecord::RecordInvalid(验证失败:任务必须存在):
逻辑似乎是它应该首先尝试创建创建 ID 的任务详细信息(标题和详细信息),然后它应该创建 timerecord(timetracker) 记录并将任务 ID 包含在 task_id时间记录栏。但是根据错误,猜测这不会发生。
感谢任何帮助我完成这项工作或指出我做错事的正确方向。
########## 编辑 发帖后,我意识到一个任务可以有多个时间记录,因为用户可以停止并重新启动同一个任务,该任务会创建具有相同任务 ID 的新记录。我已将任务模型从 has_one 更改为 has_many。 ###########
这是两个模型
class Timerecord < ApplicationRecord
belongs_to :task
end
class Task < ApplicationRecord
#has_one :timerecord #this has been changed to
has_many :timerecord
accepts_nested_attributes_for :timerecord
end
在我的 Timetracker 控制器中#new & #create & private
def new
@timetracker = Timerecord.new
@timetracker.build_task
end
def create
@timetracker = Timerecord.new(timetracker_params)
if @timetracker.save
flash[:notice] = "Time Tracker Started"
redirect_to timetracker_index_path
end
end
private #at the tail of permit you will see including the task attribute title
def timetracker_params
params.require(:timerecord).permit(:user_id, :agency_id, :client_id, :task_id, :is_billable, :time_start, :time_end, :manual_input_hours, :timerecordgroup_id, :is_paused, :service_type_id, task_attributes: [:title])
end
和表格
<%= form_with(model: @timetracker, url: timetracker_index_path, local: true) do |f| %>
... a bunch of fields for @timetracker
<%#= fields_for :task, @timetracker.task do |t| %>
<%#= t.text_field :title, class: "form-control shadow-sm", placeholder: "Title" %>
<%# end %>
... more fields for timetracker
<% end %>
首先,您必须知道哪个模型嵌套在另一个模型中,以及您要在哪个模型上调用 save
方法。
由于您的模型是:
class Timerecord < ApplicationRecord
belongs_to :task
end
class Task < ApplicationRecord
#has_one :timerecord #this has been changed to
has_many :timerecord
accepts_nested_attributes_for :timerecord
end
您应该在 Task
模型上调用 save
(这也会节省 timerecord
)而不是在 TimeRecord
模型上,因为您的 Task
模型是接受 TimeRecord
模型的嵌套属性的模型,而不是相反的模型。
你的控制器应该看起来像这样:
def create
@timetracker = Task.new(task_params)
if @timetracker.save
flash[:notice] = "Time Tracker Started"
redirect_to timetracker_index_path
end
end
private
def task_params
params.require(:task).permit(#your permitted params for task, timetracker_attributes: [:title])
end
如果您注意到,您的 Task
模型接受 timetracker
的嵌套属性,因此您应该允许 timetracker_attributes
而不是 task_attributes
。
很容易知道您应该允许哪些嵌套参数,只需查看您的模型并查看 accept_nested_attributes_for
指的是哪个模型,然后在末尾添加 _attributes。
查看 accept_nested_attributes_for
文档,应该会有帮助
https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
不是这样的答案,只是一些建议,可以为您指明正确的方向,因为您的实施存在很多问题。
你不需要
accepts_nested_attributes_for :timerecord
在任务中,因为您在 creating/editing 任务时没有创建时间记录。您不需要在 TimerecordController 中为任务要求嵌套属性
表单应该有一个 hidden_field 表示 :task_id - 这就是您收到错误的主要原因。
但是您没有时间记录的关联任务,因此您还需要在生成新时间记录时分配它。您的 TimerecordController 新操作应该类似于:
def new
@timetracker = Timerecord.new
@timetracker.task_id = params[:task_id]
end
- 这意味着您还需要确保将 task_id 发送到新操作,例如
new_timerecord_path(task_id: my_task_instance.id)