パーシャルのフォームをレンダリングする: 小林研 Rails Tips (67)

このページの内容は以下のリポジトリに1日遅れで反映されます(記事執筆前に前日分をコミットしています)。

https://github.com/hkob/hkob_blog

はじめに

Rails Tips の 67 回目です。Rails ガイドでは、コメントのエラーに対する対応がされていません。これは index の中にフォームを書いているために、エラー対応ができないためでした。せっかくなのでその部分を対応するようにしたいと思います。

Rails をはじめよう - Railsガイド

9.2 パーシャルのフォームをレンダリングする

Rails ガイドでは、show に直接 form を書き込んでいました。二度手間になるので、この部分を部分テンプレートにします。また、そのあとで追加するコメント一覧の部分も部分テンプレートで表示します。app/views/articles/show.html.haml は以下のようになりました。

- content_for :title do
  - @page_title = @article.title

%p= @article.body

%ul
  %li= lotfp edit_article_path(@article)
  %li= destroy_lotfp article_path(@article), Article

%h2 Comments
= render partial: "articles/comments/comment", collection: @comments

%h2 Add a comment:
= render "articles/comments/form"

articles/comments/_comment.html.haml は以下のようになります。

- %i[commenter body].each do |attr|
  %p= t_ars Comment, attr
  %p= comment.send attr

同様に articles/comments/_form.html.haml は以下のようになります。ガイドでは、その場で @article.comments.build で新規オブジェクトを作成していますが、これだと既存のエラーが発生したオブジェクトが捨てられてしまうので、あくまで @comment というインスタンス変数にしています。こちらは後でコントローラで作成します。

= form_with model: [@article, @comment] do |form|
  %table
    %thead
      %tr
        %th 項目
        %th 内容
    %tbody
      - %i[commenter body].each do |attr|
        %tr
          %td= form_label_and_error form, @comment, attr
          %td
            - case attr
            - when :commenter
              = form.text_field attr
            - else
              = form.text_area attr, rows: 10, cols: 80
      %tr
        %td{colspan: 2}= form.submit

ここで利用する @comments@commentarticles_controller の show で取得します。

  def show
    @comments = @article.comments.order_created_at_desc
    @comment = @article.comments.build
  end

order_created_at_desc は comment.rb 内の scope で作成します。先に comment_spec.rb でテストをしておきます。降順確認は以下で解説しています。

  describe "Comment クラスについて" do
    context "order_bar_desc" do
      subject { described_class.order_created_at_desc }
      it_behaves_like "降順確認", Date.today + 1, ->(o) { o.created_at }
    end
  end

このテストを通すために、comment.rbscope を追加します。

  scope :order_created_at_desc, -> { order(created_at: :desc) }

おわりに

これでとりあえず form まで表示されることまで確認しました。少し長くなったので、コントローラのテストと実装は明日に回します。