Rails 4:使用具有has_many通过关系的嵌套形式保存子记录ID,但不保存其属性 [英] Rails 4: child record ID is saved but not its attributes, using nested form with has_many through relationship

查看:77
本文介绍了Rails 4:使用具有has_many通过关系的嵌套形式保存子记录ID,但不保存其属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有3个通过关系具有has_many的模型:食物(例如巧克力),Sub(巧克力食物替代品),关节(关节表).

I have 3 models with a has_many through relationship: Food (eg: Chocolate), Sub (Chocolate food substitute), Joint (joint table).

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

Say @food = Food.find(1); The has_many through relationship allows me to do @subs = @food.subs which return all substitutes associated with @food. This work fine, however only the Sub id is saved and not its attributes which are :name and :description as you can see it returned nil when trying to save @food.subs in my create action in my controller:

=> #<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">]>

我想问题出在我的食品控制器中的create动作,也可能与嵌套表格有关.我花了无数小时试图找出答案,我非常渴望找到答案.我真的不知道在哪里看了. 我是Rails的新手,非常感谢您的帮助和您的宝贵时间,我真的很感激.请尽可能将您的答案调整为我的初学者级别:-).

I guess the issue lies with my create action in my food controller and perhaps something to do with my nested form as well. I spent countless hours trying to figure this out I am so desperate to find an answer. I really do not know where to look anymore. I am new to rails so thanks a lot for your help and your time, I really appreciate it. Please if possible adapt your answer to my beginner level :-) .

下面是我的控制器,表格和相关信息的示例.

Down below are samples of my controller, form and relevant information.

这是我的模特:

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

这是我的数据库模式供参考:

Here is my 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:

Here is my 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

这是我的意见/食物/表格:

Here is my 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 %>

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

My routes in case it helps: resources :foods

resources :subs

resources :joints

root "foods#index"

非常感谢您!

Antoine.

推荐答案

在您的新操作中:

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

并在您看来:

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

当您直接传递一个对象时,该对象将成为新的form_builder的对象-rails不知道它以任何方式与原始对象连接,因此会导致不同的字段名称.

When you're passing directly an object, this object becomes the new form_builder's object - rails have no idea it is in any way connected with original object so it will result in different field names.

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

When you pass a symbol, rails will first try to find if your current object defines subs_attributes method. If so it will loop over subs association and build the fields for each associated model.

参考此处.

更新-评论的答案:

首先-@subs不是符号,它是一个实例变量.符号以冒号开头,例如:subs.当fields_for接收到一个参数时,它将检查它是符号还是对象.在前一种情况下,它搜索与表单生成器(f.object)关联的对象,以查明是否定义了<passed_symbol>_attributes=.这样一来,它便知道该模型接受此关联的嵌套属性,因此它可以相应地工作(为每个关联的对象使用正确的名称-<symbol>_attributes创建了新的表单生成器).

Firstly - @subs is not a symbol, it is an instance variable. Symbols start with a colon like :subs. When fields_for receives an argument, it checks whether it is a symbol or object. In former case it search an object associated with form builder (f.object) to find out if it defines <passed_symbol>_attributes=. That way it knows that the model accepts nested attributes for this association so it can behave accordingly (the new form builder is created for each associated object with a correct name - <symbol>_attributes).

传递对象时,rails无法检测它是否以某种方式连接到当前对象-您可能会为同一类型的对象建立两个关联,甚至可能与原始对象完全没有关系目的.在这种情况下,fields_for就像是嵌套的form_for一样-生成的表单生成器将携带对象的模型名称(f.object.class.model_name.singular)

When object is passed, rails has no way of detecting if this is in ay way connected to the current object - you could have two associations for the same type of objects, or even it might have absolutely nothing to do with the original object. In that case fields_for acts like it was a nested form_for - resulting form builder will carry the model name of the object (f.object.class.model_name.singular)

这篇关于Rails 4:使用具有has_many通过关系的嵌套形式保存子记录ID,但不保存其属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