NoMethodError in As1851Tests#new with shallow rout

2019-08-04 10:30发布

问题:

I have a rails 5 app using shallow resource nesting. The form_for has stopped working and I can't find why.

The App has multiple nested models that worked before changing to shallow routes on the recommendation from my previous question found here

My Schema is as follows:

db/schema.rb:

create_table "as1851_tests", force: :cascade do |t|
    t.bigint "damper_id"
    t.boolean "AS1851A", default: false, null: false
    t.boolean "AS1851B", default: false, null: false
    t.boolean "AS1851C", default: false, null: false
    t.boolean "AS1851D", default: false, null: false
    t.boolean "AS1851E", default: false, null: false
    t.boolean "Pass", default: false, null: false
    t.string "comment"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["damper_id"], name: "index_as1851_tests_on_damper_id"
  end

create_table "dampers", force: :cascade do |t|
    t.string "location"
    t.string "number"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.bigint "site_id"
    t.index ["site_id"], name: "index_dampers_on_site_id"
  end

Models

app/models/damper.rb

class Damper < ApplicationRecord
  belongs_to :site
  has_many :as1851_tests
end

app/models/as1851_test.rb

class As1851Test < ApplicationRecord
  belongs_to :damper
end

Controllers

app/controllers/as1851_tests_controller.rb

  class As1851TestsController < ApplicationController
      before_action :set_as1851_test, only: [:show, :edit, :update, :destroy]

      # GET /as1851_tests
      # GET /as1851_tests.json
      def index
        @as1851_tests = As1851Test.all
      end

      # GET /as1851_tests/1
      # GET /as1851_tests/1.json
      def show
      end

      # GET /as1851_tests/new
      def new
        @as1851_test = As1851Test.new
        @as1851_test.damper = @damper
      end

      # GET /as1851_tests/1/edit
      def edit
      end

      # POST /as1851_tests
      # POST /as1851_tests.json
      def create
        @as1851_test = As1851Test.new(as1851_test_params)
        @as1851_test.damper = @damper

        respond_to do |format|
          if @as1851_test.save
            format.html { redirect_to @damper.site, notice: 'As1851 test was successfully created.' }
            format.json { render :show, status: :created, location: @damper.site }
          else
            format.html { render :new }
            format.json { render json: @damper.site, status: :unprocessable_entity }
          end
        end
      end

      # PATCH/PUT /as1851_tests/1
      # PATCH/PUT /as1851_tests/1.json
      def update
        respond_to do |format|
          if @as1851_test.update(as1851_test_params)
            format.html { redirect_to @as1851_test, notice: 'As1851 test was successfully updated.' }
            format.json { render :show, status: :ok, location: @as1851_test }
          else
            format.html { render :edit }
            format.json { render json: @as1851_test.errors, status: :unprocessable_entity }
          end
        end
      end

      # DELETE /as1851_tests/1
      # DELETE /as1851_tests/1.json
      def destroy
        @as1851_test.destroy
        respond_to do |format|
          format.html { redirect_to as1851_tests_url, notice: 'As1851 test was successfully destroyed.' }
          format.json { head :no_content }
        end
      end

      private
        # Use callbacks to share common setup or constraints between actions.
        def set_as1851_test
          @as1851_test = As1851Test.find(params[:id])
        end

        # Never trust parameters from the scary internet, only allow the white list through.
        def as1851_test_params
          params.require(:as1851_test).permit(:damper_id, :AS1851A, :AS1851B, :AS1851C, :AS1851D, :AS1851E, :Pass, :comment)
        end
    end

app/controllers/dampers_controller.rb

