В моем приложении на Rails 6 я хочу модели Post
и Comment
. Когда пользователь просматривает сообщение, он может оставить комментарий. Комментарии отображаются на posts#show
в виде текста со ссылкой для редактирования.
Когда нажата ссылка для редактирования, я хочу показать фрагмент, чтобы пользователь мог редактировать комментарий.
Однако, верно теперь, когда нажата ссылка редактирования, я вижу ошибку 500 в консоли Chrome и не знаю почему.
Вот что я вижу в консоли:
GET http://localhost:3000/posts/7/comments/1/edit 500 (Internal Server Error)
(anonymous) @ VM6383:1
window.XMLHttpRequest.send @ main.js?attr=JpIV9sz…9rF02y-O8AJVkZ:1063
./node_modules/@rails/ujs/lib/assets/compiled/rails-ujs.js.Rails.ajax @ rails-ujs.js:216
./node_modules/@rails/ujs/lib/assets/compiled/rails-ujs.js.Rails.handleRemote @ rails-ujs.js:652
(anonymous) @ rails-ujs.js:172
Пример URL для ссылки редактирования, которая отображается в представлении: http://localhost:3000/posts/7/comments/1/edit
Мой код:
# posts_controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
def index
@pagy, @posts = pagy(Post.where(account_tag_id: params[:account_tag]).sort_by_params(params[:sort], sort_direction))
@tags = current_account.account_tags
@tag = AccountTag.find(params[:account_tag])
end
# GET /posts/1
def show
@comment = Comment.new
@pagy, @comments = pagy(@post.comments.sort_by_params(params[:sort], sort_direction))
end
# GET /posts/new
def new
@post = Post.new
@account_tag = AccountTag.find_by_name(params[:topic])
end
# GET /posts/1/edit
def edit
end
# POST /posts
def create
@post = Post.new(post_params)
@post.account_user_id = current_account_user.id
current_account_user.tag(@post, on: :tags, with: params[:post][:tag_list])
if @post.save
redirect_to @post, notice: 'Post was successfully created.'
else
render :new
end
end
# PATCH/PUT /posts/1
def update
if @post.update(post_params)
redirect_to @post, notice: 'Post was successfully updated.'
else
render :edit
end
end
# DELETE /posts/1
def destroy
@post.destroy
redirect_to posts_url, notice: 'Post was successfully destroyed.'
end
# GET /posts/feed
def feed
@account_tags = current_account_user.account_tags
@pagy, @posts = pagy(Post.where(account_tag_id: @account_tags).sort_by_params(params[:sort], sort_direction))
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
@post = Post.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def post_params
params.fetch(:post, {}).permit(:title, :content, :post_type_id, :account_tag_id)
end
end
# comments_controller
class CommentsController < ApplicationController
before_action :authenticate_user!
before_action :load_post, except: [:upvote, :downvote, :set_flag]
before_action :set_user_comment, only: [:edit, :update, :destroy, :cancel_update]
before_action :set_comment, only: [:upvote, :downvote, :set_flag]
# GET /comments/1/edit
def edit
respond_to do |format|
format.js
end
end
# POST /comments
def create
@comment = @post.comments.create(comment_params)
@comment.account_user = current_account_user
if @comment.save
redirect_to @post, notice: "Thanks for commenting!"
else
redirect_to @post
end
end
# PATCH/PUT /comments/1
def update
if @comment.update(comment_params)
format.js
else
format.js { render :edit }
end
end
def cancel_update
respond_to do |format|
format.js { render :update }
end
end
# DELETE /comments/1
def destroy
@comment.destroy
redirect_to @post, notice: "Your comment has been successfully deleted."
end
# using act as votable for upvote
def upvote
@comment.upvote_by current_account_user
respond_to do |format|
format.html { redirect_back(fallback_location: root_path) }
format.js
end
end
# using act as votable for upvote
def downvote
@vote = Vote.where(votable_type: 'Comment', votable_id: @comment.id, voter_id: current_account_user.id)
@vote.destroy(@vote.id)
respond_to do |format|
format.html { redirect_back(fallback_location: root_path) }
format.js
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
@comment = Comment.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def comment_params
params.require(:comment).permit(:content)
end
def set_user_comment
@comment = current_account_user.comments.find(params[:id])
end
def load_post
@post = Post.find(params[:post_id])
end
end
# comments/edit.js.erb
$('#content_<%= @comment.id %>').html(
'<%= j render(partial: 'comments/edit_content', locals: { comment: @comment, post: @post }) %>'
);
# comments/edit_content.html.erb
<%= simple_form_for [post, comment], remote: true do |f| %>
<% if comment.errors.any? %>
<div class="alert alert-warning">
<% comment.errors.full_messages.each do |msg| %>
<%= msg %>
<% end %>
</div>
<% end %>
<div class="media media-post">
<div class="media-body">
<%= f.input :content, label: false %>
<div class="media-footer pull-right">
<%= f.submit 'Update', class: "btn btn-info btn-sm" %>
<%= link_to 'Cancel',
cancel_update_post_comment_path(comment.post.id, comment.id),
remote: true,
class: "btn btn-info btn-sm"
%>
</div>
</div>
</div>
<% end %>
# routes.rb
resources :posts do
resources :comments, except: [:index, :show, :new] do
member do
get "edit" # I tried with this line, and without
get "cancel_update", to: "comments#cancel_update"
end
end
end
# comments/show_content
<%= simple_format comment.content %>
<%= render 'comments/actions', comment: comment %>
# comments/action
<% if comment.user_id == current_user.id %>
<li><%= link_to 'Edit', edit_post_comment_path(comment.post.id, comment.id), remote: true %></li>
<li><%= link_to 'Delete', post_comment_path(comment.post.id, comment.id), method: :delete %></li>
<% end %>