【Rails】超便利コマンドscaffoldの使い方を完全理解|何が起こっているかを徹底解説

rails-prograshi(プロぐらし)-kv Rails
記事内に広告が含まれていることがあります。

Railsでデータベース操作を使ったアプリケーションを作成するときに、一覧ページの表示、詳細ページの表示、データの編集・削除機能をまとめて生成してくれる超便利コマンドscaffold(スキャッフォルド)があります。

このscaffoldコマンドの使い方や、具体的に何をしているか、生成されたファイルのそれぞれの意味、間違ってscaffoldを実行してしまったときの取り消し方について、実例で解説しています。


scaffoldとは?

railsにおけるscaffoldとは、DB操作で使う基本的なファイルをまとめて生成するコマンドです。

scaffold自体は、工事現場の足場という意味で、このscaffoldで作成したファイルを足場として細かい処理を追加で記述しカスタマイズしていくイメージになります。


scaffoldの使い方

scaffoldの使い方はとても簡単です。rails g scaffold の後に、テーブル操作のためのモデル名と、テーブルに追加するカラムと型を指定するだけです。( gはgenerateの省略形です。)

モデルを生成する、rails g model の「model」が「scaffold」に置き換わっただけです。

rails g scaffold モデル名 <カラム名1:型1> <カラム名2:型2>,,,

モデル名を指定するときは次の2点に注意してください。

  1. 単数形
  2. 単語をつなげるときは冒頭大文字でつなげる。

例えば、usersテーブルを作成したときは、rails g scaffold userとし、
user_namesテーブルを作成したいときは、 rails g scaffold userName とします。

モデルとテーブルの命名規則

モデルクラス名とテーブル名はそれぞれが対応するように命名規則があります。モデル名を指定するときはこの規則に従います。

rails g modelrails g scaffoldで指定するモデル名の最初の1単語は小文字でも問題ありません。

項目命名規則詳細
テーブルスネークケース複数形全て小文字の複数形
モデルアッパーキャメルケース単数形単語の冒頭が大文字の単数形

テーブル名とモデル名の

テーブル名モデル名モデルファイル名
clientsClientclient.rb
client_numbersClientNumberclient_number.rb

ファイル生成後はrails db:migrate でデータベースにマイグレーションファイルの内容を反映します。

scaffoldで生成されるファイル一覧

scaffoldを実行したときの生成・編集されるファイルはとても多いです。(それだけ多くのものを自動的に生成しています)

大きく次の9つに分けられます。

  1. マイグレーションファイル
  2. モデルファイル
  3. コントローラファイル
  4. ビューファイル(index, edit, show, new, _form)
  5. ヘルパーファイル
  6. SASSファイル
  7. jbuilderファイル
  8. ルーティングファイル
  9. テスト用ファイル

それぞれのファイルの内容は次のようになります。

ファイルの種類内容
マイグレーションファイル DBにテーブルを作成する(rails g db:migrate)
モデルファイルテーブルを操作する(バリデーションや一意の設定など)
コントローラファイルリクエストを受け取り、ビューを開く(ビューに処理したデータを渡す)
ビューファイルブラウザに表示する内容
ヘルパーファイル自作ヘルパの作成
SASSファイルスタイル調整
jbuilderファイルJSON形式のデータを生成する
ルーティングファイル一連のDB操作に必要なルートを生成(resourcesの追記)

なお、ファイルを生成するときに必要なディレクトリも自動で作成します。

例えば、名前(name)と年齢(age)カラムのある、usersテーブルをscaffoldで作成すると次のようになります。

# rails g scaffold user name:string, age:integer
Running via Spring preloader in process 308
      invoke  active_record
   identical    db/migrate/20210729000816_create_users.rb
   identical    app/models/user.rb
      invoke    test_unit
   identical      test/models/user_test.rb
   identical      test/fixtures/users.yml
      invoke  resource_route
       route    resources :users
      invoke  scaffold_controller
   identical    app/controllers/users_controller.rb
      invoke    erb
       exist      app/views/users
   identical      app/views/users/index.html.erb
   identical      app/views/users/edit.html.erb
   identical      app/views/users/show.html.erb
   identical      app/views/users/new.html.erb
   identical      app/views/users/_form.html.erb
      invoke    resource_route
      invoke    test_unit
   identical      test/controllers/users_controller_test.rb
   identical      test/system/users_test.rb
      invoke    helper
   identical      app/helpers/users_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/users/index.json.jbuilder
      create      app/views/users/show.json.jbuilder
      create      app/views/users/_user.json.jbuilder
      invoke  assets
      invoke    scss
       force      app/assets/stylesheets/users.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.scss


マイグレーションファイル

db/migrate/20210729000816_create_users.rb がマイグレーションファイルです。

