超初心者がエンジニアになるまでの力戦奮闘の軌跡

プログラミングをメインで学んだことのアウトプットブログ

Railsガイドのわからない用語など #1 ~Railsをはじめよう~

Railsガイド

railsguides.jp

上記のサイトはRailsのガイドが書かれているRailsを使う人間ならば必ず目を通すであろうガイド。 プログラミング初心者である自分はその中でRailsのことだけでなくIT用語でわからない用語が複数出てきたので、しっかりと理解して読み進めていきたいと思う。

なのでこの記事では実際にわからない用語や基礎的な内容で知っておきたいことを調べそれについてまとめていきたい。

わからない用語

スクリプト

⋯プログラムの種類の一つで、人間が読み書きしやすいプログラミング言語で書かれたプログラム(ソースコード)を即座に実行できるようなもの。Railsではジェネレータというものがこのスクリプトのことでこれが多数付属されているためモデル作成などの特定のタスクを行う際に必要なもの(ファイルなど)を自動で生成してくれる。

スキーマ

⋯データベースにおけるスキーマとは「データベースの設計図」のようなもの。OSに置き換えるとディレクトリに相当するのがスキーマで、ファイルに相当するのがテーブルとなる。データベースの構造のようなもの。MySQLでは複数のデータベースを持つことができ、この1つ1つのデータベースをスキーマと定義している。

スモークテスト

⋯開発途上のソフトウェアをテスト(試験)する手法の一つで、開発・修正したソフトウェアを実行可能な状態に組み立て、起動するかどうかや基本的な機能が動作するかなどをざっと確認すること。Railsでははじめlocalhost:3000に接続してRailsの起動ページが表示されるかどうかがスモークテストとなる。

publicメソッド

⋯コントローラはRubyのクラスで、そのクラスのpublicメソッドがアクション。このpublicメソッドは制限が全くないメソッドを指す。

rootルーティングの書き方

root "articles#indexでトップページ(開発の際はhttp://localhost:3000)を開くと自動でindexに割り当てられる

オートロード

Railsではアプリケーションのクラスやモジュールはどこでも利用できるのでrequireを書く必要がない。この機能をオートロードという。

requireを書く必要があるのは、

①lib/ディレクトリの下にあるファイルを読み込むとき

②Gemfileでrequire: falseが指定されているgem依存を読み込むときの2つ。

モデル名

⋯常に単数形で表記する。理由はインスタンス化されたモデルは1件のデータレコードを表すから。この規約を覚えるために、モデルのコンストラクタを呼び出す時にArticle.new()と単数形で書くということを思い出す。

マイグレーション

⋯データベースを操作する機能。マイグレーションファイルのcreate_tableメソッドはarticlesテーブルの構成方法を指定する。create_tableメソッドはデフォルトでidカラムを主キーとして追加する。

create_tableのブロックの末尾業はt.timestampsmwソッドを呼び出す。これでcreated_atupdated_atという2つのカラムを追加している。

ActiveRecord::Relationオブジェクト

⋯allメソッドなどで返すオブジェクトで一種の強力な配列と考える。

ERB(Embedded Ruby)

⋯ドキュメントに埋め込まれたRubyコードを評価するテンプレートシステムのこと。<%= %>などのERBタグを使用。

パラメータ

⋯ルーティングでget "/articles/:id", to: "articles#show":idの部分のことをルーティングパラメータと呼ぶ。これはリクエストのパス(URL)に含まれる特定の値をキャプチャして、その値をparamsというハッシュに保存する。このparamsはコントローラのアクションでもアクセスできる。例えばhttp://localhost:3000/articles/1というリクエストを扱う場合、1がキャプチャされ、showアクションでparams[:id]と書くと1にアクセスできる。

リソースフルルーティング

Railsはresourcesというルーティングメソッドを提供し、リソースの集まり(コレクション)を対応づけるのによく使われるルーティングをすべて対応づけてくれる。

