最近ちょっと作りたいサービスがあって、サーバサイドとしてRuby on Railsをやってみようと思い立ち、入門してみました。
そもそもRuby自体ほとんど書いたことないので、細かいものをつらつらとメモしていきます。
Railsとは
Railsにはいくつか大事な考え方があるようです。
ひとつは DRY(Don't Repeat Your self)で、同じことを繰り返すな、ということ。なので同じ記述が現れるところはどんどん共通化していく方針のようです。(そのための仕組みが多数用意されています)
そしてもっとも大事なものが「設定より規約」と呼ばれるソフトウェア設計パラダイムです。
端的に言うと、規約に基いてコードを書けば設定はいらない、ということです。
つまり、Rails側で規約を定めていて、その規約に則ってコードを書いている限り、設定を書く必要がなくなります。
なので、ルールに基いてモデルクラスを宣言するだけで基本的な処理(Create, Read, Update, Delete)などは自動的に行われます。
MVCに基づく設計
後述しますが、モデルやコントローラのひな形を自動生成してくれる便利なコマンドがあります。
基本的な処理はそのコマンドから初めて、必要な箇所だけあとから編集、というのがおおまかな処理の流れになると思います。
Model
app/models
に配置されます。
Modelは ActiveRecord::Base
クラスを継承したものになります。
基本的な CRUD (Create, Read, Update, Delete)
の仕組みはベースクラスで定義されているため、特殊な処理がないモデルの場合は以下のように定義するだけで基本的な機能を使うことができます。
コメントで指摘もらいましたが、あくまでその処理を行うことが定義されている、という意味です。
なので実際にアプリケーションとして実行可能な状態にするにはコントローラなどとの連携が必要になります。
class Product < ActiveRecord::Base
end
インタラクティブな操作
以下のコマンドを使うと、ターミナルからインタラクティブにモデルデータの操作を行うことができます。
$ rails console
Loading development environment (Rails 4.2.3)
2.2.3 :001 >
実行すると上記のようになるので、そこにRubyのコードを書いてモデルの生成を行うと、そのままDBに反映することができます。
(ちなみに quit
で抜けることができます)
例)
Product.create(title: "hoge")
Modelを作成する
モデルクラスのひな形とDBのマイグレーションファイルを作成するには以下のコマンドを実行します。
$ rails g model ModelName fieldName1:string fieldName2:integer
ちなみに、デフォルトの型は string
のため、string
の型の場合は省略することができます。
また、いわゆる has meny
な関係を作りたい場合は以下のようにします。
$ rails g model Hoge title fuga:references
ここについては少し勘違いをしていました。
コメントを引用させてもらうと以下の意味のようです。
fuga:references は,Fuga モデルに属すること(belongs_to)を含意しているだけです。Fuga モデルから見てこちらを has_many とは限りません。has_one かもしれない。
上記を実行するとHogeクラスには belogns_to :fuga
が自動挿入されます。
ただ、fugaモデルにはその記述が自動挿入されないので、手で追記する必要があります。
class Fuga < ActiveRecord::Base
has_many :tasks # あるいは has_one
# ...
end
Modelで使用される型
型 | 概要 |
---|---|
string | 文字列 |
text | 長い文字列 |
integer | 整数 |
float | 浮動小数点数 |
decimal | 精度の高い小数 |
datetime | 日時 |
timestamp | タイムスタンプ |
time | 時刻 |
date | 日付 |
binary | バイナリ |
boolean | 真理値 |
primary_key | 主キー |
Modelのカラムを更新する
こちらの記事を参考にしました。
Modelのカラムを更新するには、マイグレーションスクリプトを生成し、それを実行する必要があります。
例えば、url
と message
という新しいカラムを追加する場合は以下のようにします。
$ rails g migration AddXXXToYYYY columnName:columnType (columnName:columnType ...)
ここで、XXX
は追加するカラム名など任意の文字列です。(複数追加する場合などは明示できないため)
そして YYY
は対象のテーブル名をスネークケースで指定します。
仮に any_models
というテーブル名だったとしたら、 AddParamsToAnyModels
という感じです。
そしてこれを実行するとRails側で適切にマイグレーションスクリプトを生成してくれます。
あとはこれを実行してあげればDBがマイグレーションされます。
$ rake db:migrate
ちなみに db/migrate/2015....rb
みたいな形でファイルが生成されますが、これを削除する場合は以下のようにします。
$ rails destroy migration AddParamsToAnyModels
ファイルを直に消しても大丈夫かはやってないので分かりません・・。
Modelに関する規約
Railsのルール(規約)として、モデルは 大文字始まりの単数形 が定められています。
Controller
app/controllers
に配置されます。
ユーザからの操作を受け付けて、アプリケーションの動作を決定するコントローラです。
ルーティングを設定する
プロジェクトディレクトリの下に config
ディレクトリがあります。
その中の routes.rb
ファイルにルートをに関する設定をしてあげると自動的にそのルーティングを行う処理を実行してくれます。
Rails.application.routes.draw do
resources :projects
# 以下略
end
rootを設定する
サイトトップにアクセスしたときなどに、どこを表示して欲しいかをコントローラとアクションの単位で指定しておくことができます。
例)
root 'projects#index'
上記のようにすると、トップに来た場合に projects
の index
アクションが実行されます。
URLの階層を定義する
以下のようにすることで、あるモデル以下に紐付いた他モデルのデータ(has many的な)を表示、というようなURLのルーティングを実現することができます。
(いわゆるhas manyの関係にあるデータの表示とか)
resources :projects do
resources :tasks, only: [:create, :destroy]
end
こうすることで、とあるプロジェクトに紐付いたタスク一覧を表示するURLを設定することができます。
特定URLをアクションに結びつける
このURLにアクセスしたらこのアクションを実行したい、という場合は以下のようにすることで設定することができます。
post '/projects/:project_id/tasks/:id/toggle' => 'tasks#toggle'
tasks
はコントローラです。そのコントローラの toggle
メソッド(アクション)を実行する設定です。
Controllerのルーティングを確認する
ルーティングの設定ができたら rake routes
コマンドでルーティングを確認することができます。
$ rake routes
Prefix Verb URI Pattern Controller#Action
project_tasks POST /projects/:project_id/tasks(.:format) tasks#create
project_task DELETE /projects/:project_id/tasks/:id(.:format) tasks#destroy
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PATCH /projects/:id(.:format) projects#update
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
POST /projects/:project_id/tasks/:id/toggle(.:format) tasks#toggle
root GET / projects#index
before_action, after_action
モデルの取得など、各アクションの中で共通に処理する部分があるかと思います。
その際に、同じことを書くのはDRYに反するので、before_action
や after_action
に処理をまとめることで共通化することができます。
具体的には以下のようにします。
class ProjectsController < ApplicationController
before_action :anyMethod, only: [:show, :edit]
private
def anyMethod
# do common action
end
end
ちなみにこの before_action
という記述はRubyの機能で、クラス・メソッドなどを指定するとそれがクラス宣言時に実行されるようになります。
※ コメントで指摘をもらったので補足しておきます。before_action
というメソッド自体はRails側の機能です。ただ、クラス宣言時に実行される、という点がRubyの機能という意味です。
Controllerに関する規約
モデルを操作するコントローラを作成する場合は同様に、モデル名の複数形で作成する必要があります。上記の例で言えば Projects
。
さらに、上記のルーティングで示されている Controller#Action
の項目が、コントローラにどのメソッドを実装したらどのアクションが実行されるかを表しています。
例えば、index
メソッドを実装すれば /projects(.:format)
にアクセスされたときにそれが実行されます。
View
app/views
に配置されます。
HTMLをレンダリングし表示するビュー。
ちなみに ERB(Embed RuByの略)
を利用してHTMLを構築します。
<% if (hoge) %>
ここにHTML
<% end %>
<%= hoge.name %>
<% ~ %>
と <%= ~ %>
という記述方法がある。
前者はRubyを実行するだけで返り値は無視されますが、後者は戻り値がそのままHTMLとして出力される点が異なります。
パーシャルを使う
DRY(Don't repeat your self)の精神で、同じことを記述することを避けるのがRails風です。
ということで、Viewの中で同じ記述が現れる箇所がある場合は、「パーシャル」という機能を使ってまとめておくと便利です。
パーシャルの使い方にもルールがあり、以下のように記述します。
<%= render 'hoge' %>
上記は erb
ファイルの一部です。上記のように render
メソッドを使ってパーシャルを呼び出します。
パーシャル自体は、Viewsの中に、renderの引数に渡された文字列にアンダースコアを付けたファイル(上記の例では _hoge.erb
)を作成し、そこに共通項目を書きます。
あとはRailsが規約に則って該当のパーシャルのその位置に読み込んでくれます。
Viewに関する規約
Viewに関する規約は、コントローラのアクション名と同名のファイル名にする、という点です。
(例えば index
アクションなら index.html.erb
ファイル)
共通テンプレート
Viewはまた、共通テンプレートを持つことができます。HTML内のhead要素などサイト内で共通にしておきたいものはたくさんあると思います。
それらについては app/views/layouts
ディレクトリ内に配置されます。
また、各Viewに記述された内容はテンプレート内の <%= yield %>
に展開されるようになっています。
プロジェクトの作成
以下の rails
コマンドでさくっと新規プロジェクトが生成できます。
$ rails new hoge
データ(モデル)の作成
モデルの作成には bundle exec rails generate scaffold
を使います。
$ rails generate scaffold hoge name:string fuga:string
ちなみに、generate
は g
のみでも実行可能です。
$ rails g scaffold hoge name:string fuga:string
また、DBのマイグレーションファイルも自動生成されるため、以下のようにすることでDBをマイグレーションすることができます。
$ rake db:migrate
作成したアプリケーションの動きをブラウザで確認する
$ rails server
s
だけでも起動できます。
$ rails s
bundle exec
いくつかのコマンドで bundle exec
というのが使われていますが、これは、プロジェクト内の vendeor/bundle
内に保存されている gem
を使うためのコマンドのようです。
Rails 4からの便利機能
http://localhost:3000/rails/info/routes
でルートを確認することができます。
POSTやGETの種類、引数としてどんなパラメータが必要かなどが一覧されるので便利。
覚えておきたいメモ
レスポンスを JSON
で返します。
controllerで出し分けができるみたい。
具体的には以下。
class AnyController < ApplicationController
def index
@products = Product.all
respond_to {|format|
format.html # => 通常のアクセス
format.json { render json: @products } # URLが `.json` でのアクセス
}
end
end
上記のように、アクション処理の中で respond_to
メソッドを使って、フォーマットに応じて処理を分けてやると実現できます。
Rubyについてのメモ は別記事に移動しました。
JSONを返すAPIで
スタブ環境みたいなものを作ろうと思って、モデルを2つ用意して、それをネストしてJSONとして返す、みたいなことをやろうとして意外とハマったのでメモ。
以下のようなモデルがあったとして。
class HogeModel < ActiveRecord::Base
has_one :fuga_model
end
class FugaModel < ActiveRecord::Base
belongs_to :hoge_model
end
こんな感じでコントローラを書く。
class HogeModelsController < ApplicationController
def index
@hoge_models = HogeModel.all
@fuga_models = FugaModel.all
render :json => @hoge_models, :methods => :fuga_model
end
end
まだRubyからして怪しいけど、とりあえずこれで目的のような形になった。