マイグレーションファイルはテーブルの構造履歴を追えるようにするため、ファイル名にタイムスタンプを入れ、それぞれ固有にしています。

生成されたマイグレーションファイルの中身は次のようになっています。

class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string, :name
      t.integer :age

      t.timestamps
    end
  end
end

usersテーブルに指定したnameカラム、ageカラムと timestampsのカラムを生成する指示になっています。

テーブルの構造管理の詳細は以下をご参考ください。


モデルファイル

app/models/user.rbがモデルファイルです。

class User < ApplicationRecord
end

必要に応じてバリデーションやテーブルのリレーション(関連付け)などを追記します。

それぞれの実例については下記をご参考ください。

コントローラファイル

app/controllers/users_controller.rbはコントローラになります。

コントローラの中には、以下の内容が記述されています。

  • 7つのアクション(index, show, new, edit, create, update, destroy)
  • アクション実行のために必要な処理(メソッド)
  • セキュリティの設定(ストロングパラメータ)の処理
class UsersController < ApplicationController
  before_action :set_user, only: %i[ show edit update destroy ]

  # GET /users or /users.json
  def index
    @users = User.all
  end

  # GET /users/1 or /users/1.json
  def show
  end

  # GET /users/new
  def new
    @user = User.new
  end

  # GET /users/1/edit
  def edit
  end

  # POST /users or /users.json
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        format.html { redirect_to @user, notice: "User was successfully created." }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /users/1 or /users/1.json
  def update
    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to @user, notice: "User was successfully updated." }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1 or /users/1.json
  def destroy
    @user.destroy
    respond_to do |format|
      format.html { redirect_to users_url, notice: "User was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def user_params
      params.require(:user).permit(:name, :age)
    end
end

before_action

before_actionはアクションを実行する前に行うメソッドを指定するものです。コントローラファイルの冒頭に記述します。

before_actionの後ろに:メソッド名 で実行するメソッドを指定します。

#基本形
before_action :メソッド名


#メソッドを複数指定
before_action :メソッド名1, :メソッド名2, :メソッド名3,,, 

onlyやexceptといったオプションも使えます。

#アクションの指定
before_action :メソッド名, only: :アクション名   #1つの場合
before_action :メソッド名, only: [:アクション名1, :アクション名2,,,] #複数の場合


#指定したアクションのみ適用を除外
before_action :メソッド名, except: :アクション名   #1つの場合
before_action :メソッド名, except: [:アクション名1, :アクション名2,,,]  #複数の場合

scaffoldで作成されたファイルは次のようになっています。

show, edit, update, destroyの4つのアクションを実行する前に、set_userメソッドを実行することが指定されています。

before_action :set_user, only: %i[ show edit update destroy ]
%iとは何か?

アクション名の指定に %i が使われています。%iは後ろに続くデータを配列のシンボルにするものです。

%i[show edit update destroy]

↓ 同じ

[:show, :edit, :update, :destroy]


なお、onlyやexcptでアクションを指定するときは、「:」を使ったシンボル以外に、文字列で指定することもできます。

次の4つは全て同じ処理になります。

#シンボルで指定
only: [ :show, :edit ]
only: %i[ show edit ]

#文字列で指定
only: [ "show", "edit" ]
only: %w[ show edit ]

%wは文字列の配列を作り出す処理です。

set_userメソッド

before_actionで指定されている、set_userメソッドはパラメータ(またはPOST)で渡されたid情報を使って、usersテーブルから該当するユーザーの情報を取得し、インスタンス変数@userに代入しています。

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end
    (省略) 
privateとは?

scaffoldで作成したコントローラの末尾には、詳細ページに表示するデータを取得する set_〇〇 とストロングパラメータを指定する 〇〇_params の2つのメソッドが記述されています。

この2つのメソッドはprivateの中に定義されています。

privateとは現在のクラス内からのみアクセス可能なメソッドです。(継承したクラスでも呼び出し可能)

privateより下に記述したメソッドがprivateメソッドとして認識されます。


private以外にもpublicとprotectedがあります。(※Cなど多言語とは定義が異なります)

アクセス制限内容
public制限なし。デフォルトはこの状態
privateクラスの中で呼び出せる。継承したクラスも可
(クラス内でselfなどレシーバーありでは呼び出せない)
protectedクラスの中で呼び出せる。継承したクラスも可。
(クラス内でselfなどレシーバーありでも呼び出せる)

protectedは基本使いません。publicとprivateで対応できます。

レシーバーとは、インスタンスのメソッドを呼び出すときに、インスタンス.メソッド として記述したときの「インスタンス」のことを指します。

hoge.hello であれば、hogeがレシーバーです。
self.hello であれば、selfがレシーバーです。


ストロングパラメータの指定

privateメソッドには、set_user以外に、user_paramsというメソッドも記載されています。

これは、セキュリティのために、指定したカラムのデータしか受け付けないようにする処理です。(Rails4から追加)

具体的には、requireで指定したパラメータの中で、permitで指定した以外のデータを除外しています。

  private
   # Only allow a list of trusted parameters through.
    def user_params
      params.require(:user).permit(:name, :age)
    end

params.require(:パラメータ名) で、指定したパラメータの情報のみを抽出します。

.permit(:パラメータ名,,,)で、渡されたパラメータの中で、指定したパラメータのデータのみに絞り込みを行います。

例えば、userの情報をPOSTすると、action名、controller名、user情報の3つのデータが渡されます。

"action" : "create",
"user": 
  {
    "name": "test",
    "age": 24,
    "roll": 1
  }
"controller" : "users"
}

