Rails 4:保存子记录ID但不保存其属性,使用嵌套形式与has_many通过关系
Rails 4: child record ID is saved but not its attributes, using nested form with has_many through relationship
我有 3 个模型具有 has_many through 关系:Food(例如:巧克力)、Sub(巧克力食品替代品)、Joint(联合表)。
说@food = Food.find(1); has_many through 关系允许我做 @subs = @food.subs 其中 return 所有与@food 关联的替代品。这工作正常,但是只有 Sub id 被保存而不是它的属性:name 和 :description 正如你所看到的那样 returned nil 当试图在我的创建操作中保存 @food.subs控制器:
=> #<ActiveRecord::Associations::CollectionProxy [#<Sub id: 28,name:nil,description:nil,created_at:
"2015-01-07 00:40:35", updated_at: "2015-01-07 00:40:35">]>
我想问题出在我的食物控制器中的创建操作上,也可能与我的嵌套表单有关。我花了无数个小时试图弄清楚这一点,我非常渴望找到答案。我真的不知道该去哪里找了。
我是 rails 的新手,非常感谢您的帮助和时间,我真的很感激。如果可能的话,请根据我的初学者水平调整你的答案:-) .
下面是我的控制器样本、表格和相关信息。
这是我的模型:
class Food < ActiveRecord::Base
has_many :joints
has_many :subs, :through => :joints
accepts_nested_attributes_for :subs
end
class Sub < ActiveRecord::Base
has_many :joints
has_many :foods, :through => :joints
accepts_nested_attributes_for :foods
end
class Joint < ActiveRecord::Base
belongs_to :food
belongs_to :sub
end
这是我的数据库模式供参考:
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
这是我的 views/foods/_form:
<%= form_for(@food) do |f| %>
<% if @food.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@food.errors.count, "error") %> prohibited this food from being saved:</h2>
<ul>
<% @food.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div>
<%= f.fields_for(@sub) do |sub| %>
<div class="field">
<%= sub.label :name %>
<%= sub.text_field :name %>
</div>
<div class="field">
<%= sub.label :description %>
<%= sub.text_area :description %>
</div>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
我的路线以防有帮助:
资源:食物
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
关联并为每个关联模型构建字段。
引用here.
更新 - 对评论的回答:
首先 - @subs
不是一个符号,它是一个实例变量。符号以冒号开头,如 :subs
。当 fields_for 接收到一个参数时,它会检查它是一个符号还是对象。在前一种情况下,它会搜索与表单生成器 (f.object
) 关联的对象,以查明它是否定义了 <passed_symbol>_attributes=
。这样它就知道模型接受此关联的嵌套属性,因此它可以相应地运行(为每个关联对象创建新的表单构建器并使用正确的名称 - <symbol>_attributes
)。
传递对象时,rails 无法检测它是否以任何方式连接到当前对象 - 您可能对同一类型的对象有两个关联,甚至可能有绝对与原始对象无关。在这种情况下,fields_for
就像嵌套的 form_for
- 生成的表单构建器将携带对象的模型名称 (f.object.class.model_name.singular
)
我有 3 个模型具有 has_many through 关系:Food(例如:巧克力)、Sub(巧克力食品替代品)、Joint(联合表)。
说@food = Food.find(1); has_many through 关系允许我做 @subs = @food.subs 其中 return 所有与@food 关联的替代品。这工作正常,但是只有 Sub id 被保存而不是它的属性:name 和 :description 正如你所看到的那样 returned nil 当试图在我的创建操作中保存 @food.subs控制器:
=> #<ActiveRecord::Associations::CollectionProxy [#<Sub id: 28,name:nil,description:nil,created_at:
"2015-01-07 00:40:35", updated_at: "2015-01-07 00:40:35">]>
我想问题出在我的食物控制器中的创建操作上,也可能与我的嵌套表单有关。我花了无数个小时试图弄清楚这一点,我非常渴望找到答案。我真的不知道该去哪里找了。 我是 rails 的新手,非常感谢您的帮助和时间,我真的很感激。如果可能的话,请根据我的初学者水平调整你的答案:-) .
下面是我的控制器样本、表格和相关信息。
这是我的模型:
class Food < ActiveRecord::Base
has_many :joints
has_many :subs, :through => :joints
accepts_nested_attributes_for :subs
end
class Sub < ActiveRecord::Base
has_many :joints
has_many :foods, :through => :joints
accepts_nested_attributes_for :foods
end
class Joint < ActiveRecord::Base
belongs_to :food
belongs_to :sub
end
这是我的数据库模式供参考:
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
这是我的 views/foods/_form:
<%= form_for(@food) do |f| %>
<% if @food.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@food.errors.count, "error") %> prohibited this food from being saved:</h2>
<ul>
<% @food.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div>
<%= f.fields_for(@sub) do |sub| %>
<div class="field">
<%= sub.label :name %>
<%= sub.text_field :name %>
</div>
<div class="field">
<%= sub.label :description %>
<%= sub.text_area :description %>
</div>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
我的路线以防有帮助: 资源:食物
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
关联并为每个关联模型构建字段。
引用here.
更新 - 对评论的回答:
首先 - @subs
不是一个符号,它是一个实例变量。符号以冒号开头,如 :subs
。当 fields_for 接收到一个参数时,它会检查它是一个符号还是对象。在前一种情况下,它会搜索与表单生成器 (f.object
) 关联的对象,以查明它是否定义了 <passed_symbol>_attributes=
。这样它就知道模型接受此关联的嵌套属性,因此它可以相应地运行(为每个关联对象创建新的表单构建器并使用正确的名称 - <symbol>_attributes
)。
传递对象时,rails 无法检测它是否以任何方式连接到当前对象 - 您可能对同一类型的对象有两个关联,甚至可能有绝对与原始对象无关。在这种情况下,fields_for
就像嵌套的 form_for
- 生成的表单构建器将携带对象的模型名称 (f.object.class.model_name.singular
)