ruby-on-railsruby-on-rails-6wicked-gem

ActionController::UrlGenerationError in ModelController#create


Working in a Rails app with a model called Shootings. It has several fields in it, so I'm using the Wicked gem to collect them in several steps.

I'm able to create Shooting records correctly, and I'm able to start the Wicked wizard correctly if I manually type the path. However I'm not able to set the redirection after the Shooting creationg with the first step of the wizard.

I get this error in the build_controller.rb once I try to redirect after I create the shooting, to the first step of the wizard

No route matches {:action=>"show", :controller=>"shootings/build", :shooting_id=>#<Shooting id: 100, title: "cwe AVER", created_at: "2021-02-13 20:01:26.212909000 +0000", updated_at: "2021-02-13 20:01:26.212909000 +0000", user_id: 1, typeshooting: nil, numberimages: nil, proservices: nil, goals: nil, status: nil>}, missing required keys: [:id]

I'll let the code speak for itself

shootings_controller.rb

class ShootingsController < ApplicationController
  before_action :set_shooting, only: %i[ show edit update destroy ]

  # GET /shootings/new
  def new
    @shooting = Shooting.new
  end

  # POST /shootings or /shootings.json
  def create
    @shooting = Shooting.new(shooting_params)

    respond_to do |format|
      if @shooting.save
        format.html { redirect_to shooting_build_path(@shooting), notice: "Shooting was successfully created." }
        format.json { render :show, status: :created, location: @shooting }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @shooting.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /shootings/1 or /shootings/1.json
  def update
    respond_to do |format|
      if @shooting.update(shooting_params)
        format.html { redirect_to @shooting, notice: "Shooting was successfully updated." }
        format.json { render :show, status: :ok, location: @shooting }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @shooting.errors, status: :unprocessable_entity }
      end
    end
  end

end

build_controler.rb (in controllers > shootings)

class Shootings::BuildController < ApplicationController
  include Wicked::Wizard

  steps :add_typeshooting, :add_numberimages, :add_proservices, :add_goals

  def show
    @shooting = Shooting.find(params[:shooting_id])
    render_wizard
  end

  def update
    @shooting = Shooting.find(params[:shooting_id])
    params[:shooting][:status] = 'active' if step == steps.last
    @shooting.update(shooting_params)
    render_wizard @shooting
  end

  def create
    @shooting = Shooting.create
    redirect_to wizard_path(steps.first, shooting_id: @shooting.id)
  end

  private

  def redirect_to_finish_wizard options = nil, params =  {}
    redirect_to root_url, notice: 'Thanks for your shooting'
  end
  
  # Only allow a list of trusted parameters through.
  def shooting_params
    params.require(:shooting).permit(:title, :user_id, :typeshooting, :numberimages, :proservices, :goals)
  end

  def set_shooting
    @shooting = Shooting.find(params[:id])
  end

end

routes.rb

Rails.application.routes.draw do
  resources :users
  resources :shootings do
    resources :build, controller: 'shootings/build'
  end
  resources :photos
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  root "shootings#index"
end

and rail routes

shooting_build_index GET    /shootings/:shooting_id/build(.:format)                                                           shootings/build#index
                                         POST   /shootings/:shooting_id/build(.:format)                                                           shootings/build#create
                      new_shooting_build GET    /shootings/:shooting_id/build/new(.:format)                                                       shootings/build#new
                     edit_shooting_build GET    /shootings/:shooting_id/build/:id/edit(.:format)                                                  shootings/build#edit
                          shooting_build GET    /shootings/:shooting_id/build/:id(.:format)                                                       shootings/build#show
                                         PATCH  /shootings/:shooting_id/build/:id(.:format)                                                       shootings/build#update
                                         PUT    /shootings/:shooting_id/build/:id(.:format)                                                       shootings/build#update
                                         DELETE /shootings/:shooting_id/build/:id(.:format)                                                       shootings/build#destroy
                               shootings GET    /shootings(.:format)                                                                              shootings#index
                                         POST   /shootings(.:format)                                                                              shootings#create
                            new_shooting GET    /shootings/new(.:format)                                                                          shootings#new
                           edit_shooting GET    /shootings/:id/edit(.:format)                                                                     shootings#edit
                                shooting GET    /shootings/:id(.:format)                                                                          shootings#show
                                         PATCH  /shootings/:id(.:format)                                                                          shootings#update
                                         PUT    /shootings/:id(.:format)                                                                          shootings#update
                                         DELETE /shootings/:id(.:format)                                                                          shootings#destroy

shootings form

<%= form_with(model: shooting) do |form| %>
<% if shooting.errors.any? %>
<div id="error_explanation">
    <h2><%= pluralize(shooting.errors.count, "error") %> prohibited this shooting from being saved:</h2>

    <ul>
        <% shooting.errors.each do |error| %>
        <li><%= error.full_message %></li>
        <% end %>
    </ul>
</div>
<% end %>

<div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
</div>
<div class="field">
    <%= form.label :user_id %>
    <%= form.text_field :user_id %>
</div>

<div class="actions">
    <%= form.submit %>
</div>
<% end %>

Solution

  • You have to change following url, and it is working

    format.html {
      flash.now[:notice] = 'Shooting was successfully created.'
      redirect_to shooting_build_index_path(@shooting) 
     }
    
    

    Or rails way

    format.html do
      flash.now[:notice] = 'Shooting was successfully created.'
      redirect_to shooting_build_index_path(@shooting) 
     end
    
    

    But personally I think it should work like above but some how it is not working.