今さらRails3メモ - その2 : C, V を中心に -

とりあえず scaffold する

最初は様子がよく分からないので

r g scaffold

しちゃう。

scaffold は一躍 Rails を有名にしたものなんだけど、これは何より様子を掴むのに向いている。例えば

r g scaffold example name:text

とすると

  • カラムを1つ ( name ) 持つテーブル1つ ( example ) に対応するモロモロ

を作ることができる。

実際に実行するとファイルでこれだけのものができる1。(routes はファイルができたんじゃなくて routes.rb を書き換えたよの意味。)

     invoke  active_record
     create    db/migrate/#{SERIAL}_create_examples.rb
     create    app/models/example.rb
     invoke    rspec
     create      spec/models/example_spec.rb
      route  resources :examples
     invoke  scaffold_controller
     create    app/controllers/examples_controller.rb
     invoke    erb
     create      app/views/examples
     create      app/views/examples/index.html.erb
     create      app/views/examples/edit.html.erb
     create      app/views/examples/show.html.erb
     create      app/views/examples/new.html.erb
     create      app/views/examples/_form.html.erb
     invoke    rspec
     create      spec/controllers/examples_controller_spec.rb
     create      spec/views/examples/edit.html.erb_spec.rb
     create      spec/views/examples/index.html.erb_spec.rb
     create      spec/views/examples/new.html.erb_spec.rb
     create      spec/views/examples/show.html.erb_spec.rb
     invoke      helper
     create        spec/helpers/examples_helper_spec.rb
     create      spec/routing/examples_routing_spec.rb
     invoke      rspec
     create        spec/requests/examples_spec.rb
     invoke    helper
     create      app/helpers/examples_helper.rb
     invoke      rspec
     invoke  stylesheets
     create      public/stylesheets/scaffold.css

上から

  • db の migration
  • model
  • model の spec
  • routing ( 一通り CRUD できるように resources になっている )
  • controller
  • controller の各メソッドに対応する view
  • controller の spec
  • view の spec
  • helper の spec
  • routing の spec
  • requst の spec
  • helper
  • stylesheet

となっている。このまま

rake db:migrate
r s

すると

http://localhost:3000/examples

にアクセスして実際に使える。

Controller

layout

layout "NAME"

layout ファイルを指定できる。何も指定しなければ

app/views/layouts/application.html.erb

が選択される。

※ jpmobile が有効で mobile な user agent だったら

app/views/layouts/application_mobile.html.erb

などになる。

さっき scaffold したコードを読む

Controller には index, show, new, edit, create, update, destroy のメソッドがある。それぞれ

index一覧表示
show個別表示
new新規追加form表示
edit既存レコードの編集form表示
create新規追加送信先
update既存レコードの編集結果送信先
destroy既存レコードの削除

となっている。やってることは

  1. Model インスタンスを作る(.all(), .find(), .new())
  2. 必要な処理を加えて
  3. 結果を返す(render(), redirect_to(), head( :ok ))

以上。

Skinny Controller !

respond_to と format.xml の部分はとりあえず気にしなくていいと思う。たぶん。

View

Controller を読むと分かるけど View ってオブジェクトを明示的に作ることはない。

※ erb 以外のテンプレートは使ったことがないので知らない。

基本的なテンプレートの配置

app/controllers/#{controller}_controller.rb
app/views/#{controller}/#{action}.html.erb

controller のメソッド名に対応した view が勝手に呼ばれる。

見ると分かるけど先ほどの scaffold で指定した field ( name ) がちゃんと index, show, _form にハマっている。

ここでもう一度 Controller と見比べると

  • params[:example]
  • @example
  • @examples
  • example.name

などの意味するところが見えてくると思う。

partial の扱い

(主に V や Helper で)

render 'NAME'[, { 渡すオブジェクトのマップ }]

と指定するとこれを呼んだ View と同じディレクトリの

File.dirname( __FILE__ ) + "/_#{NAME}.html.FORMAT"

を探しにいく。例えば上で scaffold した例だと

app/views/examples/edit.html.erb
app/views/examples/new.html.erb

<%= render 'form' %>

と書かれている。実際に呼び出されるのは同じディレクトリにある

app/views/examples/_form.html.erb

になる。

※ オブジェクトのマップについては後述。partial の呼び出しは Rails 3 で簡略化されたので 2 以前の知識のある人、2 以前を対象にした本を参考にしている人は注意。

partial を別なディレクトリに置く

partialの名前に / が入ると app/views/ 以下のどこかのパスのpartialを探しにいく。

View から見えるもの

View から Controller の持っているものは基本的にすべて見える。request, params, cookies, response, session, headers など。Controller で Model のインスタンスをインスタンス変数に持っているなら、V からもそれが見える。

だから index.html.erb で @examples.each と書いてすべてのレコードの一覧を表示することができるし、_form.html.erb でいきなり @example を参照して form を組み立てることができる。

というか `controller' で Controller そのものにもアクセスできる。つまり全部見える。テンプレートで

<%= debug( controller ) %>

として見れば分かる。

partial に渡るオブジェクトと partial の動き

partial の書き方はいろいろあるので、本当に細かいところは

Ruby on Rails Guides: Layouts and Rendering in Rails

に譲るとして、とりあえず

  • インスタンス変数は何もせずにアクセスできる
  • ローカル変数へのマップは :locals で明示する
  • :collection を使うとループの処理書かなくてもいい具合に動く
  • :action で他の action 呼び出して結果を返せる

くらいは分かっておくとよい。

HTML は helper で書くより partial の方が楽かも?

ActionView::Helpers::TagHelper

  • content_tag
  • tag

という便利メソッドがあって HTML の組み立てもラクチンにできそうだけど、デフォルトでエスケープされるし

<%= %>

は Rails 3 以降デフォルトでエスケープされるので注意が必要。とは言え動的に何か組み立てようと思ったら Helper に書いた方が見通しはよくなるので、

<%= raw helper_method %>

みたいな形に落ち着くのかな。でもこの代わりにも partial が使えるような。

<%= yield :NAME %>
<%= render 'name' %>

とやって partial の方で

<%
content_for :NAME do
  ...
end
%>

とか。

jpmobile が有効な場合、partial に対してもテンプレートの切り替えが有効なので、Controller や Helper で分岐を書く必要がなくなって嬉しい気がする。

form

この辺を見る。

  • ri ActionView::Base
  • ri ActionView::Helpers
  • ri ActionView::Helpers::FormBuilder
  • ri ActionView::Helpers::FormHelper
  • ri ActionView::Helpers::FormOptionsHelper
  • ri ActionView::Helpers::FormTagHelper

form_for が form_builder を作るメソッド。

form_for( @model ) do |f|
  f は FormBuilder が渡ってきている
end

Model.columns を使うと column 情報は取れるので、手動で作る分にも雑な form ならすぐに作れそう。

二つの Model にまたがる場合はどうするんだろう? 宿題。

  1. Test::Unit ではなく RSpec を使う設定になっているものとする。 

More