我已经构建了一个经典的Rails API后端,该后端具有User
,Comment
,Sighting
。我已通过多态形态关系将Comment
设置为Commentable
。顺便说一下,Sighting
也是User
和Animal
之间的联接表,但是Animal
在这里不相关。
我可以在控制台中通过Sighting.first.comments.create()
创建注释,并通过`Comment.first.comments.create()对注释进行注释,但是当我尝试在路由中查看它们时,不会出现方法错误或路由错误。我需要从React获取请求,所以这些路由需要工作。
我的模特:
class Comment < ApplicationRecord
belongs_to :commentable, :polymorphic => true
has_many :comments, as: :commentable, dependent: :destroy
end
class Sighting < ApplicationRecord
has_one_attached :image
belongs_to :user
belongs_to :animal
has_many :comments, :as => :commentable, dependent: :destroy
def image_filename
self.image.filename.to_s if self.image.attached?
end
def image_attached?
self.image.attached?
end
end
class User < ApplicationRecord
include Rails.application.routes.url_helpers
has_many :sightings
has_many :animals, through: :sightings
has_many :comments, :as => :commentable, dependent: :destroy
has_secure_password
has_one_attached :avatar
def avatar_filename
self.avatar.filename.to_s if self.avatar.attached?
end
def avatar_attached?
self.avatar.attached?
end
validates :username, uniqueness: true
def attachment_url
if self.attachment.attached?
Rails.application.routes.url_helpers.rails_blob_url(self.attachement, only_path: false)
else
nil
end
end
end
我的控制器:
class Api::V1::CommentsController < ApplicationController
before_action :find_comment, only: [:index, :update, :destroy]
before_action :find_commentable
def index
@comments = Comment.all
render json: @comments
end
def create
@comment = @commentable.comments.new(comment_params)
if @comment.save
render json: @comment, status: :accepted
else
render json: { errors: @comment.errors.full_messages }, status: :unprocessible_entity
end
end
def update
@comment.update(comment_params)
if @comment.save
render json: @comment, status: :accepted
else
render json: { errors: @comment.errors.full_messages }, status: :unprocessible_entity
end
end
private
def comment_params
params.require(:comment).permit(:body, :likes)
end
def find_comment
@comment = Comment.find(params[:id])
end
def find_commentable
@commentable = Sighting.find_by_id(params[:sighting_id])
if params[:sighting_id]
@comentables = Comment.find_by_id(params[:comment_id])
if params[:comment_id]
end
end
end
end
class Api::V1::SightingsController < ApplicationController
before_action :find_sighting, only: [:update, :show, :destroy]
def index
@sightings = Sighting.all
render json: @sightings
end
def show
render json: @sighting, status: :ok
end
def create
@sighting = Sighting.new(sighting_params)
# @sighting.image.attach(params[:sighting][:image])
if @sighting.save
render json: @sighting, status: :accepted
else
render json: { errors: @sighting.errors.full_messages }, status: :unprocessible_entity
end
end
def update
# if curr_user.id == @sighting.user_id
@sighting.update(sighting_params)
if @sighting.save
render json: @sighting, status: :accepted
else
render json: { errors: @sighting.errors.full_messages }, status: :unprocessible_entity
end
end
def destroy
if curr_user.id == @sighting.user_id
@sighting.delete
render json: "sighting deleted"
else
render json: { errors: "You are not authorized to delete"}
end
end
private
def sighting_params
params.require(:sighting).permit(:title, :body, :likes, :image, :user_id, :animal_id)
end
def find_sighting
@sighting = Sighting.find(params[:id])
end
end
class Api::V1::UsersController < ApplicationController
before_action :find_user, only: [:update, :show, :avatar_upload, :destroy]
def index
@users = User.all
render json: @users
end
def create
@user = User.new(
username: params[:username],
password: params[:password]
)
if @user.save
encode_token(@user.id)
render json: {user: UserSerializer.new(@user), token: ENV['jwt']}, status: :ok
else
render json: {errors: @user.errors.full_messages}
end
end
def show
if @user
if curr_user.id == @user.id
render json: @user
elsif
curr_user.id == @user.id
# @user.avatar.attach(params[:user][:avatar])
render json: @user
else
render json: {errors: @user.errors.full_messages }, status: :unprocessible_entity
end
else
render json: {errors: "User not found!"}
end
end
def update
if curr_user.id == @user.id
@user.update(user_params)
# @user.avatar.attach(params[:user][:avatar])
if @user.save
render json: @user, status: :accepted
else
render json: { errors: @user.errors.full_messages }, status: :unprocessible_entity
end
end
end
def avatar_upload
@user.update(user_params)
if @user.save
render json: @user, status: :accepted
else
render json: { errors: @user.errors.full_messages }, status: :unprocessible_entity
end
end
def destroy
if curr_user.id == @user.id
@user.avatar.purge_later if @user.avatar
@user.delete
render json: "user deleted"
else
render json: { errors: "You are not authorized to delete"}
end
end
private
def user_params
params.require(:user).permit(:name, :username, :password, :avatar)
end
def find_user
@user = User.find(params[:id])
end
end
我的序列化器
class CommentSerializer < ActiveModel::Serializer
attributes :id, :body, :likes, :user_id
belongs_to :commentable, :polymorphic => true
has_many :comments, as: :commentable, dependent: :destroy
def user_name
User.all.find { |f| f.id == object.user_id }.username
end
end
class SightingSerializer < ActiveModel::Serializer
include Rails.application.routes.url_helpers
belongs_to :user
belongs_to :animal
has_many :comments, :as => :commentable, dependent: :destroy
attributes :id, :title, :body, :likes, :image, :created_at, :user_id
def image
rails_blob_path(object.image, only_path: true) if object.image.attached?
end
end
class UserSerializer < ActiveModel::Serializer
include Rails.application.routes.url_helpers
attributes :id, :name, :username, :avatar
has_many :sightings
has_many :animals, through: :sightings
has_many :comments, :as => :commentable, dependent: :destroy
def avatar
rails_blob_path(object.avatar, only_path: true) if object.avatar.attached?
end
end
和我的路线:
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
post "/rails/active_storage/direct_uploads", to: "direct_uploads#create"
root to: 'sightings#index'
namespace :api do
namespace :v1 do
resources :users, only: [:index, :show, :create, :update, :destroy] do
resources :comments
end
resources :animals, only: [:index, :show, :update]
resources :sightings, only: [:index, :show, :create, :update, :destroy] do
resources :comments
end
resources :comments, only: [:create, :update, :destroy] do
resources :comments
end
put "/users/avatar_upload/:id", to: "users#avatar_upload"
post "/login", to: "auth#login"
get "/current_user", to: "auth#get_user_from_token"
end
end
end
这里是localhost:9000/api/v1/sightings/17/comments
Started GET "/api/v1/sightings/17/comments" for 127.0.0.1 at 2019-03-27 19:15:03 -0400
Processing by Api::V1::CommentsController#index as HTML
Parameters: {"sighting_id"=>"17"}
Completed 404 Not Found in 27ms (ActiveRecord: 19.8ms)
ActiveRecord::RecordNotFound (Couldn't find Comment without an ID):
app/controllers/api/v1/comments_controller.rb:42:in `find_comment'
和localhost:9000/api/v1/sightings
Completed 200 OK in 157ms (Views: 117.3ms | ActiveRecord: 33.9ms)
Started GET "/api/v1/comments" for 127.0.0.1 at 2019-03-27 19:17:07 -0400
ActionController::RoutingError (No route matches [GET] "/api/v1/comments"):
答案 0 :(得分:1)
第一个错误
/api/v1/sightings/17/comments
是/api/v1/sightings/:sighting_id/comments
该路线只有params [:sighting_id]。
它在运行索引操作之前调用before_action:find_comment,并且find_comment需要参数[:id]
但是Api :: V1 :: CommentsController#index没有参数[:id]
所以Rails会发出“没有ID找不到评论”的提示
我认为您在请求索引时不需要调用before_action
将:index
删除为仅条件
before_action :find_comment, only: [:update, :destroy]
第二个错误
resources :comments, only: [:create, :update, :destroy] do
resources :comments
end
此路由没有:index
仅将:index
添加为条件
resources :comments, only: [:index, :create, :update, :destroy] do