Rails 4 - 嵌套对象不会保存

时间:2014-05-05 19:49:45

标签: ruby-on-rails ruby-on-rails-4 nested-attributes

注意:我读过几篇与此类似的帖子。但非解决方案回答了我的问题

我有两个对象,Bid和Moz。当我构建我的Bid对象时,除Moz对象外,一切似乎都保存好了。

模型

class Bid < ActiveRecord::Base
  belongs_to :user
  has_many :mozs, :dependent => :destroy
  accepts_nested_attributes_for :mozs, :allow_destroy => true
end

class Moz < ActiveRecord::Base
    belongs_to :bid
end

出价::构建控制器

class Bids::BuildController < ApplicationController
  include Wicked::Wizard

  steps :intro, :problems, :solutions, :pricing

  def show
    @bid = Bid.find(params[:bid_id])
    render_wizard
  end

  def update
    @bid = Bid.find(params[:bid_id])
    @bid.attributes = build_params
    4.times { @bid.mozs.build } if step == steps.second
    render_wizard @bid
  end

  def new
    @bid = Bid.new
    redirect_to wizard_path(steps.first, :bid_id => @bid.id)
  end

  def build_params
    params.require(:bid).permit(:client_name, :intro, :prob1, :prob2, :prob3, :site_feel, :search_phrase, :page_score, :total_links,
                                :internal_links, :external_links, :competition, :complete, :user_id, :us_company, :philosophy_1,
                                :philosophy_2, :website_conclusions, :is_onsite_seo, :onsite_seo, :is_ongoing_seo, :ongoing_seo,
                                :is_ppc, :ppc, :is_social_media, :social_media, :is_google_places, :google_places, :is_adwords_express,
                                :adwords_express, moz_attributes: [:url, :id, :_destroy]
                                )
  end

  private

  def finish_wizard_path
    root_url
  end
end

solutions.html.erb

<%= form_for (@bid), url: wizard_path do |f| %>
  <% if @bid.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@bid.errors.count, "error") %> prohibited this bid from being saved:</h2>

      <ul>
      <% @bid.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <% if @bid.is_onsite_seo? %>

  <div class="field">
    <%= f.label :onsite_seo %><br>
    <%= f.text_area :onsite_seo %>
  </div>

  <% end %>
  <% if @bid.is_ongoing_seo? %>

  <div class="field">
    <%= f.label :ongoing_seo %><br>
    <%= f.text_area :onsite_seo %>
  </div>

  <% end %>

  <div class="field">
    <%= f.label :ppc %><br>
    <%= f.text_area :ppc %>
  </div>

  <div class="field">
    <%= f.label :social_media %><br>
    <%= f.text_area :social_media %>
  </div>

  <div class="field">
    <%= f.label :google_places %><br>
    <%= f.text_area :google_places %>
  </div>

  <div class="field">
    <%= f.label :adwords_express %><br>
    <%= f.text_area :adwords_express %>
  </div>


  <%= f.fields_for :mozs do |builder| %>
    <%= render partial: "moz_fields", locals: {f: builder} %>
  <% end %>
  <%= link_to_add_association "Add URL", f, :mozs %>

  <div class="actions">
    <%= f.submit %>
    or <%= link_to "skip this step", next_wizard_path %>
  </div>
<% end %>

_moz_fields.html.erb

<div class="field fields">
<%= f.label :url, "Comparative URL" %><br>
<%= f.text_field :url %>
<%= f.hidden_field :destroy %>
<%= link_to_function "remove", "remove_fields(this)"%>
</div>

我不明白他们为什么不救。另外,我注意到一些奇怪的事情 - 当我不使用部分嵌套对象并使用f表单构建器作为@bid对象(而不是'builder')时,我收到错误{ {1}},但保存了一个Moz对象(尽管没有任何所需的属性)。

2 个答案:

答案 0 :(得分:3)

我认为您使用permit attrbibutes hash拼写错误,请尝试将moz_attributes更改为mozs_attributes

params.require(:bid).permit(..., :mozs_attributes: [:url, :id, :_destroy])

答案 1 :(得分:2)

如果您通过隐藏字段发送参数_destroy: 1

<%= f.hidden_field :destroy %>

你指示Rails销毁子moz对象,或者在你的情况下,防止它被创建。

至于你问题的第二部分,如果你从这个

中插入部分内容
<%= f.fields_for :mozs do |builder| %>
  <%= render partial: "moz_fields", locals: {f: builder} %>
<% end %>

到这个

<%= f.fields_for :mozs do |builder| %>
  <div class="field fields">
    <%= f.label :url, "Comparative URL" %><br>
    <%= f.text_field :url %>
    <%= link_to_function "remove", "remove_fields(this)"%>
  </div>
<% end %>

它不起作用,因为范围f的模型对象是@bid,而不是moz。出价没有url属性,因此出错。

如果输入字段是在错误的表单构建器范围内创建的,则实际上并未传输moz对象的任何属性,因此它被创建为空白。作为副作用,这也意味着不发送_destroy参数,因此保存了对象。

相反,请将此部分内联(为了清晰起见,我将builder重命名为moz):

<%= f.fields_for :mozs do |moz| %>
  <div class="field fields">
    <%= moz.label :url, "Comparative URL" %><br>
    <%= moz.text_field :url %>
    <%= link_to_function "remove", "remove_fields(this)"%>
  </div>
<% end %>