↓ params.require(:user)で、userのデータのみに絞り込みます。

"user": 
  {
    "name": "test",
    "age": 24,
    "roll": 1
  }

↓ .permit(:name, :age) でデータをnameとageに絞り込みます。

{  
  "name": "test",
  "age": 24
}

これがデータの絞り込みの流れになります。最後に、データをDBのテーブルに登録するcreateアクションにこのデータを渡します。

↓ createアクション

  def create
    @user = User.new(user_params)
    @user.save
  end

これで、指定したデータのみを保存することができます。

パラメータそそのまま渡すのではなく、制約を設けて強化したパラメータなので、ストロングパラメータというわけです。

tips

ストロングパラメータはなぜ必要か?

例えば、usersテーブルに、name, ageと権限を管理するrollの3つのカラムがあった場合に、ブラウザ経由でユーザーが入力できるのは、nameとageだけにしたとします。

このとき、以下のようにDBへの保存処理に受け取ったパラメータをそのまま保存するよう設定している場合、パラメータ名ユーザーで渡された内容をすべて保存されます。

def create
  user = User.new(params[:user])
  user.save
def

ユーザーが 送信データを改ざんして、パラメータに name と age 以外にもrollも付与して送信すると、その情報が全て保存されてしまいます。

▼送信パラメータの例

"user": 
  {
    "name": "test",
    "age": 24,
    "roll": 1
  }
}

こういったDBに登録するデータの改ざんや、意図しないデータの登録を防ぐのがストロングパラメータです。


各アクションの役割

7つのアクション(index, show, new, edit, create, update, destroy) のそれぞれの役割は次のようになります。

アクション内容
index一覧を表示
createデータ追加処理
newデータ追加用の画面
edit指定したデータを変更する画面
show指定したデータの詳細画面
update指定したデータの更新処理(変更箇所のみ)
update指定したデータの更新処理(全体を更新)
destroy指定したデータの削除処理

respond_toとは?

create, update, destroyアクションの処理の中にrespond_to do |format| という処理があります。

これは、リクエストされたフォーマットがHMTLかJSON形式かで処理を分けるための処理です。

記述内容
format.html {処理}HTMLがリクエストされたときに行う処理
format.json {処理}JSONがリクエストされたときに行う処理

リクエストで、HTMLかJSONを切り分けは、URLの末尾に .json をつけるかつけないかです。

リクエストの例内容
https://example.com/usersユーザー一覧ページを表示(HTML)
https://example.com/users.jsonユーザー一覧の情報をJSON形式で表示

実際に、scaffoldで自動生成された、createメソッドの処理内容を確認してみます。

  # POST /users or /users.json
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        format.html { redirect_to @user, notice: "User was successfully created." }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

ストロングパラメータで指定したカラムのデータのみを@userに代入しています。

条件分岐で、@user.saveが実行できた場合は、次の2つの処理に移ります。

format.html { redirect_to @user, notice: "User was successfully created." }
format.json { render :show, status: :created, location: @user }

HTMLのリクエストだった場合は、format.htmlに記述されている処理を実行します。内容は @userにリダイレクトし、そのビューに「User was successfully created.」というnoticeを渡します。

JSONのリクエストだった場合は、format.jsonに記述している処理を実行します。内容は、showアクションのURLで、ページの中身を:locationで指定した@userにし、ステータスコード201(:created)で開く処理になります。

redirect_to @userとは?

redirect_to @userとは、redirect_to user_url(@user.id)を省略したものです。

user_urlとは、ルーティングのprefixを使ってルートを指定する方法です。各ルートのprefixはrails routesコマンドで確認できます。

prefixに_urlヘルパーをつけると、指定したprefixに対応する絶対パスを返します。引数を渡すと、そのパスに指定した引数をパラメータとして渡します。

