SQL文を読み解こう①(Pundit, Simple_form,FormObject,scope)

joinsでテーブルをくっつけた時に発行されたSQL文を読み解くための記事です。RailsのORMであるActiveRecordと実際に発行されるSQLを理解することで、今後ActiveRecordを扱うときのreading力を高めることができると考えやした。#やした

下記項目をざっくり学べます。

・INNER JOIN句

・IN句

・Pluckメソッド

・Pundit gem

・Simple_form gem

・FormObject

・scope

まず下記SQLを読み解く。

SELECT "taxonomies"."id" ・・①
FROM "taxonomies" ・・②
INNER JOIN "article_tags" ・・③
ON "taxonomies"."id" = "article_tags"."tag_id" ・・④
WHERE "taxonomies"."type" 
IN ('Tag') AND "article_tags"."article_id" = ?  [["article_id", 21]] ・・⑤

①何を: taxnomies.idを

②どこから: taxonomiesテーブルから

③どのように: article_tags テーブルとtaxonomiesテーブルをinner joinさせて

④どんな条件で1: taxonomies.idとarticle_tags.tag_idが一緒である

⑤どんな条件で2:Tagモデルにある taxonomies.typeと、article_tags.article_idが22である

補足:

IN句とは

複数の一致するかの条件判定をまとめて行うために使用する命令

【フルーツテーブル(fruit)の、名前が「みかん」か「りんご」の要素を取得する】

SELECT * FROM fruit WHERE name = "みかん" OR name = "りんご";
↑を↓は同じ意味
SELECT * FROM fruit WHERE name IN("みかん","りんご");

どんなコードを書いたら先のSQL文が発行されるか。

順を追って読み解いていきます。

  1. simple_formって何
  2. いやpluckって何
  3. controllerの挙動どうなってるん?
  4. Punditて何
  5. FormObjectて何
  6. ほんでscopeて何なんw

1. simple_formって何

フォームの作成局面で先のSQL文が発行されています。

今回はsimple_formを使い、記事投稿におけるtagの作成を行うフォームを作成しています。

# edit.html.slim
= simple_form_for @article, url: admin_article_path(@article.uuid) do |f|
  = f.input :tag_ids, as: :select2, collection: Tag.pluck(:name, :id), include_blank: false, input_html: { multiple: true }

解説:

@article モデルにf.inputの内容を格納して admin_article_pathに渡しています。admin_article_pathに遷移するときのparams[:uuid]を指定するために(@article.uuid)をadmin_article_pathの後ろにつけています。

simple_formとは

カラムの型に応じてformの種類の自動で判断し生成してくれる便利なgemです。

今回は、select2というタイプを使って、下記のようなフォームを作成しています。値を入れる場所をクリックしたらスクロールで候補を出現させてくれるようなフォームになりますね。

Image from Gyazo

2. いやpluckって何

Tag.pluck(:name, :id)

モデル.pluck(カラム名 [, ...])

Tag.pluck(:name,:id)
# SELECT tag.id, tag.name FROM tag
# [['ruby',1], ['php',2], ['python'],3]

このTagは下記のように構成されていて、pluckを使って、idカラムとnameカラムを上記のように配列形式で表示することができます。

Tag(id: integer, type: string, name: string, slug: string, description: text, created_at: datetime, updated_at: datetime)

3. controllerの挙動どうなってるん?

controller

フォームを入力したときの挙動を記入してあります。

Articleから、渡されたuuidと同じ@articleを取り出しています。ここでは、punditと言うgemを使用し、編集権限を精査しています。punditとは専門家と言う英単語を由来としていて、おそらく、専門⇨その道のプロ⇨プロにしかできないこと⇨ プロ = 管理権限のあるユーザーと言うロジックでしょう。知らんけども。#知らんけども

# controller
class Admin::ArticlesController < ApplicationController
  layout 'admin'

  before_action :set_article, only: %i[edit update destroy]
  def edit
    authorize(@article)
   //とってきたuuidを持つユーザーに編集権限がなければ例外を出す。
  end

  private
  def set_article
    @article = Article.find_by!(uuid: params[:uuid])
  end
end