dimanche 7 janvier 2018

ID param not being sent to Controller when manually changing routes

I have looked through the other answers provided on StackOverflow, and none of them answered my question. Here is what is happening with my code.

Error

undefined method `update' for nil:NilClass

Problem: It looks like the param id is not being sent to the controller from the form as they show up as nil in the console using byebug.

console readout:

(byebug) params[:id]
nil
(byebug) @support
nil
(byebug) params[:title]
nil
(byebug) params[:support]
<ActionController::Parameters {"title"=>"Test", "subtitle"=>"testing", 
"website"=>"www.test.com", "type_of_support"=>"", "description"=>""}
permitted: false>
(byebug) params[:support][:id]
nil
(byebug) params[:support][:title]
"Test"

I do not believe that the problem is with the form as it is the same form partial used for the new/create action and the params are sent to the controller then and the object is created (though in that case there is no id, since it is generated when creating the object, not passed from the form).

You can see in my code below that the route for PATCH is just 'support' without the :id param. If I try to add that to the route, I get an error stating that there is no route matching 'support/'. So, I have to take away the :id param in the route for it to pass the information to the controller.

I am at a loss here. How do I pass the :id to the controller? How does rails do this? Before I manually change the routes, the automatic routes from resources :supports includes an :id param for the PATCH route and it works. What am I doing wrong that it won't allow me to add that to the route?

Code:

config/routes.rb

get    'support',          as: 'supports',     to: 'supports#index'
post   'support',                              to: 'supports#create'
get    'support/new',      as: 'new_support',  to: 'supports#new'
get    'support/:id/edit', as: 'edit_support', to: 'supports#edit'
get    'support/:title',   as: 'support_page', to: 'supports#show'
patch  'support/',                             to: 'supports#update'
put    'support/:id',                          to: 'supports#update'
delete 'supports/:id',                         to: 'supports#destroy'

Results this for rake routes:

supports     GET    /support(.:format)                supports#index
support      POST   /support(.:format)                supports#create
new_support  GET    /support/new(.:format)            supports#new
edit_support GET    /support/:id/edit(.:format)       supports#edit
support_page GET    /support/:title(.:format)         supports#show
             PATCH  /support(.:format)                supports#update
             PUT    /support/:id(.:format)            supports#update
             DELETE /supports/:id(.:format)           supports#destroy

app/controllers/supports_controllers.rb

class SupportsController < ApplicationController
  before_action :set_support_by_title, only: [:show]
  before_action :set_support_by_id,    only: [:edit, :update, :destroy]

  def index
    @supports = Support.all
  end

  def show
  end

  def new
    @support = Support.new
  end

  def edit
  end

  def create
    @support = Support.new(support_params)

    respond_to do |format|
      if @support.save
        format.html { redirect_to @support, 
                      notice: 'Support was successfully created.' }
      else
        format.html { render :new }
      end
    end
  end

  def update
    # byebug
    respond_to do |format|
      if @support.update(support_params)
        format.html { redirect_to @support, 
                      notice: 'Support was successfully updated.' }
      else
        format.html { render :edit }
      end
    end
  end

  def destroy
    @support.destroy
    respond_to do |format|
      format.html { redirect_to supports_url, 
                    notice: 'Support was successfully destroyed.' }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_support_by_title
      @support = Support.find_by(title: params[:title])
      # byebug
    end

    def set_support_by_id
      @support = Support.find(params[:id])
      # byebug
    end

    # Never trust parameters from the scary internet, 
    # only allow the white list through.

    def support_params
      params.require(:support).permit(:title, 
                                      :subtitle, 
                                      :website, 
                                      :type_of_support, 
                                      :description)
    end
end

app/views/supports/edit.html.erb

<h1>Editing Support</h1>

<%= render 'form', support: @support %>

<%= link_to 'Show', support_page_path(@support.title) %> |
<%= link_to 'Back', supports_path %>

app/views/supports/_form.html.erb

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

      <ul>
      <% support.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    Title: 
    <%= form.text_field :title, id: :support_title %>
  </div>

  <div class="field">
    Subtitle: 
    <%= form.text_field :subtitle, id: :support_subtitle %>
  </div>

  <div class="field">
    Website: 
    <%= form.text_field :website, id: :support_website %>
  </div>

  <div class="field">
    Type of Support: 
    <%= form.text_field :type_of_support, id: :support_type %>
  </div>

  <div class="field">
    Description: 
    <%= form.text_area :description, id: :support_description %>
  </div>

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

Aucun commentaire:

Enregistrer un commentaire