つまり、 redirect_to @userは、指定したユーザーIDに該当するユーザーの詳細ページへのリダイレクトになります。

参考までに、以下の4つの処理はどれも同じになります。

redirect_to @user
redirect_to user_url(@user.id)
redirect_to “https://example.com/users/#{@user.id}”
redirect_to action: show, id:@user.id

(参考) 【Rails】コントローラの作成方法使い方実例|リダイレクト方法

status: :createdとは?

status: :createdとは、ステータスコード201でページを開く処理です。

200番台のステータスコードは、ページが正しく表示されたことを表します。特に、201を指定すると、ページの内容を新たに生成して表示したということを示します。


Railsのstatusオプションはrenderメソッドと合わせて使います。指定の方法は、:createdのようにシンボルで指定する方法と、201のようにステータスコードをそのまま指定する方法のどちら使えます。

以下の2つは同じです。

status: :created
status: 201

(参考)Railsガイド レイアウトとレンダリング

location: @userとは?

location:とは、renderメソッドで使うオプション一つで、ページの内容を指定します。具体的にはHTTPヘッダーのLocationをURLに指定します。

renderで指定したページの内容を表示するわけではないので、location:オプションを使うときは、ステータスコードは201か、300番台のリダイレクトである必要があります。

locationで値として指定している@userは、user_url(@user.id)を省略したものです。

user_urlとは、ルーティングのprefixを使ってルートを指定する方法です。各ルートのprefixはrails routesコマンドで確認できます。

prefixに_urlヘルパーをつけると、指定したprefixに対応する絶対パスを返します。引数を渡すと、そのパスに指定した引数をパラメータとして渡します。

ここではrenderを使っていつので、user_url(@user.id) で表示するデータをページ内に表示する処理となります。

(参考)


ビューファイル

ビューファイルは app/views/users ディレクトリ配下に次の5つが生成されます。

  1. index.html.erb
  2. edit.html.erb
  3. new.html.erb
  4. show.html.erb
  5. _form.html.erb

index.html.erb

index.html.erbは登録ユーザーの一覧を表示するビューです。

テーブル形式で作成したカラムとその値が表示されるようになっています。

一番下に、新規作成ページへのリンクがあります。<%= link_to 'New User', new_user_path %>

<p id="notice"><%= notice %></p>

<h1>Users</h1>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.name %></td>
        <td><%= user.age %></td>
        <td><%= link_to 'Show', user %></td>
        <td><%= link_to 'Edit', edit_user_path(user) %></td>
        <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New User', new_user_path %>
noticeとは?

<%= notice %>とは、redirect_toでnoticeが指定してある時にその内容を表示します。

index.html.erbにnoticeを渡す処理は、コントローラのdestroyアクションに記載があります。

format.html { redirect_to users_url, notice: "User was successfully destroyed." }

HTML形式でdestroyアクションが実行された場合に、users_url(indexアクションに該当)にリダイレクトし、noticeとして「User was successfully destroyed.」を渡します。

index.html.erbのビューの <%= notice %>に渡されたデータが表示されます。

redirect_toでnoticeを使うときは注意点があります。詳細は下記をご参考ください。

【Rails】redirect_toでnoticeやflash, alertがパラメータになる場合の対処法(%= notice % や%=alert %、flash[:]が表示されない)

link_toとは?

link_toとは、Railsのヘルパーで、指定した内容でlinkタグを生成します。

ビューファイルの中で<%= link_to 'アンカーテキスト',リンク先パス %> として使います。

リンク先のパスの指定方法は複数あります。

<%= link_to 'アンカーテキスト',"絶対パス" %>
<%= link_to 'アンカーテキスト',"相対パス" %>
<%= link_to 'アンカーテキスト',prefix_url(引数) %>
<%= link_to 'アンカーテキスト',prefix_path(引数) %> 
<%= link_to 'アンカーテキスト', オブジェクト %>

<%= link_to 'アンカーテキスト', オブジェクト %>があまり見慣れずトリッキーな指定です。index.html.erbだと以下に該当します。

<%= link_to 'Show', user %>

ここでuserとは、DBのUsersテーブルから抽出した個々のユーザーデータです。モデルを使うとUser.find(n) という指定になります(nはid番号)。

link_toの第2引数にこのパスを渡すと、url_forヘルパーを使って、url_for( User.find(n) )と解釈します。すると、Usersコントローラの指定したユーザーの個別ページへのパスになります。

#link_toのパスの指定 以下は同じ(ID=1の場合)
user
url_for(User.find(1))
"/users/1"
"https:/example.com/users/1"

index.erb.htmlのブラウザでの表示

デフォルトの状態だと、ブラウザの表示は次のようになります。


edit.html.erb

eidt.html.erbは登録ユーザーの情報を変更するためのビューです。

