Al17
Al17

Reputation: 430

Ruby on Rails Saving in two tables from one form

I have two models Hotel and Address. Relationships are:

class Hotel
  belongs_to :user
  has_one    :address
  accepts_nested_attributes_for :address

and

class Address
  belongs_to :hotel

And I need to save in hotels table and in addresses table from one form.

The input form is simple:

<%= form_for(@hotel) do |f| %>

  <%= f.text_field :title %>
  ......other hotel fields......

  <%= f.fields_for :address do |o| %>
    <%= o.text_field :country %>
    ......other address fields......

  <% end %>
<% end %>

Hotels controller:

class HotelsController < ApplicationController
  def new
    @hotel = Hotel.new
  end

  def create
    @hotel = current_user.hotels.build(hotel_params)
    address = @hotel.address.build
    if @hotel.save      
      flash[:success] = "Hotel created!"
      redirect_to @hotel
    else
      render 'new'      
    end    
  end

But this code doesn't work.

ADD 1 Hotel_params:

  private
    def hotel_params
      params.require(:hotel).permit(:title, :stars, :room, :price)
    end

ADD 2

The main problem is I don't know how to render form properly. This ^^^ form doesn't even include adress fields (country, city etc.). But if in the line

<%= f.fields_for :address do |o| %> 

I change :address to :hotel, I get address fields in the form, but of course nothing saves in :address table in this case. I don't understand the principle of saving in 2 tables from 1 form, I'm VERY sorry, I'm new to Rails...

Upvotes: 2

Views: 7297

Answers (3)

Richard Peck
Richard Peck

Reputation: 76774

Bottom line here is you need to use the f.fields_for method correctly.

--

Controller

There are several things you need to do to get the method to work. Firstly, you need to build the associated object, then you need to be able to pass the data in the right way to your model:

#app/models/hotel.rb
Class Hotel < ActiveRecord::Base
   has_one :address
   accepts_nested_attributes_for :address
end

#app/controllers/hotels_controller.rb
Class HotelsController < ApplicationController
    def new
       @hotel = Hotel.new
       @hotel.build_address #-> build_singular for singular assoc. plural.build for plural
    end

    def create
        @hotel = Hotel.new(hotel_params)
        @hotel.save
    end

    private

    def hotel_params
        params.require(:hotel).permit(:title, :stars, :room, :price, address_attributes: [:each, :address, :attribute])
    end
end

This should work for you.

--

Form

Some tips for your form - if you're loading the form & not seeing the f.fields_for block showing, it basically means you've not set your ActiveRecord Model correctly (in the new action)

What I've written above (which is very similar to that written by Pavan) should get it working for you

Upvotes: 2

Pavan
Pavan

Reputation: 33542

You are using wrong method for appending your child with the parent.And also it is has_one relation,so you should use build_model not model.build.Your new and create methods should be like this

class HotelsController < ApplicationController
  def new
    @hotel = Hotel.new
    @hotel.build_address #here
  end

  def create
    @hotel = current_user.hotels.build(hotel_params)

    if @hotel.save      
      flash[:success] = "Hotel created!"
      redirect_to @hotel
    else
      render 'new'      
    end    
  end

Update

Your hotel_params method should look like this

def hotel_params
   params.require(:hotel).permit(:title, :stars, :room, :price,address_attributes: [:country,:state,:city,:street])
end

Upvotes: 6

khaled_gomaa
khaled_gomaa

Reputation: 3412

You should not build address again

class HotelsController < ApplicationController
  def new
    @hotel = Hotel.new
  end

  def create
    @hotel = current_user.hotels.build(hotel_params)
    # address = @hotel.address.build 
    # the previous line should not be used
    if @hotel.save      
      flash[:success] = "Hotel created!"
      redirect_to @hotel
    else
      render 'new'      
    end    
  end

Upvotes: 2

Related Questions