Techioz Blog

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 がレンダリングされると、次のようになります。

このとりとめのない答えがお役に立てば幸いです。