I've looked at all kinds of threads on the same error and tried different things people suggested, but can't seem to figure this one out. I'm using Rails 5 and keep getting this error when I try to submit my form:
Step reference must exist
Here are my routes
Rails.application.routes.draw do
resources :jobs do
resources :steps, except: [:index], controller: 'jobs/steps'
member do
patch :complete
end
end
get '/job/:id/next_step', to: 'jobs#next_step', as: 'next_step_jobs'
root "pages#home"
end
I have a Job model and Step model
class Job < ActiveRecord::Base
has_many :steps, dependent: :destroy
accepts_nested_attributes_for :steps
def step_completed?
!steps.last.completed_at.blank?
end
end
class Step < ActiveRecord::Base
belongs_to :job, optional: true
belongs_to :step_reference
end
Here are both controllers
class JobsController < ApplicationController
before_action :set_job, only: [:show, :edit, :next_step, :update]
# GET /jobs
def index
@dashboard = Dashboard.new
end
# GET /jobs/:id
def show
end
# GET /jobs/new
def new
@job = Job.new
end
# GET /jobs/:id/edit
def edit
end
# POST /jobs
def create
@job = Job.create(job_params)
if @job.save
# redirect to the next_step_path to ask questions
redirect_to next_step_jobs_path(@job), flash: { success: "Job successfully added" }
else
redirect_to new_job_path, flash: { danger: @job.errors.full_messages.join(", ") }
end
end
# PATCH /jobs/:id
def update
if @job.update(job_params)
redirect_to jobs_path, flash: { success: "Job successfully updated" }
else
redirect_to edit_jobs_path(@job), flash: { danger: @job.errors.full_messages.join(", ") }
end
end
# GET /jobs/:id/next_step
def next_step
# get question number from query string
@q = params[:q]
# create new instance of step
@next = Next.new
# pull the next_step object with question and answers to pass to the view
@next_step = @next.next_step(@job, @q)
if @next_step[:answers][0][:text].nil?
redirect_to new_job_step_path(@job)
else
@next_step
end
end
private
def set_job
@job = Job.find(params[:id])
end
def job_params
params.require(:job).permit(:company, :position, :contact, :contact_email,
:posting_url, steps_attributes: [:step_reference_id, :job_id, :completed_at, :next_step_date])
end
end
class Jobs::StepsController < ApplicationController
before_action :set_job
before_action :set_step, only: [:show, :edit, :update, :complete]
# GET /jobs/:job_id/steps/:id
def show
end
# GET /jobs/:job_id/steps/new
def new
@step = @job.steps.new
end
# GET /jobs/:job_id/steps/:id/edit
def edit
end
# POST /jobs/:job_id/steps/
def create
@step = @job.steps.create(step_params)
if @step.save
redirect_to jobs_path, flash: { success: "Next step successfully added." }
else
redirect_to jobs_path, flash: { danger: @step.errors.full_messages.join(", ") }
end
end
# PATCH /jobs/:job_id/steps/:id
def update
if @step.update(step_params)
redirect_to jobs_path, flash: { success: "Next step successfully updated." }
else
redirect_to edit_job_step_path, flash: { danger: @step.errors.full_messages.join(", ") }
end
end
# PATCH /jobs/:job_id/steps/:id/complete
def complete
if @step.update_attribute(:completed_at, Date.today)
redirect_to jobs_path, flash: { success: "Job step completed" }
else
redirect_to jobs_path, flash: { danger: @step.errors.full_messages.join(", ") }
end
end
private
def set_job
@job = Job.find(params[:job_id])
end
def set_step
@step = Step.find(params[:id])
end
def step_params
params.require(:step).permit(:step_reference_id, :job_id, :completed_at, :next_step_date)
end
end
And here's my view for /jobs/:job_id/steps/new
<h1 class="text-xs-center">New Step</h1>
<%= form_for @step, url: job_steps_path(@job) do |f| %>
<div class="form-group">
<%= f.label :next_step_date %>
<%= f.date_field :next_step_date, class: "form-control", id: "add-next-date-field" %>
</div>
<%= f.submit 'Save', class: "btn btn-primary" %>
<% end %>
So the form should be submitting to the StepsController's create method, but when it submits I get the "Step reference must exist" error. Based on other threads it seems like this might have to do with the strong parameters, but everything looks pretty standard to me.
Here's the log from terminal
Started POST "/jobs/1/steps" for ::1 at 2017-01-27 14:28:46 -0500
Processing by Jobs::StepsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0hYvZArkUXj7WZw9L04ovYUSm4txz14pk8POgvJxNsdvvQ7bwQLusz5WW2u0wDGgT81k6mwDkMZLyaFIVxZW5w==", "step"=>{"next_step_date"=>"2017-01-31"}, "commit"=>"Save", "job_id"=>"1"}
Job Load (0.2ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
(0.1ms) begin transaction
StepReference Load (0.1ms) SELECT "step_references".* FROM "step_references" WHERE "step_references"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
(0.1ms) commit transaction
(0.1ms) begin transaction
(0.0ms) rollback transaction
Redirected to http://localhost:3000/jobs
Completed 302 Found in 28ms (ActiveRecord: 1.0ms)
I've been fooling around with this for hours, so if anyone can shed some light I'd be extremely greatful!!!
I think your problem isn't with your params, but rather the way you've built your form. Typically, the way to do forms with nested attributes is to use the fields_for
helper (info here).
So your form should look more like this:
<%= form_for @job do |f| %>
<%= f.fields_for :steps do |steps| %>
<div class="form-group">
<%= steps.label :next_step_date %>
<%= steps.date_field :next_step_date, class: "form-control", id: "add-next-date-field" %>
</div>
<% end %>
<%= f.submit 'Save', class: "btn btn-primary" %>
<% end %>