Daniel Rusu
Daniel Rusu

Reputation: 115

Creating nested form with devise

I would like on the form page for a campaign for a user to be able to create cities as well. I followed http://railscasts.com/episodes/196-nested-model-form-part-1?view=comments and https://medium.com/karuna-sehgal/building-a-rails-app-using-tdd-devise-omniauth-and-nested-forms-f7b9769ba2ae (this one uses devise) but cant seem to get it to work.

The error I get is: ActiveRecord::RecordInvalid: Validation failed: Cities campaign must exist

Can anyone tell me what's wrong?

Models:

class City < ApplicationRecord
  belongs_to :campaign#, optional: true
end

class Campaign < ApplicationRecord
  has_many :cities, :dependent => :destroy
  belongs_to :user
  accepts_nested_attributes_for :cities, allow_destroy: true, reject_if: :all_blank
end

Controller:

  def new
    @campaign = current_user.campaigns.build
    3.times { @campaign.cities.build }
  end

  def create
    #binding.pry
    @campaign = current_user.campaigns.build  campaign_params
    binding.pry
    if @campaign.save
      flash[:notice] = "#{@campaign.name} created"
      redirect_to @campaign
    else
      flash[:notice] = "#{@campaign.name} not created"
      redirect_to @campaign
    end
  end

  private

  def campaign_params
    params.require(:campaign).permit(:name, :titles, :sentences, :keywords, cities_attributes: [:name, :phone_number, :zip_code])
  end

Form:

<%= form_for @campaign do |f| %>
  <%= f.label "Name" %>
  <br />
  <%= f.text_field :name %>
  <br /> <br />

  <%= f.label "Titles" %>
  <br />
  <%= f.text_area :titles, cols: 80, rows: 20 %>
  <br /> <br />

  <%= f.label "Sentences" %>
  <br />
  <%= f.text_area :sentences, cols: 80, rows: 20 %>
  <br /> <br />

  <%= f.label "Keywords" %>
  <br />
  <%= f.text_area :keywords, cols: 80, rows: 20 %>
  <br /> <br />

  <%= f.fields_for :cities do | city_form | %>
    <%= city_form.label :name %>
    <%= city_form.text_field :name%>
    <%= city_form.label :phone_number %>
    <%= city_form.text_field :phone_number %>
    <%= city_form.label :zip_code %>
    <%= city_form.text_field :zip_code %>
    </br>
  <% end %>

  <%= f.submit "Submit" %>
<% end %>

Upvotes: 0

Views: 199

Answers (2)

Vishal Taj PM
Vishal Taj PM

Reputation: 1359

It seems you have missed out to pass campaign_id inside cities_attributes error happened because when rails tried to save inside the cities active_record there were no campaign_id that's why you are getting a validation error like:

ActiveRecord::RecordInvalid: Validation failed: Cities campaign must exist

So you can change campaign_params as follows:

def campaign_params
  params.require(:campaign).permit(:name, :titles, :sentences, :keywords, cities_attributes: [:campaign_id, :name, :phone_number, :zip_code])
end 

Upvotes: 0

fongfan999
fongfan999

Reputation: 2624

You can use :inverse_of like this:

Active Record provides the :inverse_of option so you can explicitly declare bi-directional associations:

class City < ApplicationRecord
  belongs_to :campaign, inverse_of: :cities
end

class Campaign < ApplicationRecord
  has_many :cities, inverse_of: :campaign
end

Upvotes: 1

Related Questions