Question

Note: I've read a couple posts similar to this. But non of the solutions answer my question

I have two objects, Bid and Moz. When I build my Bid object, everything seems to save okay, except for the Moz objects.

Model

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

Bids::Build Controllers

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>

I don't understand why they won't save. In addition, I noticed something odd -- when I don't use a partial for the nested object and use the f form builder for the @bid object (as opposed to 'builder'), I get an error no method or variable :url, but a Moz object is saved (although, not with any of the desired attributes).

Was it helpful?

Solution 2

If you send the parameter _destroy: 1 through your hidden field

<%= f.hidden_field :destroy %>

you instruct Rails to destroy the child moz object, or in your case, prevent it from being created.

As for the second part of your question, if you inline the partial from this

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

to this

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

it won't work, because the model object for the scope f is your @bid, not moz. Bids have no url attribute, hence the error.

With the input fields being created in the wrong form builder scope, you did not actually transmit any attributes for your moz object, and so it was created blank. As a side effect, this also meant not sending the _destroy parameter, so the object was saved.

Instead, inline the partial like this (I renamed builder to moz for clarity):

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

OTHER TIPS

My opinion that you misspelled with permit attrbibutes hash, try to change moz_attributes to mozs_attributes.

params.require(:bid).permit(..., :mozs_attributes: [:url, :id, :_destroy])
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top