【问题标题】:Rails 4: child record ID is saved but not its attributes, using nested form with has_many through relationshipRails 4:保存子记录ID但不保存其属性,通过关系使用带有has_many的嵌套表单
【发布时间】:2015-01-07 01:38:52
【问题描述】:

我有 3 个具有 has_many through 关系的模型:Food(例如:Chocolate)、Sub(巧克力食品替代品)、Joint(联合表)。

说@food = Food.find(1); has_many through 关系允许我执行@subs = @food.subs,它返回与@food 关联的所有替代品。这工作正常,但是只有 Sub id 被保存,而不是它的属性,即 :name 和 :description 因为你可以看到它在我的控制器的创建操作中保存 @food.subs 时返回 nil:

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

这是我的 db-schema 仅供参考:

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:

<%= 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"

非常感谢!

安托万。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 nested-forms nested-attributes has-many-through


    【解决方案1】:

    在你的新动作中:

    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) 关联的对象,以确定它是否定义了 &lt;passed_symbol&gt;_attributes=。这样它就知道模型接受此关联的嵌套属性,因此它可以做出相应的行为(为每个关联对象创建新的表单构建器,并具有正确的名称 - &lt;symbol&gt;_attributes)。

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

    【讨论】:

    • YESSS 除了您的回答之外,我还删除了食物控制器中创建操作中的 @food.subs.build(params[:subs]) 和 @food.save 行。现在所有属性都已保存。
    • 能否请您解释一下 :subs 是如何工作的,或者它在 。我虽然最好在表单中使用@sub 之类的符号并在控制器中定义它,但是你会如何定义它呢?我还想知道单击 _form 中的 f.subtmit 时是否触发了创建操作?非常感谢你的光!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多