/users/:id/editにアクセスしたときに表示されます。

ページの中身は、_form.erb.htmlにuserというオブジェクト名で@userのデータを渡し、レンダリングしたものがメインになっています。

下部に、Show(詳細ページ)とBack(戻る)のリンクがあります。

<h1>Editing User</h1>

<%= render 'form', user: @user %>

<%= link_to 'Show', @user %> |
<%= link_to 'Back', users_path %>
render ‘form’とは?

render 'form'とは、テンプレートとして、_form.erb.html または form.erb.htmlを表示する記述です。(renderの後ろに直接文字列を指定する記述です)

ファイルの前の「アンダースコア」

_form.erb.htmlのようにファイルの前にアンダースコアがつくものは、ビューファイルの中で部分的に呼び出すビューであることを示しています。

部分的に使うテンプレートのことを「部分テンプレート」や「パーシャル」と言います。

renderで呼び出すときは「_」は省略します。renderの後を’form’とし、第2引数でモデル経由で取得したデータを渡しています。

renderでは呼び出している対象がパーシャルであることを明示するためにpartialオプションをつけることもできます。(データの渡し方が変わります。localオプションを使います)

以下の2つの記述は同じ処理になります。

render 'form'
render partial: 'form'


テンプレートにデータを渡す

テンプレートにデータを渡すときは、,変数名: データ とします。

<%= render 'form', user: @user %>

上記は、_form.erb.html(またはform.erb.html)に@userのデータを変数userとして渡しています。

partialを明示した場合は、localsオプションを使ってデータを渡します。

<%= render partial: 'form', locals: {user: @user} %>

_form.erb.htmlの内容は以下になります。

<%= form_with(model: user) do |form| %>
  <% if user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
        <% user.errors.each do |error| %>
          <li><%= error.full_message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.label :age %>
    <%= form.number_field :age %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

_form.erb.htmlの詳細についてはこちらをご参考ください。


new.html.erb

new.html.erbはデータを新規登録するためのビューです。

/users/newにアクセスしたときに表示されます。

ページの中身は、_form.erb.htmlにuserというオブジェクト名で@userのデータを渡し、レンダリングしたものがメインになっています。

下部でlink_toを使って、Backというアンカーテキストで、users_pathページ、すなわちユーザー一覧 /users へのリンクを設置しています。

<h1>New User</h1>

<%= render 'form', user: @user %>

<%= link_to 'Back', users_path %>


show.html.erb

show.html.erbは選択したデータ(ここではユーザー)の詳細情報を表示する画面です。

/users/:idにアクセスしたときに表示されます。

<p id="notice"><%= notice %></p>

<p>
  <strong>Name:</strong>
  <%= @user.name %>
</p>

<p>
  <strong>Age:</strong>
  <%= @user.age %>
</p>

<%= link_to 'Edit', edit_user_path(@user) %> |
<%= link_to 'Back', users_path %>

冒頭の<%= notice %>は、ユーザー新規作成のcreateメソッドが実行されたときに渡される文字列を表示します。(User was successfully created.)

format.html { redirect_to @user, notice: "User was successfully created." }

末尾にlink_toヘルパで、編集画面と、一覧ページへのリンクを設置しています。


_form.html.erb

_form.html.erbはedit.html.erbとnew.html.erbの中で呼び出される部分テンプレート(パーシャル)です。

_form.html.erbは以下の記述で呼び出すことができます。

<%= render 'form', user: @user %>

_form.html.erbは、form_withヘルパーを使って作成しています。

中身は大きく次の2つのパートから成ります。

  1. DBからのデータ取得時にエラーが発生した場合の処理を記述したif~end
  2. 実際の入力フォーム部分
<%= form_with(model: user) do |form| %>
 
  <%# ーーエラー発生時の処理ーー %>
  <% if user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
        <% user.errors.each do |error| %>
          <li><%= error.full_message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <%# ーー入力フォームーー %>
  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.label :age %>
    <%= form.number_field :age %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

form_withの使い方や、errors.any、pluralize、form.label、form.text_fieldなど、この中で使われている処理の詳細については下記をご参考ください。

【Rails】ファイル名冒頭のアンダースコアやform_with(model: user) do |form|とは何か?scaffoldで生成される_form.html.erbの中身を完全理解


ヘルパーファイル

app/helpers配下に、users_helper.rbというファイルが生成されます。

Railsにはlink_toや_url, _pathなど便利なヘルパがデフォルトで用意されています。このヘルパファイルにメソッドを定義すると自作のヘルパを追加することができます。

ファイルの中身はmoduleになっていて、モジュール名が UsersHelper となっています。デフォルトでは処理は何も記述されていません。

module UsersHelper
end
moduleとは?

