LoginSignup
0
0

More than 1 year has passed since last update.

Rails6.1ハンズオン(5)~6.1の機能を触る

Last updated at Posted at 2021-07-18

はじめに

Rails6.1ハンズオン(4)の続きです。

ようやくここまできました。今回が最終回です。
コードはGithubにあげています。章ごとにコミットしてますので、参考にしていただければ幸いです。

やること

個人的に気になった(面白そうor仕事で使いそう)機能をピックアップして、現在のRails_6.1_hands_onプロジェクトに追加してみます。

  • Delegated Types
  • Strict Loading
  • ActiveModel::Errorオブジェクト

参考:

Ruby on Rails 6.1の主要な新機能・変更点 - Qiita

6-1. Delegated Types

※単一テーブル継承(STI)とは?

予約語「type(String)」カラムを用いて、単一のテーブルに複数のモデルを定義する

例えば今回の掲示板のCommentモデルについて、

Commentの種類をこれまで実装した「テキスト形式」と新たに追加する「emoji形式」(LINEのスタンプみたいな感じ)に分けるとしたら、以下のようなレコードになる。(具体的な実装は省略)

author type text emoji
taro text (ActionTextへの参照) NULL
jiro emoji NULL 😎

STIだと一つのテーブルで似たようなモデルを管理できるので、実装が楽?になるし、テーブルが無尽蔵に増えなくて管理も楽そう。(仕事で使ったことないのでなんともですが...)

しかし、ものによってはNULLの穴ぼこだらけのテーブルになって、たくさんのレコードを扱うようなシステムだとパフォーマンスに影響が出そう。。。

そこで実装されたのが今回の「Delegated Types」だと解釈しました!

STIのメリットである、代表のテーブルを用いたカラムの共通化をしつつ、モデル毎の微妙な違いは別途テーブルに分けて管理する形になります。(NULLの穴ぼこは無くなります!)

上の例だと、
authorカラムは共通なので、代表としてCommentテーブルの中にauthorカラムを残し、
「違い」である、textカラムとemojiカラムはそれぞれTextテーブルとEmojiテーブルに分けて管理します。

Delegate Typeに則った最終的なテーブル図はこうなります

<図>
Untitled.png

6-1-1. モデル作成

すごく適当なマイグレーションファイルです。。。

def change
    create_table :texts do |t|
      t.timestamps
    end

    create_table :emojis do |t|
      t.integer :emoji_type, null: false, default: 0
    end

    add_column :comments, :content_type, :string, null: false
    add_column :comments, :content_id, :bigint, null: false
end
class Comment < ApplicationRecord
  belongs_to :community
  delegated_type :content, types: %w[Text Emoji]
end

class Text < ApplicationRecord
  has_one :comment, as: :content, touch: true
  has_rich_text :text_content
  delegate :author_name, to: :comment
end

class Emoji < ApplicationRecord
  has_one :comment, as: :content, touch: true
  enum emoji_type: %i[😀 😂 😎]
  delegate :author_name, to: :comment
end

6-1-2. コントローラー・ビュー

一部を略して書きます、詳しくはgithubをご覧ください。

app/controllers/text_comments_controller.rb

class TextCommentsController < ApplicationController
  before_action :set_community

  def new
    @text = Text.new.build_comment
  end

  def create
    # FIXME: バリデーションエラーを無視している
    @community.comments
              .create(content: Text.new(text_content: text_params[:text_content]),
                      author_name: text_params[:author_name])
    redirect_to community_path(@community)
  end

  private

  def set_community
    @community = Community.find(params[:community_id])
  end

  def text_params
    params.require(:comment).permit(:text_content, :author_name)
  end
end

ポイントは親のCommentにcontentという属性で子供のTextやEmojiを渡しているところだと思います。

Untitled 1.png
action_textとただのenumを使い分けられるようになりました。

6-2. Strict Loading

class Community < ApplicationRecord
  has_many :comments, strict_loading: true
end

こんな風につけておくだけで、N+1問題が発生しているときに例外を出すようになります。例外になるので、bulletより強制力がありますね。。。(今回は意味なかったです)

6-3. ActiveModel::Errorオブジェクト

バリデーションエラーが起きたときにモデルのインスタンスに付与されていたエラー情報がただのハッシュではなく、クラスのインスタンスになりました。

app/views/shared/_error_messages.html.haml

- if object.errors.present?
  .card.mb-2.border-danger
    .card-header.bg-danger.text-white
      エラーがあります
    .card-body
      %ul
        - object.errors.each do |e|
          %li= e.full_message

エラー文の呼び出し方が変わって、whereとかも使えるようになって、どこかで使えそうですね。。。

さいごに

このシリーズはこれで以上ですが、今回触らなかったもの(特に並列データベースとかは、大規模な開発で使いそう)もいつか触れたいと思いました。(小並感)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0