resourcesメソッドではurlで終わるURLヘルパーメソッドと、pathで終わるパスヘルパーメソッドも自動的に設定する。このパスヘルパーを使うことで、コードが特定のルーティング設定依存することを避けられる。たとえば記事1件渡されると、article_pathヘルパーは"/articles/#{article.id}"を返す。

link_toヘルパーを用いる際も、第一引数はリンクテキスト、第二引数はリンク先を記述するが、第二引数にモデルオブジェクト(article)を渡すと、link_toが適切なヘルパーを呼び出してオブジェクトをパスに変換(article_path)する。

redirect_toとrender

⋯redirect_toの場合はブラウザで新しいリクエストを発生させる。なのでデータベースの変更を終えたあとに使うべきで、もしも変更される前に呼び出すとユーザーがブラウザをリロードしたときに同じリクエストが再送信され、変更が重複してしまう。renderは指定のビューを現在のリクエストとしてレンダリングする。

なのでrenderは表示させるviewファイルを指定、redirect_toはURL(HTTPリクエスト)を指定。

フォームビルダー

Railsの機能で、最小限のコードを書くだけで設定が全て出来上がったフォームを表示でき、かつRailsの規約に沿うことができる。

<h1>New Article</h1>

<%= form_with model: @article do |form| %>
  <div>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
  </div>

  <div>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </div>

  <div>
    <%= form.submit %>
  </div>
<% end %>

上記のコードでは、まずform_withというヘルパーメソッドがフォームビルダー(form)をインスタンス化する。そしてform_withのブロック内でフォームビルダーのlabeltext_fieldといったメソッド呼び出すと適切なフォーム要素が出力される。

ストロングパラメータ

⋯フォームから送信されたデータはparamsハッシュに保存され、createアクションなどでparams[:article][:title]などで用いると記事のタイトルにアクセスできる。この値を個別にArticle.newに渡すこともできるがそれだと面倒なのと毎回フィルタをかけなければセキュリティ的に第三者が悪意を持ったデータに書き換え上書きすることができてしまうため、Railsではあらかじめフィルタがかかっていないデータの受け渡しをArticle.newなどにするとForbiddenAttributesErrorと警告が出るようになっている。

そのためストロングパラメータという機能でparamsをフィルタする。

バリデーション

⋯無効なユーザー入力を適切に処理するための機能。バリデーションとはモデルオブジェクトを保存する前に自動的にチェックするルールのこと。そのチェックに失敗した場合は保存を中止し、モデルオブジェクトのerror属性に適切なエラーメッセージが追加される。

モデル側でバリデーションを設定した上で

    <% @article.errors.full_messages_for(:title).each do |message| %>
      <div><%= message %></div>
    <% end %>

のような形でviewに記述することで、full_messages_forメソッドが指定の属性に対応するわかりやすいエラーメッセージを含む配列を1つ返す。その属性でエラーが発生していない場合は配列は空となる。

パーシャル内でインスタンス変数に依存しない

⋯パーシャルファイルは共有ビューのことでそのファイルのコードがいろいろな場面で共有されるので、パーシャル内には特定のインスタンス変数を使わない方がよい。つまりコントローラのアクションで定義されているインスタンス変数を使うと他のアクションで共有する際に不具合が生じる可能性があるため。なのでローカル変数を設定し、インスタンス変数はそのパーシャルを呼び出す際に設定しておく。

<%= render "form", article: @article %>

# 呼び出された_formパーシャル内では@articleをarticleとして扱うという設定
Turboにフックしてdataオプションを使う

Railsバージョン7.0からはデフォルトでTurboというものが含まれているため、destroyアクションで記事を削除する際にはこれを使い、data-turbo-methoddata-turbo-confirmを設定する。

data: {
                    turbo_method: :delete,
                    turbo_confirm: "Are you sure?"
                  }

