目次
低レイヤーのプログラミングとOS開発が趣味。C言語を使っています。
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」というアクセスも可能です。
ビューテンプレートファイル
link_to ヘルパー
'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のみ
記事の執筆者にステッカーを贈る
有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。
さらに詳しく →Feedbacks
ログインするとコメントを投稿できます。
関連記事
- レイアウトおよび部分テンプレートに関するまとめ (Rails4)レイアウトおよび部分テンプレートはどちらもテンプレート (*.html.erb) に共通の要素をまとめておき、任意のテンプレートから利用できるようにしておくための仕組みです。フッターやヘッダーといった大枠はレイアウト、小さなパーツは部分テンプレートというイメージで使い分けましょう。 レイアウトの使用方法 クラス毎に指定する方法と、アクション毎に指定する方法があります。 app/views/layo...
- Ruby コードスニペット (正規表現)sample.rb str = "001: This is a string." var1,var2 = 2,3 # 'EOS'とすると#{}による変数展開がなされない (%03dは展開される) doc = (<<"EOS" % var1) # 括弧は省略可。要は<<"EOS"の次の行からEOSまで。(参: <<-"EOS"とすると前に空白...
- 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 のうち...
- Rails3ビューテンプレートの基本的な使用方法 (Ruby)Railsでは、ERB (eRuby (テキストファイルにRubyスクリプトを埋込む書式の仕様) をRubyで実装したもの) を用いてHTML内にRubyスクリプトを埋込むことができます。 <% %> で囲むと出力されません (if-elseなど制御構文を記述します) <%= %> で囲むとエスケープ出力されます <%== %> で囲むとエスケープされずに...