class DampersController < ApplicationController
  before_action :set_damper, except: [:new, :create]

  # GET /dampers
  # GET /dampers.json
  def index
    @dampers = Damper.all
  end

  # GET /dampers/1
  # GET /dampers/1.json
  def show

  end

  # GET /dampers/new
  def new
    @damper = Damper.new
  end

  # GET /dampers/1/edit
  def edit
  end

  # POST /dampers
  # POST /dampers.json
  def create
    @damper = Damper.new(damper_params)
    @damper.site = @site

    respond_to do |format|
      if @damper.save
        format.html { redirect_to @damper.site, notice: 'Damper was successfully created.' }
        format.json { render :show, status: :created, location: @site }
      else
        format.html { render :new }
        format.json { render json: @damper.site.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /dampers/1
  # PATCH/PUT /dampers/1.json
  def update
    respond_to do |format|
      if @damper.update(damper_params)
        format.html { redirect_to @damper.site, notice: 'Damper was successfully updated.' }
        format.json { render :show, status: :ok, location: @site }
      else
        format.html { render :edit }
        format.json { render json: @damper.site.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /dampers/1
  # DELETE /dampers/1.json
  def destroy
    @damper.destroy
    respond_to do |format|
      format.html { redirect_to @damper.site, notice: 'Damper was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_damper
      @damper = Damper.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def damper_params
      params.require(:damper).permit(:location, :number, :site_id, :client_id)
    end
end

Routes

resources :clients, shallow: true do
    resources :sites do
      resources :dampers do
        resources :as1851_tests
      end
    end
  end

Form

app/views/as1851_tests/_form.html.erb <% form_for [@damper, @as1851_test] do |form| %>

  <div class="form-group">
    <%= form.label :damper_id %>
    <%= form.text_field :damper_id, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= form.label :AS1851A %>
    <%= form.check_box :AS1851A, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= form.label :AS1851B %>
    <%= form.check_box :AS1851B, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= form.label :AS1851C %>
    <%= form.check_box :AS1851C, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= form.label :AS1851D %>
    <%= form.check_box :AS1851D, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= form.label :AS1851E %>
    <%= form.check_box :AS1851E, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= form.label :Pass %>
    <%= form.check_box :Pass, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= form.label :comment %>
    <%= form.text_field :comment, class: 'form-control' %>
  </div>

  <div class="form-group">
    <% if as1851_test.persisted? %>
      <div class="float-right">
        <%= link_to 'Destroy', as1851_test, method: :delete, class: "text-danger", data: { confirm: 'Are you sure?' } %>
      </div>
    <% end %>

    <%= form.submit class: 'btn btn-primary' %>
  </div>
<% end %>

The error that I get is

NoMethodError in As1851Tests#new
Showing /Users/jeremybray/RubymineProjects/ComplianceManagerv2/app/views/as1851_tests/_form.html.erb where line #1 raised:

undefined method `as1851_tests_path' for #<#<Class:0x00007fe0c7c820a8>:0x00007fe0c8325248>
Did you mean?  as1851_test_path
               as1851_test_url

Any help with this would be greatly appreciated as the whole shallow routes is new to me.

routes raked

    Controller#Action
       damper_as1851_tests GET    /dampers/:damper_id/as1851_tests(.:format)                                               as1851_tests#index
                           POST   /dampers/:damper_id/as1851_tests(.:format)                                               as1851_tests#create
    new_damper_as1851_test GET    /dampers/:damper_id/as1851_tests/new(.:format)                                           as1851_tests#new
          edit_as1851_test GET    /as1851_tests/:id/edit(.:format)                                                         as1851_tests#edit
               as1851_test GET    /as1851_tests/:id(.:format)                                                              as1851_tests#show
                           PATCH  /as1851_tests/:id(.:format)                                                              as1851_tests#update
                           PUT    /as1851_tests/:id(.:format)                                                              as1851_tests#update
                           DELETE /as1851_tests/:id(.:format)                                                              as1851_tests#destroy
              site_dampers GET    /sites/:site_id/dampers(.:format)                                                        dampers#index
                           POST   /sites/:site_id/dampers(.:format)                                                        dampers#create
           new_site_damper GET    /sites/:site_id/dampers/new(.:format)                                                    dampers#new
               edit_damper GET    /dampers/:id/edit(.:format)                                                              dampers#edit
                    damper GET    /dampers/:id(.:format)                                                                   dampers#show
                           PATCH  /dampers/:id(.:format)                                                                   dampers#update
                           PUT    /dampers/:id(.:format)                                                                   dampers#update
                           DELETE /dampers/:id(.:format)                                                                   dampers#destroy
              client_sites GET    /clients/:client_id/sites(.:format)                                                      sites#index
                           POST   /clients/:client_id/sites(.:format)                                                      sites#create
           new_client_site GET    /clients/:client_id/sites/new(.:format)                                                  sites#new
                 edit_site GET    /sites/:id/edit(.:format)                                                                sites#edit
                      site GET    /sites/:id(.:format)                                                                     sites#show
                           PATCH  /sites/:id(.:format)                                                                     sites#update
                           PUT    /sites/:id(.:format)                                                                     sites#update
                           DELETE /sites/:id(.:format)                                                                     sites#destroy
                   clients GET    /clients(.:format)                                                                       clients#index
                           POST   /clients(.:format)                                                                       clients#create
                new_client GET    /clients/new(.:format)                                                                   clients#new
               edit_client GET    /clients/:id/edit(.:format)                                                              clients#edit
                    client GET    /clients/:id(.:format)                                                                   clients#show
                           PATCH  /clients/:id(.:format)                                                                   clients#update
                           PUT    /clients/:id(.:format)                                                                   clients#update
                           DELETE /clients/:id(.:format)                                                                   clients#destroy
               admin_users GET    /admin/users(.:format)                                                                   admin/users#index
                           POST   /admin/users(.:format)                                                                   admin/users#create
            new_admin_user GET    /admin/users/new(.:format)                                                               admin/users#new
           edit_admin_user GET    /admin/users/:id/edit(.:format)                                                          admin/users#edit
                admin_user GET    /admin/users/:id(.:format)                                                               admin/users#show
                           PATCH  /admin/users/:id(.:format)                                                               admin/users#update
                           PUT    /admin/users/:id(.:format)                                                               admin/users#update
                           DELETE /admin/users/:id(.:format)                                                               admin/users#destroy
       admin_announcements GET    /admin/announcements(.:format)                                                           admin/announcements#index
                           POST   /admin/announcements(.:format)                                                           admin/announcements#create
    new_admin_announcement GET    /admin/announcements/new(.:format)                                                       admin/announcements#new
   edit_admin_announcement GET    /admin/announcements/:id/edit(.:format)                                                  admin/announcements#edit
        admin_announcement GET    /admin/announcements/:id(.:format)                                                       admin/announcements#show
                           PATCH  /admin/announcements/:id(.:format)                                                       admin/announcements#update
                           PUT    /admin/announcements/:id(.:format)                                                       admin/announcements#update
                           DELETE /admin/announcements/:id(.:format)                                                       admin/announcements#destroy
       admin_notifications GET    /admin/notifications(.:format)                                                           admin/notifications#index
                           POST   /admin/notifications(.:format)                                                           admin/notifications#create
    new_admin_notification GET    /admin/notifications/new(.:format)                                                       admin/notifications#new
   edit_admin_notification GET    /admin/notifications/:id/edit(.:format)                                                  admin/notifications#edit
        admin_notification GET    /admin/notifications/:id(.:format)                                                       admin/notifications#show
                           PATCH  /admin/notifications/:id(.:format)                                                       admin/notifications#update
                           PUT    /admin/notifications/:id(.:format)                                                       admin/notifications#update
                           DELETE /admin/notifications/:id(.:format)                                                       admin/notifications#destroy
            admin_services GET    /admin/services(.:format)                                                                admin/services#index
                           POST   /admin/services(.:format)                                                                admin/services#create
         new_admin_service GET    /admin/services/new(.:format)                                                            admin/services#new
        edit_admin_service GET    /admin/services/:id/edit(.:format)                                                       admin/services#edit
             admin_service GET    /admin/services/:id(.:format)                                                            admin/services#show
                           PATCH  /admin/services/:id(.:format)                                                            admin/services#update
                           PUT    /admin/services/:id(.:format)                                                            admin/services#update
                           DELETE /admin/services/:id(.:format)                                                            admin/services#destroy
                admin_root GET    /admin(.:format)                                                                         admin/users#index
                   privacy GET    /privacy(.:format)                                                                       home#privacy
                     terms GET    /terms(.:format)                                                                         home#terms
             notifications GET    /notifications(.:format)                                                                 notifications#index
             announcements GET    /announcements(.:format)                                                                 announcements#index
               sidekiq_web        /sidekiq                                                                                 Sidekiq::Web
          new_user_session GET    /users/sign_in(.:format)                                                                 devise/sessions#new
              user_session POST   /users/sign_in(.:format)                                                                 devise/sessions#create
      destroy_user_session DELETE /users/sign_out(.:format)                                                                devise/sessions#destroy
         new_user_password GET    /users/password/new(.:format)                                                            devise/passwords#new
        edit_user_password GET    /users/password/edit(.:format)                                                           devise/passwords#edit
             user_password PATCH  /users/password(.:format)                                                                devise/passwords#update
                           PUT    /users/password(.:format)                                                                devise/passwords#update
                           POST   /users/password(.:format)                                                                devise/passwords#create
  cancel_user_registration GET    /users/cancel(.:format)                                                                  devise/registrations#cancel
     new_user_registration GET    /users/sign_up(.:format)                                                                 devise/registrations#new
    edit_user_registration GET    /users/edit(.:format)                                                                    devise/registrations#edit
         user_registration PATCH  /users(.:format)                                                                         devise/registrations#update
                           PUT    /users(.:format)                                                                         devise/registrations#update
                           DELETE /users(.:format)                                                                         devise/registrations#destroy
                           POST   /users(.:format)                                                                         devise/registrations#create
back_user_masquerade_index GET    /users/masquerade/back(.:format)                                                         devise/masquerades#back
           user_masquerade GET    /users/masquerade/:id(.:format)                                                          devise/masquerades#show
                      root GET    /                                                                                        clients#index
        rails_service_blob GET    /rails/active_storage/blobs/:signed_id/*filename(.:format)                               active_storage/blobs#show
 rails_blob_representation GET    /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
        rails_disk_service GET    /rails/active_storage/disk/:encoded_key/*filename(.:format)                              active_storage/disk#show
 update_rails_disk_service PUT    /rails/active_storage/disk/:encoded_token(.:format)                                      active_storage/disk#update
      rails_direct_uploads POST   /rails/active_storage/direct_uploads(.:format)                                           active_storage/direct_uploads#create

Update:

to me it looks like the routes are manipulated to singular by the shallow: true

回答1:

Well this had me stumped for a while but using the lead I found in this question I realised that the id is not set by the route or before_action anymore so I must stipulate it like so:

Controllers

app/controllers/as1851_tests_controller.rb

# GET /as1851_tests/new
  def new
    @damper = Damper.find(params[:damper_id])
    @as1851_test = As1851Test.new
  end

  # GET /as1851_tests/1/edit
  def edit
  end

  # POST /as1851_tests
  # POST /as1851_tests.json
  def create
    @damper = Damper.find(params[:damper_id])
    @as1851_test = As1851Test.new(as1851_test_params)
    @as1851_test.damper = @damper

    respond_to do |format|
      if @as1851_test.save
        format.html { redirect_to @damper.site, notice: 'As1851 test was successfully created.' }
        format.json { render :show, status: :created, location: @damper.site }
      else
        format.html { render :new }
        format.json { render json: @damper.site, status: :unprocessable_entity }
      end
    end
  end

app/controllers/dampers_controller.rb

  # GET /dampers/new
  def new
    @site = Site.find(params[:site_id])
    @damper = Damper.new
  end

  # GET /dampers/1/edit
  def edit
  end

  # POST /dampers
  # POST /dampers.json
  def create
    @site = Site.find(params[:site_id])
    @damper = Damper.new(damper_params)
    @damper.site = @site

    respond_to do |format|
      if @damper.save
        format.html { redirect_to @damper.site, notice: 'Damper was successfully created.' }
        format.json { render :show, status: :created, location: @damper.site }
      else
        format.html { render :new }
        format.json { render json: @damper.site.errors, status: :unprocessable_entity }
      end
    end
  end

Pretty basic stuff really