3

I have a nested form, and am having trouble getting the create and update function to work.

I think what's happening is that the nested object is being created first, and is causing an error.

I get this error when trying to run the create action:

ActiveRecord::RecordNotFound in ApplicationsController#create
Couldn't find Answer with ID=5 for Application with ID=

Rails.root: /Users/stepan/Desktop/Sites/atlas

Application Trace | Framework Trace | Full Trace
app/controllers/applications_controller.rb:22:in `create'

This only happened after I allowed the :id parameter for the answers model. The reason I did that was to make it possible for the update action to work.

This is what my Controller Looks like ->

class ApplicationsController < ApplicationController


  def new 
    @job = Job.find(params[:job_id])
    @user = current_user 

    @application = Application.new() 

    @job.questions.count.times do 
         @application.answers.build 
    end 

  end

  def create
    @user = current_user 
    @job = Job.find(params[:job_id])

    @application = Application.new(application_params)
    @application.job_id = @job.id

    if @application.save
      redirect_to root_url, :notice => "You have now applied!"
    else
      render :action => 'new'
    end
  end


  def edit 
    @job = Job.find(params[:job_id])
    @user = current_user 
    @application = Application.find(params[:id])
    @answers = []

    @job.questions.each do |question|
      @application.answers.each do |answer|
        @answers << answer if answer.question_id == question.id
      end
    end

  end

  def update
    @job = Job.find(params[:job_id])
    @user = current_user 
    @application = Application.find(params[:id])

    if @application.update_attributes(application_params)
      redirect_to root_url, :notice => "You have updated your application!"
    else
      render :action => 'new'
    end
  end



  def destroy
    Application.find(params[:id]).destroy
    flash[:success] = "Application Deleted."
    redirect_to root_url 
  end 

  def show 
    @job = Job.find(params[:job_id])
    @user = current_user 
    @application = Application.find(params[:id])

    @answers = []

    @job.questions.each do |question|
      @application.answers.each do |answer|
        @answers << answer if answer.question_id == question.id
      end
    end

  end

private

  def application_params
    params.require(:application).permit(:id, :job_id, :user_id, answers_attributes:[:content, :question_id, :id]).merge(user_id: current_user.id) 
  end

end

This is the form:

<% provide(:title, " Apply to this job") %>

  <div class="row">
      <div class="span6">
        <h2> Job: <%= @job.job_title  %></h2>
        <p> <%= @job.job_summary %> </p>
      </div>
      <div class="span6">
        <h2> Applicant: <%= @user.name  %></h2>
      </div>

      <div class="span12">
        <h3>You're almost done! Answer the questions below and you'll be applied to the job.</h3>
      </div>
  </div>


<%= form_for [@job, @application]  do |f| %>
  <%= render 'shared/error_messages', object: f.object %>

     <% @job.questions.each_with_index do |question| %>
         <%= f.fields_for :answers, question do |question_field| %>
              <%= question_field.label :content, question.content %>
              <%= question_field.text_area :content, :value => "" %>
              <%= question_field.hidden_field :question_id,  :value => question.id  %>
         <% end %>
    <% end %>


   <%= f.submit "Submit the application", class: "button" %>
<% end %>

This is my Application Model:

# == Schema Information
#
# Table name: applications
#
#  id         :integer          not null, primary key
#  user_id    :integer
#  job_id     :integer
#  created_at :datetime
#  updated_at :datetime
#

class Application < ActiveRecord::Base
    belongs_to :job
    belongs_to :user
    validates :job_id, presence: true 
    validates :user_id, presence: true 
    has_many :answers
    accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end

This is my answer model:

# == Schema Information
#
# Table name: answers
#
#  id             :integer          not null, primary key
#  application_id :integer
#  question_id    :integer
#  created_at     :datetime
#  updated_at     :datetime
#  content        :string(255)
#

class Answer < ActiveRecord::Base
    belongs_to :question
    belongs_to :application
    validates :content, presence: true
end

There was a similar problem here --> Rails 4 Nested Attributes Unpermitted Parameters, But I don't quite understand what the answer is doing.

Help much appreciated!

Community
  • 1
  • 1
Stepan Parunashvili
  • 2,627
  • 5
  • 30
  • 51

1 Answers1

1

Some issues you may benefit from looking into:


Application Create

Bluntly, I think you're trying to do too much with the application create function

There's a principle in Rails (and all MVC) called fat model skinny controller, meaning you should put as many actions into the model as possible. The controller really just needs to guide logic (call respective methods depending on model responses). Here's what I'd do:

#app/controllers/applications_controller.rb
before_filter :set_user

def new
   job_id = params[:job_id]
   @application = Application.build(job_id)
end

def create 
    @application = Application.new(application_params)
    @application.save

    redirect_to root_url, :notice => "You have now applied!"
end

private
def set_user
    @user = current_user
end

def application_params
     params.require(:application).permit(:job_id, :user_id, answers_attributes:[:question_id, :content]).merge(user_id: current_user.id, job_id: params[:job_id])
end


#app/models/application.rb
Class Application < ActiveRecord::Base
    #Associations here
    accepts_nested_attributes_for :answers

    validates :title, :other_application_vars,
         presence: true #-> shows errors if validation fails (no need for "if @application.save" logic.... needs testing)


    def self.build(job_id) #-> class method -- not sure about passing arguments
        application = self.new

        job = Job.find(job.id)
        job.questions.count.times do
         application.answers.build
        end

    application
    end
end

#app/models/answer.rb
Class Answer < ActiveRecord::Base
    validates :question_id, :content,
         presence: true
end

Strong Params

You mentioned it will only allow you to do this if you send the id param through. I don't have a super amount of experience here, but I've found you don't need to send the :id param through strong params. This is probably what's causing the issue - you're not setting the id param, and consequently it's getting confused

If you adopt a conventional way of doing this, you shouldn't have this error

Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Wow, this is a lot cleaner. Gratitude Rich! I'll go in and implement this, and update on my results. The problem I was having with the id parameter was that if I don't allow it, it was having trouble in the update action. – Stepan Parunashvili Dec 29 '13 at 16:15
  • No problem -let us know what happens with the update action even with the refactoring. There's going to be a way to fix it for you! – Richard Peck Dec 29 '13 at 16:20
  • Hey Ryan, just updated it, now I understand instance methods. Cheers :). Re: the update action. Currently, if I run the update, it just goes and makes another set of answer records, rather then altering the existing ones. – Stepan Parunashvili Dec 29 '13 at 16:29
  • Would you mind if I make a new question about it? Would love your opinion on what's going on :P – Stepan Parunashvili Dec 29 '13 at 16:29
  • Sure! Send the link and I'll give my .02 for you! – Richard Peck Dec 29 '13 at 16:30
  • Hiya Rich, here's an update! http://stackoverflow.com/questions/20828117/nested-form-update-action-producing-duplicate-results I'm learning quite a lot from you, so huge high five of gratitude! – Stepan Parunashvili Dec 29 '13 at 17:39
  • Hey guys, I have the same error message and a very similar code with the fields_for... what I don't understand is why cleaning up his code made the error disappear. I already have the "clean" code but I still have the error. Also I am on Rails 3 –  Nov 28 '14 at 17:25