モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

工作HardwareHub ロゴ画像 (Laptop端末利用時)
工作HardwareHub ロゴ画像 (Mobile端末利用時)

Rails4のScaffolding機能でCRUDアプリケーションの骨組みを作成する方法

モーダルを閉じる

ステッカーを選択してください

モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2014/06/09
最終更新最終更新
2018/10/07
記事区分記事区分
一般公開

目次

    低レイヤーのプログラミングとOS開発が趣味。C言語を使っています。

    0
    ステッカーを贈るとは?

    Rails4には他のフレームワーク同様、CRUD (Create, Read, Update, Delete) を行うアプリケーションの骨組みとなるファイル一式を自動で出力するScaffolding機能があります。

    事前準備

    $ rails new myApp
    

    としてアプリケーションを作成しておきます。

    Scaffolding機能を利用した骨組みの自動生成

    $ rails generate scaffold myModel field1:string field2:integer field3:date field4:boolean
    (単数形とする。myModelsはダメです)
    

    自動生成されるファイル一覧

    • モデル: app/models/my_model.rb
    • コントローラ: app/controllers/my_models_controller.rb
    • ビューテンプレート: app/views/my_models/index.html.erb
    • ビューテンプレート: app/views/my_models/edit.html.erb
    • ビューテンプレート: app/views/my_models/show.html.erb
    • ビューテンプレート: app/views/my_models/new.html.erb
    • ビューテンプレート: app/views/my_models/_form.html.erb
    • ビューテンプレート(JSON形式): app/views/my_models/index.json.jbuilder
    • ビューテンプレート(JSON形式): app/views/my_models/show.json.jbuilder
    • ビューヘルパー: app/helpers/my_models_helper.rb
    • JavaScript: app/assets/javascripts/my_models.js.coffee
    • CSS: app/assets/stylesheets/my_models.css.scss
    • CSS: app/assets/stylesheets/scaffolds.css.scss
    • DBマイグレーション: db/migrate/20140608073740_create_my_models.rb
    • ルーティングファイルへの追記: config/routes.rb
    • テストスクリプト: test/models/my_model_test.rb
    • テストスクリプト: test/fixtures/my_models.yml
    • テストスクリプト: test/controllers/my_models_controller_test.rb
    • テストスクリプト: test/helpers/my_models_helper_test.rb

    DBマイグレーションを行っておきましょう。

    $ rake db:migrate
    

    サーバーを起動して

    $ rails s
    

    アクセスしてみましょう → http://localhost:3000/my_models

    自動生成されたファイルのカスタマイズ

    ルーティングファイル

    config/routes.rb

    MyApp::Application.routes.draw do
      resources :my_models
    ...
    

    という記述が自動追記されたことによって

    $ rake routes
           Prefix Verb   URI Pattern                   Controller#Action
        my_models GET    /my_models(.:format)          my_models#index
                  POST   /my_models(.:format)          my_models#create
     new_my_model GET    /my_models/new(.:format)      my_models#new
    edit_my_model GET    /my_models/:id/edit(.:format) my_models#edit
         my_model GET    /my_models/:id(.:format)      my_models#show
                  PATCH  /my_models/:id(.:format)      my_models#update
                  PUT    /my_models/:id(.:format)      my_models#update
                  DELETE /my_models/:id(.:format)      my_models#destroy
    

    資源myModelsを操作するために必要なルーティング一式が有効になっていることが分かります。"(.:format)" は省略時には ".html" が使用されます。上述の通りJSON形式のビューテンプレートも自動生成されているので、「http://localhost:3000/my_models.json」というアクセスも可能です。

    ビューテンプレートファイル

    'a'タグを出力するためのヘルパーで、例えば

    <%= link_to 'リンク', 'http://example.com/', target: '_blank' %>
    <%= link_to 'サイト内リンク', { controller: :my_models, action: :index }, id: :link %>
    

    という記述で

    <a target="_blank" href="http://example.com/">リンク</a>
    <a href="/my_models" id="link">サイト内リンク</a>
    

    というHTMLが生成されます。Scaffoldで生成されたファイルでもこのヘルパーは多用されており、例えば

    app/views/my_models/index.html.erb

    <%= link_to 'Show', my_model %>
    <%= link_to 'Edit', edit_my_model_path(my_model) %>
    <%= link_to 'Destroy', my_model, method: :delete, data: { confirm: 'Are you sure?' } %>
    <%= link_to 'New My model', new_my_model_path %>
    

    という記述があります。最初の例でURLを指定した箇所にモデルを指定すると、そのモデルのページへのリンクが生成されます。"edit_my_model_path" や "new_my_model_path" は、

    $ rake routes
    

    を実行して表示される一覧の "Prefix" に "_path" を付けたものです。また、"method:" や "data:" を指定することで

    <a rel="nofollow" href="/my_models/1" data-method="delete" data-confirm="Are you sure?">Destroy</a>
    

    といったHTMLが生成されます。"rake routes" における "Verb" がGET以外の場合には "method:" の指定が必要です。また、data-confirmによって確認ダイアログを表示できます。

    部分テンプレートファイル

    ビュー内で

    <%= render 'form' %>
    

    と記述すると、その部分に

    app/views/my_models/_form.html.erb

    ...
    <%= form_for(@my_model) do |f| %>
      ...
    
      <div class="field">
        <%= f.label :field1 %><br>
        <%= f.text_field :field1 %>
      </div>
      <div class="field">
        <%= f.label :field2 %><br>
        <%= f.number_field :field2 %>
      </div>
      <div class="field">
        <%= f.label :field3 %><br>
        <%= f.date_select :field3 %>
      </div>
      <div class="field">
        <%= f.label :field4 %><br>
        <%= f.check_box :field4 %>
      </div>
      <div class="actions">
        <%= f.submit %>
      </div>
    <% end %>
    

    を挿入することができます。新規登録画面と編集画面など、複数のビューで共通のものを一つにまとめる際に便利です。

    コントローラファイル

    before_action

    複数のアクションメソッドに共通の処理は、一つのprivateメソッドにまとめておくと記述がシンプルになります。

    app/controllers/my_models_controller.rb

    class MyModelsController < ApplicationController
      before_action :set_my_model, only: [:show, :edit, :update, :destroy]
    ...
      private
        # Use callbacks to share common setup or constraints between actions.
        def set_my_model
          @my_model = MyModel.find(params[:id])
        end
    
        # Never trust parameters from the scary internet, only allow the white list through.
        def my_model_params
          params.require(:my_model).permit(:field1, :field2, :field3, :field4)
        end
    end
    

    ":id" の意味については "$ rake routes" の出力を確認してみましょう。また、before_actionで直接はよび出されない処理であっても、例えばPOSTデータをハッシュ形式

    {
      "field1" => 'somevalue'
      "field2" => 'somevalue'
      "field3" => 'somevalue'
      "field4" => 'somevalue'
    }
    

    で返す定型句を "my_model_params" にまとめておくことで、アクションメソッドを簡略化できます。

    モデルを介したDBのテーブル更新

    app/controllers/my_models_controller.rb

    class MyModelsController < ApplicationController
      ...
      # POST /my_models
      # POST /my_models.json
      def create
        @my_model = MyModel.new(my_model_params)
    
        respond_to do |format|
          if @my_model.save
            format.html { redirect_to @my_model, notice: 'My model was successfully created.' }
            format.json { render action: 'show', status: :created, location: @my_model }
          else
            format.html { render action: 'new' }
            format.json { render json: @my_model.errors, status: :unprocessable_entity }
          end
        end
      end
    
      # PATCH/PUT /my_models/1
      # PATCH/PUT /my_models/1.json
      def update
        respond_to do |format|
          if @my_model.update(my_model_params)
            format.html { redirect_to @my_model, notice: 'My model was successfully updated.' }
            format.json { head :no_content }
          else
            format.html { render action: 'edit' }
            format.json { render json: @my_model.errors, status: :unprocessable_entity }
          end
        end
      end
    
      # DELETE /my_models/1
      # DELETE /my_models/1.json
      def destroy
        @my_model.destroy
        respond_to do |format|
          format.html { redirect_to my_models_url }
          format.json { head :no_content }
        end
      end
      ...
    end
    
    • redirect_to → URLを指定してリダイレクト可能です。モデルを指定することもできます
    • notice: → ビューテンプレートで "<%= notice %>" として参照できます
    • render action: 'new' → app/views/my_models/new.html.erb をテンプレートとして使用 (リダイレクトではありません)
    • status: → HTTPステータスコード。レスポンスのヘッダに記載されます
    • location: → リソースURLで、モデルも指定可能。レスポンスのヘッダに記載されます
    • head :no_content → CONTENTのないHTTPレスポンスを返す
    • my_models_url → "$ rake routes" の出力における "Prefix" に "_url" を付けたものです

    その他の関連情報

    複数のレコードを同時に更新

    where句で条件を指定

    cnt = MyModel.where(field1: 'value').update_all(field1: 'value2') # シンボルで指定可能
    # cnt: 更新した件数
    

    order → limit

    cnt = MyModel.order(:field1).limit(10).update_all('field2 = field2 * 0.5') # SQL形式でも指定可能
    # cnt: 更新した件数
    

    複数のレコードを同時に削除

    where句で条件を指定

    MyModel.where('field1 <> ?', 'value').destroy_all
    

    destroy_all 内で指定しても同じ意味

    MyModel.destroy_all(['field1 <> ?', 'value'])
    

    トランザクション

    トランザクションを使用すると、一連の処理がすべて成功しない場合、一部の実行済みの処理をロールバックして、何も実行してない状態まで戻すことができます。具体的には、コントローラ内で以下のように記述します。

    def new
      MyModel.transaction do
        my_model_1 = MyModel.new({field1: 'value'})
        my_model_1.save! # 保存に失敗すると例外を返す (参考: .save は true/false を返す。トランザクションには不向き)
        raise 'わざと例外を発生させています'
        my_model_2 = MyModel.new({field1: 'value2'})
        my_model_2.save!
      end
        # 例外が発生しなかった場合の処理
      rescue => e
        # 例外が発生した場合の処理
        render :text => e.message
    end
    

    なお、トランザクションを使用するためには、データベース側が対応していることが必要です。MySQLの場合、ストレージエンジンとして有名なものに "MyISAM" と "InnoDB" があります。しかしながら "MyISAM" はトランザクションに未対応であるため、"InnoDB" 型としてテーブルを作成する必要があります。具体的には、マイグレーションファイル内で

    class CreateMyModels < ActiveRecord::Migration
      def change
        create_table :my_models, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8' do |t|
          ...
    
        end
      end
    end
    

    と記述することでInnoDBを指定します。

    コールバック

    "DELETE" や "UPDATE" といったデータベース処理の直前や直後にコールバック関数を指定できます。具体的な用途としては、削除対象のレコードを履歴として保存する関数を作成しておきコールバック関数として指定するというものが考えられます。これによって、コントローラ内の各所で同じ処理を記述する必要がなくなり、コードを共通化できます。

    class MyModel < ActiveRecord::Base
      after_destroy :callback_func
    
      private  #← プライベート関数として宣言しましょう
      def callback_func
        # 何か共通の処理
        logger.info('deleted: ' + self.inspect)
      end
    end
    

    ちなみに、destroyした "後" に "self" で内容を参照できているのは "DELETE" が発行される前に一度 "SELECT" が発行されているからです。Railsには "destroy" の他に "delete" メソッドがありますが、こちらの場合は "DELETE" だけが発行されるため、コールバック関数が登録できません。

    MyModel.destroy(params[:id])  #→ SELECT → DELETE
    MyModel.delete(params[:id])   #→ DELETEのみ
    
    0
    詳細設定を開く/閉じる
    アカウント プロフィール画像 (本文下)

    低レイヤーのプログラミングとOS開発が趣味。C言語を使っています。

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    さらに詳しく →
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      関連記事

      • レイアウトおよび部分テンプレートに関するまとめ (Rails4)
        レイアウトおよび部分テンプレートはどちらもテンプレート (*.html.erb) に共通の要素をまとめておき、任意のテンプレートから利用できるようにしておくための仕組みです。フッターやヘッダーといった大枠はレイアウト、小さなパーツは部分テンプレートというイメージで使い分けましょう。 レイアウトの使用方法 クラス毎に指定する方法と、アクション毎に指定する方法があります。 app/views/layo...
        taro三世taro三世10/21/2016に更新
        いいねアイコン画像0
      • Ruby コードスニペット (正規表現)
        sample.rb str = "001: This is a string." var1,var2 = 2,3 # 'EOS'とすると#{}による変数展開がなされない (%03dは展開される) doc = (<<"EOS" % var1) # 括弧は省略可。要は<<"EOS"の次の行からEOSまで。(参: <<-"EOS"とすると前に空白...
        だいふくうさぎだいふくうさぎ5/13/2018に更新
        いいねアイコン画像0
      • OAuthを用いずにTwitterに自動投稿する (回数制限あり, Selenium with Ruby)
        Seleniumを用いて、OAuthを用いずにTwitterに自動投稿するRubyスクリプトを記述してみます。連続で複数回実行すると、ボット判定としてキャプチャ認証が発生します。その認証までは通過できませんので悪しからず。また、Twitterの仕様変更次第ではDOMの構造が変化するため、下記サンプルは機能しなくなる恐れが有ります。 twitter_post.rb #!/usr/bin/ruby r...
      • Ruby における日本語のエンコーディング
        日本語を含めて多言語対応する際には、Asciiコード以外の文字コードセットが必要になります。日本語が主となる場合、よく使われる文字セットにはUnicode, Shift_JIS, EUC-JPがあります。このうち Unicode だけは特殊であり、世界中のあらゆる文字を収録しようとしていることから 1 文字を表現するために必要なバイト数が大きくなってしまっています。そのため Unicode のうち...
        だいふくうさぎだいふくうさぎ4/21/2017に更新
        いいねアイコン画像0
      • Rails3ビューテンプレートの基本的な使用方法 (Ruby)
        Railsでは、ERB (eRuby (テキストファイルにRubyスクリプトを埋込む書式の仕様) をRubyで実装したもの) を用いてHTML内にRubyスクリプトを埋込むことができます。 <% %> で囲むと出力されません (if-elseなど制御構文を記述します) <%= %> で囲むとエスケープ出力されます <%== %> で囲むとエスケープされずに...
        ほんわかパンダほんわかパンダ10/21/2016に更新
        いいねアイコン画像0