moduleとは、インスタンスなどを必要としない処理をまとめて記述する機能です。RailsではなくRubyの機能です。

module モジュール名
 def 処理1
  処理1の内容
 end

 def 処理1
  処理2の内容
 end
 .
 .
 .

 
end

クラスとの大きな違いは次の2点です。

  • インスタンスを生成できない
  • 継承できない

自作ヘルパについては下記をご参考ください。

【Rails】自作ヘルパの作成方法|controllerやscaffoldで自動生成されるapp/helpers/〇_helper.rbの使い方



SASSファイル

スタイル用に、app/assets/stylesheets/配下に、コントローラ名.scssとscaffolds.scssの2つが作成されます。

  1. app/assets/stylesheets/コントローラ名.scss
  2. app/assets/stylesheets/scaffolds.scss


app/assets/stylesheets/コントローラ名.scss

コントローラ名.scssというファイルは、対象のコントローラで処理するビューに関連するスタイルを記述するファイルです。

デフォルトではコメントのみで、中身はなにも記述されていません。

// Place all the styles related to the users controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: https://sass-lang.com/
注意点

記述したスタイルは、application.cssに統合されるため、対象のコントローラに関するビューファイルにのみ適用されるわけではなく、全体に適用されます。


app/assets/stylesheets/scaffolds.scss

scaffolds.scssというファイルには、scaffoldで生成される、show.html.erbや_form.html.erbに適用するデフォルトのスタイルが記述されています。

body {
  background-color: #fff;
  color: #333;
  margin: 33px; }

body, p, ol, ul, td {
  font-family: verdana, arial, helvetica, sans-serif;
  font-size: 13px;
  line-height: 18px; }

pre {
  background-color: #eee;
  padding: 10px;
  font-size: 11px; }

