Rails 4:保存子记录ID但不保存其属性,使用带有has_many关系的嵌套表单

我有3个模型与has_many通关系:食物(例如:巧克力),Sub(巧克力食物替代品),关节(联合表)。

说@food = Food.find(1); has_many通过关系允许我做@subs = @ food.subs,它返回与@food相关的所有替代品。 这工作正常,但只保存Sub id而不是它的属性:name和:description,因为你可以看到它在我的控制器中的create action中尝试保存@ food.subs时返回nil:

=> #<ActiveRecord::Associations::CollectionProxy [#]> 

我想问题在于我的食物控制器中的创建动作,也许与我的嵌套forms有关。 我花了无数个小时试图解决这个问题,我非常渴望找到答案。 我真的不知道在哪里看。 我是rails的新手,所以非常感谢你的帮助和时间,我真的很感激。 请尽可能根据我的初学者水平调整你的答案:-)。

下面是我的控制器样品,表格和相关信息。

这是我的模特:

 class Food  :joints accepts_nested_attributes_for :subs end class Sub  :joints accepts_nested_attributes_for :foods end class Joint < ActiveRecord::Base belongs_to :food belongs_to :sub end 

这是我的db-schema FYI:

 create_table "foods", force: true do |t| t.string "name" t.text "description" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "joints", force: true do |t| t.integer "food_id" t.integer "sub_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "subs", force: true do |t| t.string "name" t.text "description" t.datetime "created_at", null: false t.datetime "updated_at", null: false end 

这是我的foods_controller:

 def new @food = Food.new @sub = Sub.new end def create @food = Food.new(food_params) @food.subs.build(params[:subs]) @food.save respond_to do |format| if @food.save format.html { redirect_to @food, notice: 'Food was successfully created.' } format.json { render :show, status: :created, location: @food } else format.html { render :new } format.json { render json: @food.errors, status: :unprocessable_entity } end end end private def food_params params.require(:food).permit(:name, :description, subs_attributes: [:name, :description]) end end 

这是我的观点/食物/ _form:

   

prohibited this food from being saved:



我的路线,如果它有帮助:资源:食物

 resources :subs resources :joints root "foods#index" 

非常感谢你 !

安托万。

在你的新动作中:

 def new @food = Food.new @food.subs.build end 

在你看来:

 <%= f.fields_for :subs do |sub| %> 

当您直接传递一个对象时,该对象将成为新的form_builder对象 – rails不知道它与原始对象有任何关联,因此它将导致不同的字段名称。

传递符号时,rails将首先尝试查找当前对象是否定义了subs_attributes方法。 如果是这样,它将遍历subs关联并为每个关联的模型构建字段。

参考这里 。

更新 – 回答评论:

首先 – @subs不是符号,它是一个实例变量。 符号以冒号开头,如:subs 。 fields_for接收参数时,会检查它是符号还是对象。 在前一种情况下,它搜索与表单构建器( f.object )相关联的对象,以确定它是否定义_attributes= 。 这样它就知道模型接受此关联的嵌套属性,因此它可以相应地运行(为每个具有正确名称的关联对象创建新表单构建器 – _attributes )。

当传递对象时,rails无法检测它是否以任何方式连接到当前对象 – 您可以为同一类型的对象创建两个关联,或者甚至可能与原始对象完全无关。 在这种情况下, fields_for就像是一个嵌套的form_for – 结果表单构建器将携带对象的模型名称( f.object.class.model_name.singular