Ruby on Rails 記事のコメントを編集
概要
目的は記事のコメントを編集することです。
ただし、 <%= render ‘form’, comment: @comment %> を使用して新しいコメントフィールドを表示する方法、または <%= render ‘comment’, comment: @comment % を使用してすでに存在するコメントテキストを表示する方法しかわかりません。 > edit.html.erb 内
<%= form_with モデルも変更してみました: [@article, @article.comments.build] do |form| %> から <%= form_with モデル: @article.comment do |form| %> ただし、Comments#edit で NoMethodError が発生します
ビュー/コメント/edit.html.erb
<h1>Edit comment</h1>
<%= render 'comment', comment: @comment %>
コメント/_form.html.erb
<%= form_with model: [@article, @article.comments.build] do |form| %>
<p>
<%= form.label :commenter %><br>
<%= form.text_area :commenter %>
</p>
<p>
<%= form.label :body %>
<%= form.text_area :body %>
</p>
<p>
<%= form.label :status %>
<%= form.select :status, ['public', 'private', 'archived'], selected: 'public' %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
コメント/_comment.html.erb
<p>
<strong>Commenter:</strong>
<%= comment.commenter %>
</p>
<p>
<strong>Comment:</strong>
<%= comment.body %>
</p>
<%= link_to "Edit comment", edit_article_comment_path(comment.article, comment) %>
<p>
<%= link_to "Destroy comment", [comment.article, comment], data: {
turbo_method: :delete,
turbo_confirm: "Are you sure?"
} %>
</p>
コメントコントローラー.rb
class CommentsController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
def create
@article = Article.find(params[:article_id])
@comments = @article.comments.create(comment_params)
redirect_to article_path(@article)
end
def destroy
@article = Article.find(params[:article_id])
@comment = @article.comments.find(params[:id])
@comment.destroy
redirect_to article_path(@article), status: :see_other
end
def edit
@article = Article.find(params[:article_id])
@comment = @article.comments.find(params[:id])
end
def update
@article = Article.find(params[:article_id])
@comment = @article.comments.find(params[:id])
# redirect_to article_path(@comment)
if @comment.update(comment_params)
redirect_to @comment
else
render :edit, status: :unprocessable_entity
end
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
end
記事_コントローラー.rb
class ArticlesController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
def index
@articles = Article.all
end
def show
@article = Article.find(params[:id])
end
def new
@article = Article.new
end
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render :new, status: :unprocessable_entity
end
end
def edit
@article = Article.find(params[:id])
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render :edit, status: :unprocessable_entity
end
end
def destroy
@article = Article.find(params[:id])
@article.destroy
redirect_to root_path, status: :see_other
end
private
def article_params
params.require(:article).permit(:title, :body, :status)
end
end
ビュー/記事/show.html.erb
<h1><%= @article.title %></h1>
<p><%= @article.body %></p>
<ul>
<li> <%= link_to "Edit", edit_article_path(@article) %></li>
<li>
<%= link_to "Destroy", article_path(@article),
data: { turbo_method: :delete, turbo_confirm: "Are you sure?" } %>
</li>
</ul>
<h2>Comments</h2>
<%= render @article.comments %>
<h2>Add a comment</h2>
<%= render 'comments/form' %>
新しいコメント/_form.html.erb
<%= form_with model: @comment do |form| %>
<p>
<%= form.label :commenter %><br>
<%= form.text_area :commenter %>
</p>
<p>
<%= form.label :body %>
<%= form.text_area :body %>
</p>
<p>
<%= form.label :status %>
<%= form.select :status, ['public', 'private', 'archived'], selected: 'public' %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
新しい記事_コントローラー.rb
class ArticlesController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
def index
@articles = Article.all
end
def show
@article = Article.find(params[:id])
@comment = @article.comments.new
end
def new
@article = Article.new
end
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render :new, status: :unprocessable_entity
end
end
def edit
@article = Article.find(params[:id])
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render :edit, status: :unprocessable_entity
end
end
def destroy
@article = Article.find(params[:id])
@article.destroy
redirect_to root_path, status: :see_other
end
private
def article_params
params.require(:article).permit(:title, :body, :status)
end
end
@comment = @article.comments.new を含めると、Articles#show で ActionController::UrlGenerationError が発生します。 {:action=>“edit”, :article_id=>“11”, :controller=>“comments” に一致するルートがありません、:id=>nil}、記事の「show.html.erb」に必要なキー [:id] がありません。それがないと、form_with を変更すると、コメントを作成できなくなります。エラーは表示されません。
解決策
ほぼすべてのコンピューターと同様に、フォームは実際に指示どおりに動作します。
<%= form_with モデル: [@article, @article.comments.build] |form| を実行します。 %>
おそらく既存のコードは、新しいコメントを作成するのにすでにうまく機能しているでしょう。
既存のコメントを編集しようとしている場合、これはフォームに間違った動作を要求していることを確認するのに役立つと思います。
いくつかのメモ:
(したがって、Rails は NoMethodError と表示します。Article のインスタンスに comment と呼ばれるメソッドがないことがわかります。)
たとえ 1 つしかない場合でも、まったくない場合でも、常にコレクション (配列) になります。最初のコメントの本文が必要な場合は、 @articles.comments.first.body と言う必要があります。 @articles.comments.body を呼び出そうとすると、別の NoMethodError が返されます。
新しいコメントをインスタンス化する他の方法は次のとおりです。
コントローラーに @comment を設定しているので (@comment = @article.comments.find(params[:id]))、それを使用するだけです。
<%= form_with model: @comment do |form| %>
<!--- all the same code you already have -->
<% end %>
ただし、ちょっと待ってください。 comments/_form.html.erb の form_with コードを変更しただけでは、フォームは編集には機能しますが、作成には機能しなくなります。
CommentsController に新しいアクションが含まれていませんでした。これは、ArticlesController アクションの 1 つ (おそらく #show) を介して「新しいコメント」フォームが表示されているためだと思います。これは非常に一般的です。
部分コードを使用しているため、_form.html.erb コードを複数の目的で再利用しようとしています。これは賢明であり、必要に応じて @comment 変数を変更できる場合に機能します。
既存のコメントを編集する場合は、@comment を実際に編集したい既存のコメントに設定する必要があります。あなたは幸運です、すでにそうなっています。
新しいコメントを作成する場合、@comment は、正しい @article にすでに関連付けられている新しいコメントである必要があります。これは次のように行うことができます: @comment = @article.comments.new (または、その方が良い場合は .build)
この新しい変数をどこに追加しますか? 「新しいコメント」フォームを表示するために使用している ArticlesController アクション内 (たとえば、comments/new.html.erb ファイルを参照している場所):
class ArticlesController < ApplicationController
def show
@article = Article.find(params[:id])
@comment = @article.comments.new
end
end
comments/_form.html.erb がレンダリングされると、次のようになります。
このとりとめのない答えがお役に立てば幸いです。