今回ははこうすることで、turbo_method: :deleteでGETリクエストではなくDELETEリクエストを送信し、turbo_confirm: "Are you sure?"でリンクをクリックすた時に指定した文字列がダイアログに表示されるようになる。

:references

⋯モデルを作成する時に:referencesというキーワードを設定することでモデル名の後ろに_idを追加した名前を持つ新しいカラムをデータベーステーブルに作成する。

モデル同士の関連付け

⋯Active Recordの関連付け機能により簡単に関連付けを宣言できる。

例:記事とコメントという2つのモデルの場合、①1件のコメントは1件の記事に属する。②1件の記事はコメントを複数持てる。

# Commentモデル
class Comment < ApplicationRecord
  belongs_to :article
end

# Articleモデル
class Article < ApplicationRecord
  has_many :comments

  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

上記の宣言によってさまざまな動作が自動化される。たとえば、@articleというインスタンス変数に記事が1件含まれていれば、@article.commentsと書くだけでその記事に関連づけられているコメントを全て取得できる。

concern

Railsの「concern(関心事)」とは、大規模なコントローラやモデルの理解や管理を楽にする手法のこと。複数のモデルやコントローラが同じconcernを共有していれば、それを再利用できるというメリットがある。concernはRubyのモジュールで実装され、モデルやコントローラが担当する機能のうち、明確に定義された部分を表すメソッドをそのモジュールに含める。

実際にrails newでアプリを作成するとapp/内にconcrnsフォルダが作成される。

app/controllers/concerns
app/models/concerns
validationオプションの「inclusionヘルパー」の使い方

⋯concernを扱うに伴い、モデルのvalidationでinclusionというものを使うことになった。これはvalidatesするカラムに入る値を制限するもの。

例:statusカラムにpublic,private,archivedの3つのステータスを設定する場合。

VALID_STATUSES = ['public', 'private', 'archived']

  validates :status, inclusion: { in: VALID_STATUSES }

inclusionヘルパーはinオプションで設定する。

concernのファイルにロジックを移す

⋯例えば記事とコメントのモデルにstatusをarchivedにするようなarchived?メソッドを作るとした時に、ArticleモデルとCommentモデルにそれぞれメソッドを定義すると今後他の機能をつける際にそのモデルにもarchived?メソッドを作らなくてはならなくなる。なのでconcernを利用し、app/models/concernsにvisible.rbという新しいファイルを作りそこに共有するメソッドを定義しておくようにする。

module Visible
  def archived?
    status == 'archived'
  end
end

また、先ほど調べたvalidationのinclusionヘルパーの部分(ステータスを制限する部分)も同じロジックなのでまとめたいが、このようなバリデーションメソッドはクラスレベルで呼び出されるため、より複雑になる。

バリデーションメソッドをconcernでまとめる

⋯バリデーションメソッドの場合はAPIドキュメントのActiveSupport::Concernというものを使用するためにまずextend ActiveSupport::Concernを記述する。

そしてバリデーション部分をincludedで囲む。

module Visible
  extend ActiveSupport::Concern

  VALID_STATUSES = ['public', 'private', 'archived']

  included do
    validates :status, inclusion: { in: VALID_STATUSES }
  end

  def archived?
    status == 'archived'
  end
end

上記のような形にまとめられ、これをモデルでinclude Visibleに修正する。

関連付けの削除

⋯記事を削除するとその記事に関連付けされているコメントも削除したい。そんな時には記事のモデルにdependentオプションを付けることで実現できる。

has_many :comments, dependent: :destroy
BASIC認証

⋯記事の編集やコメントの削除などを認証した人物のみができるようにするためにRailsではHTTP認証システムが用意されている。

# indexアクションとshowアクションは自由にアクセス、それ以外は認証を要求する

class ArticlesController < ApplicationController

  http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]

  def index
    @articles = Article.all
  end

上記を設定すると実際に記事を新規作成する場合などにuser nameとpasswordで認証する必要がある。他にもRailsではDeviseなどのgemで認証システムが作れる。