Tri Nguyen
Tri Nguyen

Reputation: 1808

Submit one form to 2 tables in database - ruby on rails

I have 2 tables, landslides and sources (maybe doesn't relate to each other). I want a form which lets user to fill in information and then submit to both tables. Here's my current form without sources fields:

 = form_for :landslide, :url => {:controller => 'landslides', :action => 'create'} do |f|

      .form-inputs
        %form#landslideForm
          .form-group.row
            %label.col-sm-2.col-form-label{for: "textinput"}Date
            .col-sm-10
              = f.date_select :start_date, :class => "form-control"
          #Some fields
     .form-actions
        = f.button :submit, class: "btn btn-lg btn-primary col-sm-offset-5", id: "submitButton"

And parameters:

    def landslide_params
          params.require(:landslide).permit(:start_date, :continent, :country, :location, :landslide_type, :lat, :lng, :mapped, :trigger, :spatial_area, :fatalities, :injuries, :notes)
    end

    def source_params
      params.require(:source).permit(:url, :text, :landslide_id)
    end

Also there's a column in sources calls landslide_id which take the landslide ID from table landslides. So when a user submits a new landslide, how can I take the upcoming landslide ID (which is auto increment, user doesn't need to fill in)?

Thanks!

Upvotes: 0

Views: 1656

Answers (2)

max
max

Reputation: 101901

HTML does not allow nested <form> elements and you can't pass the id of record that has not been persisted yet through a form (because it does not have an id).

To create a nested resource in the same request you use accepts_nested_attributes_for:

class Landslide
  # or has_many
  has_one :source
  accepts_nested_attributes_for :source    
end

class Source
  belongs_to :landslide
end

This means that you can do Landslide.create(source_attributes: { foo: 'bar' }) and it will create both a Landslide and a Source record and will automatically link them through sources.landslide_id.

To create the form inputs use fields_for:

# use convention over configuration
= form_for @landslide do |f|
  .form-inputs
    .form-group.row
      # use the form builder to create labels instead
      = f.label :start_date, class: 'col-sm-2 col-form-label'
      .col-sm-10
        = f.date_select :start_date, class: "form-control"
   %fieldset
      %legend Source
      = f.fields_for :sources do |s|
        .form-group.row
          = s.label :url, class: 'col-sm-2 col-form-label'
          .col-sm-10
            = s.text_field :url, class: "form-control"
        # ...

class LandslidesController

  # ...

  def new
    @landslide = Landslide.new
    # this is needed to seed the form with inputs for source
    @landslide.source.new 
  end

  def create
    @landslide = Landslide.new(landslide_params)
    if @landslide.save
      redirect_to @landslide
    else
      @landslide.source.new unless @landslide.source.any?
      render :new
    end
  end

  private
  def landslide_params
    params.require(:landslide).permit(
      :start_date, :continent, :country, 
      :location, :landslide_type, 
      :lat, :lng, :mapped, :trigger, :spatial_area, 
      :fatalities, :injuries, :notes,
      source_attributes: [ :url, :text ]
    )
  end
end

Upvotes: 1

Crashtor
Crashtor

Reputation: 1279

You need to use accept_nested_attributes_for and nest your form accordingly:

(With reservation in regards to what form should be nested in which, I use the example of Sources submitted via landslide-form.)

in landslide.rb

accept_nested_attributes_for :sources

In your view (I don't know haml but anyways)

<%= form_for :landslide do |f|%>
  <%= f.select :start_date %>

    <%= fields_for :sources do |s| %>
      <%= s.input :your_column %>
    <% end %>

   <%= f.button :submit %>
<% end %>

Btw, there are a lot of questions on this already, it's called 'Nested Forms'

Nested forms in rails - accessing attribute in has_many relation

Rails -- fields_for not working?

fields_for in rails view

Upvotes: 0

Related Questions