このページの内容は以下のリポジトリに1日遅れで反映されます(記事執筆前に前日分をコミットしています)。
https://github.com/hkob/hkob_blog
はじめに
Rails Tips の 73 回目です。昨日値限定制約を追加して、status 属性のテストを記述しました。続きで archived? メソッドを追加する部分から concern による Visible module を導入していきましょう。
Visible module の実装
まず、status が archived だった時に true を返す archived?
メソッドを article_spec および comment_spec の両方でテストします。ここにある「配列メソッド呼び出し」は以下で説明しています。
context "複数の Article オブジェクトについて" do let!(:targets) { articles(*%i[article1 can_delete]) } subject { targets } it_behaves_like "配列メソッド呼び出し" do let(:test_set) do { archived?: [nil, [false, false]], } end end end
context "複数の Comment オブジェクトについて" do let!(:targets) { comments(*%i[comment1 can_delete]) } subject { targets } it_behaves_like "配列メソッド呼び出し" do let(:test_set) do { archived?: [nil, [false, true]], } end end end
app/models/concerns/visible.rb を作成し、以下の内容を記述します。
module Visible def archived? status == "archived" end end
article.rb の 2行目に include Visible
を入れたことで、archive?
メソッドが Mix-in されました。これでテストも通過します。
class Article < ApplicationRecord include Visible
複数の Article オブジェクトについて behaves like 配列メソッド呼び出し amst: archived? 上述のメソッドの結果が正しいこと
同様に comment.rb にも追加してみます。こちらもテストが通過しました。
class Comment < ApplicationRecord include Visible
複数の Comment オブジェクトについて behaves like 配列メソッド呼び出し amst: archived? 上述のメソッドの結果が正しいこと
これでモデルのテストは成功していましたが、これにより request_spec が通らなくなっていました。articles_controller の article_params に status が入っていないためです。
def article_params params.require(:article).permit(:title, :body, :status) end
同様に articles/comments_controller の comment_params にも status を追加します。
def comment_params params.require(:comment).permit(:commenter, :body, :article_id, :status) end
後は、定数定義と validates を引っ越したいです。validates はクラスメソッドに相当する処理にあたるので、extend と included を活用します。これにより、article.rb と comment.rb の定数定義、validates は消します。
module Visible extend ActiveSupport::Concern VALID_STATUSES = %w[public private archived] included do validates :status, inclusion: { in: VALID_STATUSES } end def archived? status == "archived" end end
articles/index.html.haml は以下のようにして archived? のものを表示しないようにしました。
- @articles.each do |article| - next if article.archived?
articles/comments/_comment.html.haml の一行目には以下のように archived? の時に処理をやめて return するようにしました。
- return if comment.archived?
articles/_form.html.haml に status を設定する form を設定します。
= form_with model: @article do |f| %table %thead %tr %th 項目 %th 内容 %tbody - %i[title body status].each do |attr| %tr %td= form_label_and_error f, @article, attr %td - case attr - when :title = f.text_field attr - when :status = f.select attr, Article::VALID_STATUSES - else = f.text_area attr, rows: 10, cols: 80 %tr %td{colspan: 2}= f.submit
articles/comments/_form.html.haml も同様です。
= form_with model: [@article, @comment] do |form| %table %thead %tr %th 項目 %th 内容 %tbody - %i[commenter body status].each do |attr| %tr %td= form_label_and_error form, @comment, attr %td - case attr - when :commenter = form.text_field attr - when :status = form.select attr, Comment::VALID_STATUSES - else = form.text_area attr, rows: 10, cols: 80 %tr %td{colspan: 2} = form.hidden_field :article_id = form.submit
おわりに
archived に対する処理を一通り追加してみました。ガイドの内容ももうすぐ終了です。