当我将站点部署到Heroku时,控制器的 POST方法停止工作



我有一个React应用程序部署在netflix上,它的API后端(Ruby on Rails + PostgreSQL)部署在Heroku上。后端在LocalHost上运行完全正常。然而,当我将它部署到Heroku时,我的三个控制器中的一个停止了正常工作。我所有的其他控制器和它们的方法都是功能性的,所以我不太明白为什么这个特定的方法会失败。在Rails控制台上的Comment.create(...)似乎也不起作用。

发表评论。rb(模型):

class Comment < ApplicationRecord
belongs_to :User
belongs_to :ForumThread
end

comments_controller。rb(控制器):

class CommentsController < ApplicationController
#GET /Comments [Get all comments for a specific thread]
def index
@Comments = Comment.where("comments.forumthread_id = ?", params[:forum_thread_id])
render json: @Comments
end
#GET /Comments/:id [Get a specific comment by its ID]
def show
@Comment = Comment.find(params[:id])
render json: @comment
end
#POST /Comments [Create a comment]
def create
@comment = Comment.new(comment_params)
if @comment.save
render json: @comment
else
render error: {error: "Error in creating comment"}, status: 400
end
end
#PUT /Comments/:id [Update a comment]
def update
@comment = Comment.find(params[:id])
if @comment
@comment.update(comment_params)
render json: {message: "Comment successfully updated"}, status: 200
else
render error: {error: "Error in updating comment"}, status: 400
end
end
#DELETE /Comments/:id [Delete a comment]
def destroy
@comment = Comment.find(params[:id])
if @comment
@comment.destroy
render json: {message: "Comment successfully deleted"}, status: 200
else
render error: {error: "Error in deleting comment"}, status: 400
end
end
private
def comment_params
params.require(:comment).permit(:forumthread_id, :User_id, :content)
end
end

(GET仍然工作,但POST已经停止工作。我不确定其他方法,因为那些处理现有的注释,我无法创建)

schema.rb:

# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# This file is the source Rails uses to define your schema when running `bin/rails
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_01_17_054548) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "comments", force: :cascade do |t|
t.integer "User_id", null: false
t.integer "forumthread_id", null: false
t.string "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["User_id"], name: "index_comments_on_User_id"
t.index ["forumthread_id"], name: "index_comments_on_forumthread_id"
end
create_table "forum_threads", force: :cascade do |t|
t.integer "User_id", null: false
t.string "title"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "tag"
t.index ["User_id"], name: "index_forum_threads_on_User_id"
end
create_table "users", force: :cascade do |t|
t.string "username"
t.string "email"
t.string "password"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "bio"
end
end

routes.rb:

Rails.application.routes.draw do
#Routes
get 'users/s/:username', to: "users#search"
get 'users/:username/comments', to: "users#comments"
resources :users, only: [:index, :show, :create, :update, :destroy]
resources :forum_threads, only: [:index, :show, :create, :update, :destroy] do
resources :comments, only: [:index, :show, :create, :update, :destroy]
end
end

前端发送POST请求的函数:

const user_id = useSelector(state => state.id);
const threadID = useParams().id;
// console.log("Thread ID: ", threadID, "User ID: ", user_id, "Content: ", content);
//Creates new comment
const handleCreateComment = (event) => {
if (!isContentError) {
event.preventDefault();
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ User_id: user_id, forumthread_id: threadID, content: content })
};
fetch('https://highgear.herokuapp.com/forum_threads/' + threadID + "/comments", requestOptions)
.then(response => response.json())
.then(data => refreshCreate(data))
.catch(err => console.log(err));
} else {
event.preventDefault();
window.alert("Error: Please enter a longer comment");
}
}

(即使forumthread_id, User_id和content都是正确的,它仍然不工作。更不用说,它仍然可以在LocalHost上工作)。

发送POST请求时的Heroku日志输出:

