Rails 不保存嵌套属性
Rails not saving nested attributes
我有 tables 任务和项目。我有一个 Item 表单,我在其中记录了我的 Tasks 可能拥有的所有可能项目,它工作正常。然后我有一个任务表单,其中所有项目都显示在一个字段旁边,以放置每个项目的成本值。这将导致 Task 和 Item 之间的连接:TaskItem(此 table 包含 task_id、item_id 和成本)。
当我提交表单时,它保存的是任务而不是关联的任务项。我没有看到我遗漏了什么,因为我搜索了很多这个问题,但似乎没有任何效果。请看下面的代码。
型号:
class Task < ApplicationRecord
has_many :task_items
has_many :items, :through => :task_items
accepts_nested_attributes_for :task_items, :allow_destroy => true
end
class Item < ApplicationRecord
has_many :task_items
has_many :tasks, :through => :task_items
end
class TaskItem < ApplicationRecord
belongs_to :task
belongs_to :item
accepts_nested_attributes_for :item, :allow_destroy => true
end
控制器:
def new
@items = Item.all
@task = Task.new
@task.task_items.build
end
def create
@task = Task.new(task_params)
@task.save
redirect_to action: "index"
end
private def task_params
params.require(:task).permit(:id, :title, task_items_attributes: [:id, :item_id, :cost])
end
我的看法:
<%= form_for :task, url:tasks_path do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field(:title, {:class => 'form-control'}) %><br>
</p>
<% @items.each do |item| %>
<% @task_items = TaskItem.new %>
<%= f.fields_for :task_items do |ti| %>
<%= ti.label item.description %>
<%= ti.text_field :cost %>
<%= ti.hidden_field :item_id, value: item.id %>
<% end %>
<% end %>
<p>
<%= f.submit({:class => 'btn btn-primary'}) %>
</p>
您需要在 class 任务中的 has_many
方法中添加 inverse_of
选项:
class Task < ApplicationRecord
has_many :task_items, inverse_of: :task
has_many :items, through: :task_items
accepts_nested_attributes_for :task_items, :allow_destroy => true
end
这是因为在创建新的 TaskItem 实例时,它要求 Task 实例已经存在于数据库中才能获取 Task 实例的 id
。使用此选项,它会跳过验证。
您可以阅读此 post 关于 inverse_of
选项及其用例的内容。
fields_for
有一个选项可以指定要存储信息的对象。这与构建 has_many
集合中的每个 TaskItem 相结合应该确保正确设置所有关系。
查看代码:
<%= form_for @task do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field(:title, {:class => 'form-control'}) %><br>
</p>
<% @items.each do |item| %>
<% task_item = @task.task_items.build %>
<%= f.fields_for :task_items, task_item do |ti| %>
<%= ti.label item.description %>
<%= ti.text_field :cost %>
<%= ti.hidden_field :item_id, value: item.id %>
<% end %>
<% end %>
<p>
<%= f.submit({:class => 'btn btn-primary'}) %>
</p>
<% end %>
控制器代码:
def index
end
def new
@items = Item.all
@task = Task.new
end
def create
@task = Task.new(task_params)
@task.save
redirect_to action: "index"
end
private
def task_params
params.require(:task).permit(:id, :title, task_items_attributes: [:id, :item_id, :cost])
end
我有 tables 任务和项目。我有一个 Item 表单,我在其中记录了我的 Tasks 可能拥有的所有可能项目,它工作正常。然后我有一个任务表单,其中所有项目都显示在一个字段旁边,以放置每个项目的成本值。这将导致 Task 和 Item 之间的连接:TaskItem(此 table 包含 task_id、item_id 和成本)。
当我提交表单时,它保存的是任务而不是关联的任务项。我没有看到我遗漏了什么,因为我搜索了很多这个问题,但似乎没有任何效果。请看下面的代码。
型号:
class Task < ApplicationRecord
has_many :task_items
has_many :items, :through => :task_items
accepts_nested_attributes_for :task_items, :allow_destroy => true
end
class Item < ApplicationRecord
has_many :task_items
has_many :tasks, :through => :task_items
end
class TaskItem < ApplicationRecord
belongs_to :task
belongs_to :item
accepts_nested_attributes_for :item, :allow_destroy => true
end
控制器:
def new
@items = Item.all
@task = Task.new
@task.task_items.build
end
def create
@task = Task.new(task_params)
@task.save
redirect_to action: "index"
end
private def task_params
params.require(:task).permit(:id, :title, task_items_attributes: [:id, :item_id, :cost])
end
我的看法:
<%= form_for :task, url:tasks_path do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field(:title, {:class => 'form-control'}) %><br>
</p>
<% @items.each do |item| %>
<% @task_items = TaskItem.new %>
<%= f.fields_for :task_items do |ti| %>
<%= ti.label item.description %>
<%= ti.text_field :cost %>
<%= ti.hidden_field :item_id, value: item.id %>
<% end %>
<% end %>
<p>
<%= f.submit({:class => 'btn btn-primary'}) %>
</p>
您需要在 class 任务中的 has_many
方法中添加 inverse_of
选项:
class Task < ApplicationRecord
has_many :task_items, inverse_of: :task
has_many :items, through: :task_items
accepts_nested_attributes_for :task_items, :allow_destroy => true
end
这是因为在创建新的 TaskItem 实例时,它要求 Task 实例已经存在于数据库中才能获取 Task 实例的 id
。使用此选项,它会跳过验证。
您可以阅读此 post 关于 inverse_of
选项及其用例的内容。
fields_for
有一个选项可以指定要存储信息的对象。这与构建 has_many
集合中的每个 TaskItem 相结合应该确保正确设置所有关系。
查看代码:
<%= form_for @task do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field(:title, {:class => 'form-control'}) %><br>
</p>
<% @items.each do |item| %>
<% task_item = @task.task_items.build %>
<%= f.fields_for :task_items, task_item do |ti| %>
<%= ti.label item.description %>
<%= ti.text_field :cost %>
<%= ti.hidden_field :item_id, value: item.id %>
<% end %>
<% end %>
<p>
<%= f.submit({:class => 'btn btn-primary'}) %>
</p>
<% end %>
控制器代码:
def index
end
def new
@items = Item.all
@task = Task.new
end
def create
@task = Task.new(task_params)
@task.save
redirect_to action: "index"
end
private
def task_params
params.require(:task).permit(:id, :title, task_items_attributes: [:id, :item_id, :cost])
end