Search code examples
ruby-on-railsruby-on-rails-4parent-childjquery-ui-autocompletenested-attributes

Create new model record or see if it already exists using nested_attributes form - Rails 4


I am using has_nested_attributes_for to create two records of two different models (a Parent and a Child). Currently using has_nested_attributes, my new.html.erb form on the parent successfully creates the parent and child and associates them together. However, the Parent records can have_many of the children model associated to it. Therefore from the new form, I need to be able to enter a url attribute (a column on the parent model) and if the url already exists...It should popup as an already existing Parent (i may use the 'rails-jquery-autocomplete' gem for this if jquery is needed)...thereby setting the existing parent id on the form. If however it does not already exist, the form should create a new parent record and child record as is currently successfully happening.

How would i need to change my controller and view to accomplish this sort of conditional nested form? thanks,

Parent Controller:

class StoriesController < ApplicationController

  def new
    @story = Story.new
    video = @story.videos.build
  end

  def create
    @story = Story.new(story_params)
    if @story.save
      flash[:success] = "Your story video has been created."
      redirect_to current_narrator
    else
      flash[:alert] = "Your story or video could not be saved.  Please include all fields."
      render 'new'
    end
  end

  private

  def story_params
    params.require(:story).permit(:headline, :url, videos_attributes: [
          :imovie,
          :director_id
        ],)
  end
end

App/Views/Stories new.html.erb:

<!-- New Story Nested Form -->
    <% provide(:title, 'New Story') %>
    <div class="container s-in-reg">
        <div class="authform">

        <h1>New Story</h1>

        <%= form_for @story do |f| %>

        <div class="field">
         <%= f.label :headline %><br />
         <%= f.text_field :headline %>
        </div><br/>

        <div class="field">
         <%= f.label :url %><br />
         <%= f.text_field :url %>
        </div><br/>

    <%= f.fields_for :videos do |builder| %>
        <div class="field">
          <%= render 'video_fields', f: builder %>
           # Video_fields partial contains the nested video fields required
        </div>
    <% end %>

            <%= f.submit "Post this story", class: "btn btn btn-info" %>
        <% end %>

        </div>
    </div>

Story.RB Model:

has_many :videos

accepts_nested_attributes_for :videos

validates :headline, presence: true
validates :url, presence: true, uniqueness: true

Video.RB Model:

class Video < ActiveRecord::Base
  belongs_to :story
  belongs_to :user

  has_attached_file :mpeg

  has_nested_attributes_for :story
end

Solution

  • So what you want to do is to have a child which accepts_nested_attributes_for a parent.

    Basically, the easiest solution is to pass a parent_id if you already have a parent you want to associate your child with, or pass parent_attributes if you are just going to create it.

    It might require you to manually check the request parameters in the controller and remove unused parameter to avoid confusion. For example, if you pass parent_id you want to completely remove parent_attributes from the returned hash, but if parent_id = nil, then you want to remove parent_id and leave parent_attributes