【问题标题】:Issue with nested forms and posting simultaneously to two associated tables嵌套表单和同时发布到两个关联表的问题
【发布时间】:2021-06-08 02:46:59
【问题描述】:

所以我现在已经尝试了几个小时从不同的来源提取。我敢肯定,我可以通过多次创建以一种非常丑陋的方式将它组合在一起,但我相信有一种简单的方法可以做到这一点。

我正在尝试创建一个简单的时间和任务跟踪器。我有一个时间跟踪表,记录了任务的开始和结束时间以及任务 ID。

有一个包含任务标题和详细信息的关联表。

当我尝试保存时!它

它使用 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 %>

【问题讨论】:

  • 快速建议: 1. 您能检查一下表单提交时发出的 HTTP 请求的正文是什么吗? 2. 尝试使用has_many :timerecord, inverse_of: :task 不确定这里是不是这样

标签: ruby-on-rails ruby ruby-on-rails-6


【解决方案1】:

首先,您必须知道哪个模型嵌套在另一个模型中,以及您要在哪个模型上调用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

【讨论】:

  • 感谢所有花时间发表评论和提供反馈的人。得到这个工作。如果将来有人遇到此问题,这也是一个很好的参考资料meaganwaller.com/…
【解决方案2】:

不是这样的答案,只是一些建议可以为您指明正确的方向,因为您的实施存在很多问题。

  1. 你不需要accepts_nested_attributes_for :timerecord 在任务中,因为您在创建/编辑任务时没有创建时间记录。

  2. TimerecordController 中的任务不需要嵌套属性

  3. 表单应该有一个用于 :task_id 的 hidden_​​field - 这主要是您收到错误的原因。

  4. 但是您没有时间记录的关联任务,因此您需要在生成新时间记录时分配它。您的 TimerecordController 新操作应类似于:

def new
  @timetracker = Timerecord.new
  @timetracker.task_id = params[:task_id]
end
  1. 这意味着您还需要确保将 task_id 发送到新操作,例如 new_timerecord_path(task_id: my_task_instance.id)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多