Hany Moh.
Hany Moh.

Reputation: 989

rails 4 nested form belongs_to association

I have 3 tables, including nested form association as shown in the following models and while try to save,it doesn't save in Phone table.

class Activity < ActiveRecord::Base
    belongs_to :customer
    belongs_to :phone

    accepts_nested_attributes_for :customer 
    accepts_nested_attributes_for :phone, reject_if: proc { |attributes| attributes['N'].blank? }
end

class Customer < ActiveRecord::Base
  has_many   :phones, dependent: :destroy
  has_many   :activities

  accepts_nested_attributes_for :phones, reject_if: proc { |attributes| attributes['phone_number'].blank? }, allow_destroy: true
  accepts_nested_attributes_for :activities
end

class Phone < ActiveRecord::Base
  belongs_to :customer
  has_many   :activities

  accepts_nested_attributes_for :activities
end

and in ActivitiesController

def new
    @activity = Activity.new
    @activity.customer = Customer.new
    @activity.phone = Phone.new
end

def activity_params
      params.require(:activity).permit(:activityDate, :customer_id, :phone_id, :details, customer_attributes:  [:id, :name, phone_attributes: [:id, :phone_number]])
end

Note => I have in my Activity table customer_id, phone_id just for performance

in Activity _form

 <!-- Nested form customer -->
    <%= f.fields_for :customer do |builder| %>
      <%= render "customer_fields", x: builder %>
    <% end %>

in customer partial

<div class="field form-group">
      <%= x.label "Customer name" %>
      <%= x.text_field :name, class: 'form-control' %>
</div>
<%= x.fields_for :phone do |builder| %>
      <% 3.times do %>
            <%= render "customers/phone_fields", f: builder %>
      <% end %>
<% end %>

in the last phone partial

<%= f.label :phone_number %>
<%= f.text_field :phone_number %>

Why I can't save Phones in this nested

Upvotes: 3

Views: 949

Answers (2)

Richard Peck
Richard Peck

Reputation: 76784

As per Zozo's answer, you'll need to build the associated objects as follows:

def new
    @activity = Activity.new
    @activity.build_customer.phones.build
end

There's an added step you need to consider... you're embedding your phone fields inside your customer fields. This means that you'll have to build the associative models as they are associated:

#app/models/activity.rb
class Activity < ActiveRecord::Base
   belongs_to :phone
   belongs_to :customer
   accepts_nested_attributes_for :customer 
end

#app/models/customer.rb
class Customer < ActiveRecord::Base
   has_many :phones
   accepts_nested_attributes_for :phones
end

This is only necessary if you want to embed the fields_for like you have:

#app/controllers/activities_controller.rb
class ActivitiesController < ApplicationController
   def new
      @activity = Activity.new
      @activity.build_customer.phones.build
   end
   def create
      @activity = Activity.new activity_params
      @activity.save
   end

   private

   def activity_params
       params.require(:activity).permit(:x, :y, :z, customer_attributes:[ phones_attributes: [:phone, :attributes] ])
   end
end

#app/views/activities/new.html.erb
<%= form_for @activity do |f| %>
   <%= f.fields_for :customer do |x| %>
      <%= x.fields_for :phones do |phones| %> #-> see how you're embedding this inside the original fields_for?
         <%= phones.text_field %>
      <% end %> 
   <% end %>
<% end %>

To do it normally, you'd have to just build the associative data as separate objects:

#app/models/activity.rb
class Activity < ActiveRecord::Base
   belongs_to :customer
   belongs_to :phone

   accepts_nested_attributes_for :customer, :phone
end

#app/controllers/activities_controller.rb
class ActivitiesController < ApplicationController
   def new
       @activity = Activity.new  
       @activity.build_customer
       @activity.build_phone
   end
end

#app/views/activities/new.html.erb
<%= form_for @activities do |f| %>
   <%= f.fields_for :customer do |customer| %>
      <%= customer.text_field .... %>
   <% end %>
   <%= f.fields_for :phone do |phone| %>
      <%= phone.text_field .... %>
   <% end %>
<% end %>

I almost forgot, there's something else...

<% 3.times do %>
    <%= render "customers/phone_fields", f: builder %>
<% end %>

VERY BAD PRACTICE.

If you want 3 sets of fields_for to load, you need to build the object 3 times, eg:

def new
    @activity = Activity.new
    3.times do
       @activity.build_phone
    end
end

<%= form_for @activity do |f| %>
   <%= f.fields_for :phone do |f| %>
      This will appear 3 times
   <% end %> 
<% end %>

Upvotes: 3

Brozorec
Brozorec

Reputation: 1183

Activity.new, Customer.new and Phone.new create instances of the respective classes and don't save them to the database. To do that after manipulating the created objects you have to call save method. For example @activity.save.

Upvotes: 1

Related Questions