a {
  color: #000; }

a:visited {
  color: #666; }

a:hover {
  color: #fff;
  background-color: #000; }

th {
  padding-bottom: 5px; }

td {
  padding: 0 5px 7px; }

div.field,
div.actions {
  margin-bottom: 10px; }

#notice {
  color: green; }

.field_with_errors {
  padding: 2px;
  background-color: red;
  display: table; }

#error_explanation {
  width: 450px;
  border: 2px solid red;
  padding: 7px 7px 0;
  margin-bottom: 20px;
  background-color: #f0f0f0; }

#error_explanation h2 {
  text-align: left;
  font-weight: bold;
  padding: 5px 5px 5px 15px;
  font-size: 12px;
  margin: -7px -7px 0;
  background-color: #c00;
  color: #fff; }

#error_explanation ul li {
  font-size: 12px;
  list-style: square; }

label {
  display: block; }

このファイルはscaffoldを実行する度に生成されます。(既に存在する場合は上書きするか聞かれます)

scaffoldのオプションで生成しないように指定する

いちいち生成しないようにするには、rails g scaffold実行時に--no-scaffold-stylesheetsオプションをつけることで、生成しないようにできます。

--no-stylesheetsにすればすべてのスタイルシートの作成を除外できます。

config > application.rbで生成しないように指定する

config > application.rbファイルに追記することで、scaffolds.scssの作成を回避することもできます。

require_relative "boot"

require "rails/all"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module RailsVue
  class Application < Rails::Application
    (省略)

     #scaffolds.scssを生成しない
    config.generators do |g|
      g.scaffold_stylesheet false
    end
  end
end

スタイルシートを全て生成しない場合は次のようにします。

require_relative "boot"

require "rails/all"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module RailsVue
  class Application < Rails::Application
    (省略)

     #scaffoldでスタイルシートを生成しない
    config.generators do |g|
      g.stylesheet false
    end
  end
end


jbuilderファイル

jbuilderファイルはJSON形式のデータを生成するためのファイルです。

Railsにデフォルトで搭載されているjbuilderというgem(パッケージ)を使っています。拡張子を.json.jbuilderとし、指定の記述に沿って中身を書けば、JSON形式のデータとして出力されます。

scaffoldで生成されるファイルは次の3つです。いずれも、app/views/コントローラ名配下のディレクトリに生成されます。

  • app/views/users/index.json.jbuilder
  • app/views/users/show.json.jbuilder
  • app/views/users/_user.json.jbuilder

ファイルを開くためには、通常のビューファイル 〇〇.html.erbと同じ階層に、〇〇.json.jbuilderを作成し、〇〇.html.erbに対するURI(パス)の末尾に.jsonをつけてアクセスします。

例えば、URIがhome/indexのときに、index.html.erbが開かれる場合、同じ階層に、index.json.builderを設置して、home/index.json とすればアクセスすることができます。


index.json.jbuilder

index.json.jbuilderは、app/views/users/index.html.erb(ユーザー一覧)に対応するJSONデータを返します。

ファイルの中身は次のようになっています。

json.array! @users, partial: "users/user", as: :user

json.array!は指定したモデルインスタンスのデータをJSONにして配列に入れる処理です。

partialで、usersディレクトリ配下の _user.json.jbuilderをパーシャルとして呼び出しています。その際、@usersというデータ(@users = Users.all)をuserというキー名でパーシャルに渡しています。


_user.json.jbuilder

_user.json.jbuilderは、Jbuilderのパーシャルです。index.json.jbuilderとshow.json.jbuilderの中で呼び出されています。

ファイルの中身は次のようになっています。

json.extract! user, :id, :name, :age, :created_at, :updated_at
json.url user_url(user, format: :json)

json.extract!は対象のデータのうちカラムを指定したもののみを取得する処理です。

json.url user_url(user, format: :json)は、キー名が「url」値が「user_url(user, format: :json)」のデータです。"url":"http://localhost:3001/users/3.json" のようなキーと値のセットを返します。


show.json.jbuilder

show.json.jbuilderは、app/views/users/show.html.erb(ユーザー詳細)に対応するJSONデータを返します。

ファイルの中身は次のようになっています。

json.partial! "users/user", user: @user

json.partial!はパーシャルを呼び出す処理です。

usersディレクトリ配下の _user.json.jbuilderをパーシャルとして呼び出しています。その際、@userというデータ( @user = Users.find(prams[:id]) )をuserというキー名でパーシャルに渡しています。

出力結果の例

上記設定で、それぞれ、/users.jsonと、/users/1.jsonにアクセスするとWEBページの表示は次のようになります。(データは別途保存済み)

▼/users.json

[{"id":1,"name":"test1","age":24,"created_at":"2021-07-29T04:38:52.761Z","updated_at":"2021-07-29T04:38:52.761Z","url":"http://localhost:3001/users/1.json"},{"id":3,"name":"test2","age":25,"created_at":"2021-07-30T23:18:28.177Z","updated_at":"2021-07-30T23:18:28.177Z","url":"http://localhost:3001/users/3.json"},{"id":4,"name":"test3","age":28,"created_at":"2021-07-30T23:19:35.242Z","updated_at":"2021-07-30T23:19:35.242Z","url":"http://localhost:3001/users/4.json"},{"id":5,"name":"test4","age":30,"created_at":"2021-07-30T23:19:44.976Z","updated_at":"2021-07-30T23:19:44.976Z","url":"http://localhost:3001/users/5.json"},{"id":6,"name":"test5","age":32,"created_at":"2021-07-30T23:19:54.558Z","updated_at":"2021-07-30T23:19:54.558Z","url":"http://localhost:3001/users/6.json"}]


▼ /users/1.json

{"id":1,"name":"test1","age":24,"created_at":"2021-07-29T04:38:52.761Z","updated_at":"2021-07-29T04:38:52.761Z","url":"http://localhost:3001/users/1.json"}


Jbuilderは決まった規則に沿って書けばいろいろなデータをJSON形式で返すことができます。詳細については下記をご参考ください。

【Rails】便利なJbuilderの使い方|ブラウザにJSON形式のデータ表示する方法


ルーティングファイル

ルーティングを記述する、config > routes.rb には、resourcesが追加されます。

Rails.application.routes.draw do
  resources :users
end

resourcesとは、DB操作に必要な8つのルーティングをまとめて生成してくれる便利な記述です。

使うときはresources :コントローラ名 として記述します。

▼resourcesで生成されるルート

アクションHTTP動詞パス内容
indexGET/コントローラ名一覧を表示
createPOST/コントローラ名データ追加処理
newGET /コントローラ名/newデータ追加用の画面
editGET/コントローラ名/:id/edit指定したデータを変更する画面
showGET/コントローラ名/:id指定したデータの詳細画面
updatePATCH/コントローラ名/:id指定したデータの更新処理(変更箇所のみ)
updatePUT/コントローラ名/:id指定したデータの更新処理(全体を更新)
destroyDELETE/コントローラ名/:id指定したデータの削除処理

実際に登録されたルートを確認するには、rails routesコマンドを実行します。

# rails routes
   Prefix Verb   URI Pattern                Controller#Action
new_user  GET    /users/new(.:format)         users#new
edit_user GET    /users/edit(.:format)        users#edit
users     GET    /users/(.:format)            users#show
          PATCH  /users/(.:format)            users#update
          PUT    /users/(.:format)            users#update
          DELETE /users/(.:format)            users#destroy
          POST   /users(.:format)             users#create


なお、resourcesで生成するルートは、onlyやexceptなどのオプションを使って限定することもできます。resourcesをネストさせることもできたりと自由度は高めです。

resourcesの詳細については下記をご参考ください。

【Rails】ルーティングのresourcesとは?意味と使い方


scaffoldの実行結果を簡単に取り消す方法

scaffoldは便利なコマンドですが、生成されるファイルが多いため、モデル名やカラムを間違えた場合に、手動で元の状態に戻すのは大変です。

そんな時のために、Railsにはscaffoldの実行をなかったことにする便利なコマンドがあります。

rails destroy scaffoldコマンド

次のコマンドを実行すると、scaffoldの実行結果を取り消すことができます。

rails destroy scaffold <モデル名>

destroyには省略形はありません。(generateがgになるように、destroyがdにはならない)

scaffoldの後ろには rails g scaffoldと同じものを記載しておけば問題ありません。


実例

まずは、rails g scaffold でファイル群を生成します。

# rails g scaffold project name:string age:integer price:integer
Running via Spring preloader in process 63
      invoke  active_record
      create    db/migrate/20210731095320_create_projects.rb
      create    app/models/project.rb
      invoke    test_unit
      create      test/models/project_test.rb
      create      test/fixtures/projects.yml
      invoke  resource_route
       route    resources :projects
      invoke  scaffold_controller
      create    app/controllers/projects_controller.rb
      invoke    erb
      create      app/views/projects
      create      app/views/projects/index.html.erb
      create      app/views/projects/edit.html.erb
      create      app/views/projects/show.html.erb
      create      app/views/projects/new.html.erb
      create      app/views/projects/_form.html.erb
      invoke    resource_route
      invoke    test_unit
      create      test/controllers/projects_controller_test.rb
      create      test/system/projects_test.rb
      invoke    helper
      create      app/helpers/projects_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/projects/index.json.jbuilder
      create      app/views/projects/show.json.jbuilder
      create      app/views/projects/_project.json.jbuilder
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/projects.scss
      invoke  scss
   identical    app/assets/stylesheets/scaffolds.scss

↓ 取り消し

rails destroy scaffoldを実行すると生成したファイルをすべて削除されました。

# rails destroy scaffold project name:string age:integer price:integer
Running via Spring preloader in process 76
      invoke  active_record
      remove    db/migrate/20210731095320_create_projects.rb
      remove    app/models/project.rb
      invoke    test_unit
      remove      test/models/project_test.rb
      remove      test/fixtures/projects.yml
      invoke  resource_route
       route    resources :projects
      invoke  scaffold_controller
      remove    app/controllers/projects_controller.rb
      invoke    erb
      remove      app/views/projects
      remove      app/views/projects/index.html.erb
      remove      app/views/projects/edit.html.erb
      remove      app/views/projects/show.html.erb
      remove      app/views/projects/new.html.erb
      remove      app/views/projects/_form.html.erb
      invoke    resource_route
      invoke    test_unit
      remove      test/controllers/projects_controller_test.rb
      remove      test/system/projects_test.rb
      invoke    helper
      remove      app/helpers/projects_helper.rb
      invoke      test_unit
      invoke    jbuilder
      remove      app/views/projects
      remove      app/views/projects/index.json.jbuilder
      remove      app/views/projects/show.json.jbuilder
      remove      app/views/projects/_project.json.jbuilder
      invoke  assets
      invoke    scss
      remove      app/assets/stylesheets/projects.scss
      invoke  scss


destroyでカラム名と型を指定しないとどうなるか?

rails g scaffoldコマンドを実行するときには、カラム名と型も指定します(オプション)。

ですが、rails destroy scaffoldのときは、モデル名だけ指定した場合と、カラム名と型も指定した場合で同じ結果になります。

カラム名と型はファイルの数ではなく、ファイルの中の処理に影響を与えるものなので、destoryのときには影響しないようです。

試しに、rails g scaffold project name:string age:integer price:integer の実行結果に対して、以下の2つをそれぞれ実行してみましたが、結果は同じものになりました。

  • rails destroy scaffold project name:string age:integer price:integer
  • rails destroy scaffold project

▼実行結果の比較


destroyの注意点

destroyはマイグレーションファイルなど、rails g scaffoldで生成したすべてのファイルを削除します。

このため、rails db:migrateを実行しマイグレーションしたあとに行うと、対象のマイグレーションファイルがなくなり、DBのバージョン管理ができなくなります。

DBのバージョン管理ができなくなると、ロールバックができなくなります。

このような注意点あるので、destroyは状況に合わせて使うようにしてください。

ロールバックについては下記をご参考ください。

【Rails】ロールバック(rollback)で何が起こっているか?schema_migrationsとは?意味と役割。UPとDOWNとは?それぞれの使い方

タイトルとURLをコピーしました