fetch 的双命名空间路由问题

double namespaced routing issues with fetch

你好> 我正在创建一个有书籍和用户的 Javascript SPA/Rails Api。我在我的路线中使用命名空间,以及每个模型的序列化程序。我不确定为什么我在尝试为用户执行 post 提取请求时收到此错误。我不确定我的书是否会遇到同样的问题。 Belo 你可以看到我的控制器顶部的每个控制器都有 Api::V1.....等。然后我在我的路线中有我的命名空间路线。我的 rails 控制台也是 运行

路由错误 未初始化常量 Api

我的控制器

class Api::V1::UsersController < ApplicationController

    def index
        users=User.all
        render json: users
    end 

    def create
        if User.find_by(:name=> user_params[:name])
            user=User.find_by(:name=>user_params[:name])
            redirect_to "/api/v1/users/#{user.id}"
        else 
            user = User.create(user_params)
            user.save!
            render json: user
        end 
    end 

    def show
        user = User.find_by(:id => params[:id])
        render json: user
    end 

    private

    def user_params
        params.require(:user).permit(:name)
    end
end
class Api::V1::BooksController < ApplicationController

    def index
        books = Book.all
        render json: books
    end 

    def create
        book = Book.create(book_params)
        book.save!
        render json: book
    end 

    def destroy
        book=Book.find_by(:id => params[:id]).destroy
        render json: book
    end 

    private

    def book_params
        params.require(:book).permit(:title,:author,:review,:rating,:user_id)
    end 
end

路线

Rails.application.routes.draw do






  namespace :api do
    namespace :v1 do
      resources :books
    end
  end
end
//POST fetch for creating a User
    static createUser(user) {
        let newUserForm = document.getElementById('new-user-form')
        newUserForm.addEventListener('submit', function(e){
            e.preventDefault();
            fetch('http://localhost:3000/api/v1/users', {
                method: 'POST',
                headers: {
                    'Content-Type' : 'application/json',
                    'Accept' : 'application/json'
                },
                body: JSON.stringify({
                    user: {
                        name: e.target.children[1].value
                    }
                })
            })
                .then(res => {
                    if (!res.ok) {
                        throw new Error(); // Will take you to the `catch` below
                    }
                    return res.json();
                })
                .then (user => {
                    let newUser = new User(user)
                    console.log(user)
                    newUser.displayUser();
                })
                .catch(error => {
                    console.error('User class Error', error)
                })
            })
    }

Define (and reopen) namespaced classes and modules using explicit nesting. Using the scope resolution operator can lead to surprising constant lookups due to Ruby’s lexical scoping, which depends on the module nesting at the point of definition.

module Api
  module V1
    class UsersController < ApplicationController
      # ...
    end
  end 
end

虽然您可以天真地相信 class Api::V1::UsersController 做了同样的事情,但实际上并没有,因为它需要在加载 class 时定义 Api 模块,但不正确设置模块嵌套,这将导致令人惊讶的不断查找。例如,当您使用 User 时,Ruby 将找不到预期的 Api::UserApi::V1::User

然而,此代码存在更多问题,因为它充斥着糟糕的 api 设计决策——潜在的零错误(通过使用 find_by 而不是查找)。它应该看起来像这样:

# no need to repeat yourself
namespace :api do
  namespace :v1 do
    resources :users
    resources :books
  end 
end
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym 'API'
end
# Acronyms should be all-caps
# https://github.com/rubocop-hq/ruby-style-guide#camelcase-classes
module API
  module V1
    class UsersController < ApplicationController
      
      # GET /api/v1/users
      def index
        users = User.all
        render json: users
      end 

   
      # POST /api/v1/users
      def create
        user = User.new(user_params)
        if user.save
          render json: user, 
                 status: :created
        else
          render json: { errors: user.errors.full_messages }, 
                 status: :unprocessable_entity
        end
      end 
      
      # GET /api/v1/users/1
      def show
        # Use .find instead of find_by as it will return a
        # 404 - Not Found if the user is not found
        user = User.find(params[:id])
        render json: user
      end 
      
      private
      
      def user_params
        params.require(:user).permit(:name)
      end
    end
  end 
end
module API
  module V1
    class BooksController < ApplicationController
      # GET /api/v1/books
      def index
        books = Book.all
        render json: books
      end

      # POST /api/v1/books
      def create
        book = Book.new(book_params)
        if book.save
          render json: book, 
                 status: :created
        else 
          render json: { errors: book.errors.full_messages }, 
                 status: :created
        end
      end

      # DELETE /api/v1/books/1
      def destroy
        book = Book.find(params[:id])
        book.destroy
        head :ok 
      end

      private

      def book_params
        params.require(:book)
              .permit(:title, :author, :review, :rating, :user_id)
      end
    end
  end
end

创建资源时,如果成功,您应该 return 一个 201 CREATED 响应,并且在响应中包含资源 body 或提供一个位置 header 告诉客户端他们在哪里可以找到资源。

如果不成功,您应该 return 一个状态代码,例如 422 Unprocessable Entity,它告诉客户端服务器无法使用给定参数处理请求。