2023-01-18T04:32:47.335761+00:00 app[web.1]: I, [2023-01-18T04:32:47.335689 #4]  INFO -- : [bd8c3745-fffc-485c-ba6d-42ff8dbfff91] Started POST "/forum_threads/1/comments" for 137.132.217.46 at 2023-01-18 04:32:47 +0000
2023-01-18T04:32:47.336418+00:00 app[web.1]: I, [2023-01-18T04:32:47.336374 #4]  INFO -- : [bd8c3745-fffc-485c-ba6d-42ff8dbfff91] Processing by CommentsController#create as */*
2023-01-18T04:32:47.336455+00:00 app[web.1]: I, [2023-01-18T04:32:47.336430 #4]  INFO -- : [bd8c3745-fffc-485c-ba6d-42ff8dbfff91]   Parameters: {"User_id"=>1, "forumthread_id"=>"1", "content"=>"<p>Test</p>", "forum_thread_id"=>"1", "comment"=>{"User_id"=>1, "forumthread_id"=>"1", "content"=>"<p>Test</p>"}}
2023-01-18T04:32:47.394387+00:00 app[web.1]: I, [2023-01-18T04:32:47.394318 #4]  INFO -- : [bd8c3745-fffc-485c-ba6d-42ff8dbfff91] Completed 400 Bad Request in 58ms (Views: 0.1ms | ActiveRecord: 36.8ms | Allocations: 3324)
2023-01-18T04:32:47.398408+00:00 heroku[router]: at=info method=POST path="/forum_threads/1/comments" host=highgear.herokuapp.com request_id=bd8c3745-fffc-485c-ba6d-42ff8dbfff91 fwd="137.132.217.46" dyno=web.1 connect=0ms service=60ms status=400 bytes=620 protocol=https

控制台日志输出

下面是Heroku对comments控制器成功GET请求的日志:

2023-01-19T07:19:25.988821+00:00 heroku[router]: at=info method=GET path="/forum_threads/2/comments" host=highgear.herokuapp.com request_id=c9293482-735d-4039-8b40-842bd2bff8ce fwd="137.132.220.33" dyno=web.1 connect=0ms service=23ms status=304 bytes=612 protocol=https
2023-01-19T07:19:25.924581+00:00 app[web.1]: I, [2023-01-19T07:19:25.924514 #4]  INFO -- : [5e0341e6-b66a-4a79-9d33-03050c8933c5] Started GET "/users/2" for 137.132.220.33 at 2023-01-19 07:19:25 +0000
2023-01-19T07:19:25.925293+00:00 app[web.1]: I, [2023-01-19T07:19:25.925219 #4]  INFO -- : [5e0341e6-b66a-4a79-9d33-03050c8933c5] Processing by UsersController#show as */*
2023-01-19T07:19:25.925308+00:00 app[web.1]: I, [2023-01-19T07:19:25.925285 #4]  INFO -- : [5e0341e6-b66a-4a79-9d33-03050c8933c5]   Parameters: {"id"=>"2"}
2023-01-19T07:19:25.927371+00:00 app[web.1]: I, [2023-01-19T07:19:25.927325 #4]  INFO -- : [5e0341e6-b66a-4a79-9d33-03050c8933c5] Completed 200 OK in 2ms (Views: 0.3ms | ActiveRecord: 0.5ms | Allocations: 271)
2023-01-19T07:19:25.964027+00:00 app[web.1]: I, [2023-01-19T07:19:25.963965 #4]  INFO -- : [c9293482-735d-4039-8b40-842bd2bff8ce] Started GET "/forum_threads/2/comments" for 137.132.220.33 at 2023-01-19 07:19:25 +0000
2023-01-19T07:19:25.964537+00:00 app[web.1]: I, [2023-01-19T07:19:25.964491 #4]  INFO -- : [c9293482-735d-4039-8b40-842bd2bff8ce] Processing by CommentsController#index as */*
2023-01-19T07:19:25.964565+00:00 app[web.1]: I, [2023-01-19T07:19:25.964537 #4]  INFO -- : [c9293482-735d-4039-8b40-842bd2bff8ce]   Parameters: {"forum_thread_id"=>"2"}
2023-01-19T07:19:25.986038+00:00 app[web.1]: I, [2023-01-19T07:19:25.985982 #4]  INFO -- : [c9293482-735d-4039-8b40-842bd2bff8ce] Completed 200 OK in 21ms (Views: 0.5ms | ActiveRecord: 20.1ms | Allocations: 210)

如果你需要更多的信息,请告诉我。

编辑:这里有一些关于forumthreads模型的更多信息:

forum_threads_controller:

class ForumThreadsController < ApplicationController
#GET /ForumThreads [Get all threads]
def index
@threads = ForumThread.all
render json: @threads
end
#GET /ForumThreads/:id [Get a specific thread by its ID]
def show
@thread = ForumThread.find(params[:id])
render json: @thread
end
#POST /ForumThreads [Create a thread] 
def create
@thread = ForumThread.new(thread_params)
if @thread.save
render json: @thread
else
render error: {error: "Error in creating thread"}, status: 400
end
end
#PUT /ForumThreads/:id [Update a thread]
def update
@thread = ForumThread.find(params[:id])
if @thread
@thread.update(thread_params)
render json: {message: "Thread successfully updated"}, status: 200
else
render error: {error: "Error in updating thread"}, status: 400
end
end
#DELETE /ForumThreads/:id [Delete a thread]
def destroy
@thread = ForumThread.find(params[:id])
@comments = Comment.where("ForumThread_id = ?", params[:id])
if @thread
for @comment in @comments
@comment.destroy
end
@thread.destroy
render json: {message: "Thread successfully deleted"}, status: 200
else
render error: {error: "Error in deleting thread"}, status: 400
end
end
private
def thread_params
params.require(:forum_thread).permit(:User_id, :title, :description, :tag)
end
end

forum_thread.rb:

class ForumThread < ApplicationRecord
belongs_to :User
end

通过使用@comment.save并以相同的方式处理所有故障,您隐藏了故障的原因。

一个更好的方法是将您的create方法转换为:

# POST /Comments [Create a comment]
def create
@comment = Comment.new(comment_params)
@comment.save!
render json: @comment
rescue ArgumentError, ActiveRecord::RecordInvalid => err
render error: {message: err.message }, status: 400
rescue => err
render error: {message: err.message }, status: 500
end

但是这样做,你最终不得不处理每条路由的失败情况。您更希望为异常使用全局处理程序。例子:

class CommentsController < ApplicationController
rescue_from Exception, with: :render_error
rescue_from ArgumentError, with: :render_bad_request
rescue_from ActiveRecord::RecordInvalid, with: :render_bad_request

# ...

# POST /Comments [Create a comment]
def create
@comment = Comment.new(comment_params)
@comment.save!
render json: @comment
end
# ...
private 

def render_bad_request(err)
render error: {message: err.message }, status: 400
end
def render_error(err)
render error: {message: err.message }, status: 500
end
end

这些全局错误处理程序可以放在每个控制器继承的父类中,以使其更具可重用性:

class BaseController < ApplicationController
rescue_from Exception, with: :render_error
rescue_from ArgumentError, with: :render_bad_request
rescue_from ActiveRecord::RecordInvalid, with: :render_bad_request

private 

def render_bad_request(err)
render error: {message: err.message }, status: 400
end
def render_error(err)
render error: {message: err.message }, status: 500
end
end
class CommentsController < BaseController
# POST /Comments [Create a comment]
def create
@comment = Comment.new(comment_params)
@comment.save!
render json: @comment
end
end