今さら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 を使う設定になっているものとする。 

CSVを固定長フォーマットのテキストに変換して普通のエディタで開く

文字コードとか考えてません。最初 gawk で書いてたけど match() でマッチした文字列を配列で受け取れるgawk拡張について

3.1.5 はバグ持ちだよ

という記述を見つけてしまって凹んでました。というか手元の 3.1.4 で試して動いたんだか動かないんだかよく分からなくて放り投げてしまいました。awk スクリプトで最新版を要求するなんて優しさが足りない。

Therefore use:

echo test4325363test | gawk 'match($0, "([^0-9]*)([0-9]+)(.*)", a) { print a[2] }'

to extract the number.

Please, note that gawk 3.1.5 has some bugs in the match function. These should be corrected in gawk 3.1.6 (see ftp://ftp.gnu.org).

How to gram awk's regexp submatches? - Object Mix

というわけで Ruby に鞍替え。

なんか諸々 CSV に決め打ちで TSV とか対応できませんけど勘弁してちょ。optparse で delimiter 受け取って動的に正規表現作ればイケますよ、とだけ書いてお茶を濁しておく。

途中、範囲式からループを回す処理は見慣れないと気持ち悪いけど、なぜか Ruby を書いていると i += 1 とかカウンタを自分でいじる方が気持ち悪いと感じるようになるのです。for ( ; ; ) 文がないので while の中で自分でカウンタいじることになるんだけど、そうするとインクリメントのタイミングによって値が変わっちゃうとかそういう落とし穴を作ることになるんでやりたくなくなるのです。do end と { } が混ざっているのはごめんなさいということで。

#! /usr/bin/env ruby

class Csv2Fixed
  def initialize
    @num_fields = 0
    @num_lines  = 0
    @len_cols   = []
    @buf        = []
  end

  def run
    while ( line = gets )
      arr = split_csv( line.chomp )
      if ( arr.size > @num_fields )
        @num_fields = arr.size
      end
      store_line( arr )
      @num_lines += 1
    end

    output()
  end

  def store_line( arr )
    @buf[@num_lines] = []

    (0 ... arr.size).each do |i|
      str = arr[i]
      if ( @len_cols[i].nil? or str.size > @len_cols[i] )
        @len_cols[i] = str.size
      end
      @buf[@num_lines].push( str )
    end
  end

  def output
    (0 ... @num_lines).each do |i|
      arr = @buf[i]
      (0 ... arr.size).each do |j|
        printf( "%-*s ", @len_cols[j], @buf[i][j] )
      end
      printf( "\n" )
    end
  end

  def split_csv( str )
    str = str + ","
    arr = []

    str.scan( /(\"(?:[^\"]|\"\")*\"|[^,]*),/ ).each { |e|
      arr.push( e.to_s.sub( /^"/, '' ).sub( /"$/, '' ).sub( /""/, '"' ) )
    }

    return arr
  end
end # of class Csv2Fixed

if ( __FILE__ == $0 )
  app = Csv2Fixed.new()
  app.run()
end

放電中

なんかちと疲れたべ。

RWiki ってすごい?

Rubyist Magazine - Rubyist Hotlinks 【第 13 回】 関将俊さん

咳 まずは。ふだんもう立ち上げっぱなしで。

須藤 えーっ。そうだったんですか。

咳 irb 端末が一個。

一同 (笑)

笹田 じゃあ、Ruby がどうのっていうわけじゃなくて?

咳 Smalltalk の workspace みたいなかんじで繋げっぱなしで、例えば今のイテレーションの状況とかって計算するときに irb から直接 RWiki に繋いで結果ばーって。

笹田 あー、なるほど。すげーかっこいい。

須藤 かっこいい。

角谷 かっこいい。

かっこいい。分かんないけどかっこいい。

前の方にも書いてあるけど RWiki は RD → HTML ということだけではなくて、Ruby のオブジェクトを保存しているイメージなんだそうだ。中身見る気力があるかどうか分からないけど、動かすだけ動かしてみようかな。ひょっとするとものすごく便利かもしれない。1記法の問題は残るけど(結局それか)。

[2006-02-22 追記]動かす方が気合い要りそうだったのでやめた。

  1. 前から細かくメタ情報が残ってて便利だなとは思ってたけど。 

Ruby リファレンスマニュアル改善計画だそうで。

Rubyist Magazine - 0013 号 巻頭言

まず、現在「ruby 1.7 feature」「ruby 1.8 feature」というのが残っている問題について。これは現状では不要であるが、Ruby 1.6 のリファレンスがないために残っている。そこで、1.6 版の最終版として、どこかの時点で凍結したものを用意し、入手できるようにしておく。そして、今後編集していく本体の方からはすべての「ruby 1.7 feature」「ruby 1.8 feature」を削除すればよいだろう。

なお、1.9 feature については、そのまま残しても構わないが、無理につけ加える必要もないので、必要に応じてつけていくことになるだろう。まずは 1.8 の安定版のマニュアルを作ることを優先するべき、という判断の元、1.9 への対応については今後の課題とする。

これ実は個人的には結構気に入っている記述だったんだけど…。

PHP のマニュアルもこんな感じになっていて、あーこの関数は PHP 4.3 からだったのかーちくしょう、とかこれは 3 から使えてたのか、へー知らなかったな、これは 4.2 から挙動が変わったのか、じゃあここはこうしなきゃダメじゃないか、てなことを思いながら参照している。

まぁ 1.6 対応のスクリプトを書くときは 1.6 用のマニュアルを見ればよいという割り切りができる方が普通は楽なのかなぁ。なんか寂しいというか、自分にとっては使い勝手が悪くなってしまうような気もして怖い。マニュアルを2つ用意しなきゃならないという面倒くささもある。1.6 の環境だけの人、1.8 の環境だけの人は別になってると楽だけど、両方使ってる自分にとってはマニュアルが分かれるのはあんまり嬉しくないような気がするなぁ。

日本Rubyの会は世の中で Ruby に触ったことのある人たちよりも絶対にベテランで、かつ環境も新しいものに結構よく追いついて行っている方だと思われるので、1.8 以降の記述に集中したいっていうのは分からなくもない。まぁ「まずは 1.8 の安定版のマニュアルを作ることを優先するべき」という課題に最短距離で向かうためには切り離した方が作業はしやすいか。そうだよな。

ごちゃごちゃした情報が大量にあるページのデザイン

調査票デザインの原則

で、このページの筆者の方がインターネット調査は社会調査に利用できるかという報告書に以下のように突っ込んでいるが、

  • 1つの設問は1つのスクリーンに収まるように
    • ユーザの環境によって画面の広さは異なる。基準(例えばSVGA)を決める必要がある。

広さと「設定」によって異なりますぜ。今じゃ携帯だって高精細だから設定次第で結構な文字数を表示できるし、ウィンドウを全画面表示で横長に使っているとも限らない。

というツッコミは意地悪半分、本気半分。今回は報告書の言ってることは概ね正しいけど実現するのは楽じゃないよという話なわけですが、方法としては以下のような感じ?

  • (昔デザイナのサイトで流行った)新規ウィンドウを開いて固定サイズのフォントを使う
  • JavaScript と CSS で動的にサイズ調整
  • Flash とか Java とか PDF でリッチクライアントの操作性に期待する

あるいは

  • S5 のように JavaScript と CSS を使って長い HTML の1ページを複数のスクリーンに分割する

と、いちいちサーバと通信せずに JavaScript に情報を保存できるし、Flash や Java のように plugin を必要としないし、ユーザーの意思で JavaScript を off にして(あるいは JavaScript 非対応のブラウザを使って)長い HTML のページと格闘することも可能だから、これがいちばんいいのかも。でも S5 って自分自身が作りだすナビゲーションやスライドショーで実際に表示する内容以外はまったく考慮されてないから、他のコンテンツへのナビや広告も盛り込みたいって要求になった場合はちょっと使いにくいか。そこのサイトのナビや広告が CSS の管理下にあればいいけど、そうでないとダメくさい。

生 HTML は操作性があまりよくないが、plugin 前提の場合は操作性はよくなるがユーザーの環境を限定してしまうという問題って、他にもいろんなシーンがあるわけですが、この調査票ネタはそれを考えるのにとてもよい題材かもしれない。

Ruby 1.8 対応リファレンスマニュアルの HTML 一括ダウンロード

出ました!

素晴らしい! RD のままっつーのもあるけど、これは、、、自前の RWiki で再現しろとか自分で RDTool とか使って好きにしろとかそういうことかな?(^^;

今までも 1.8 対応の HTML 版は非公式にはありましたけど、本家にあるってのが重要ですね。さーて早速手元のものをこれで更新すっかー。Ruby を書く予定はないけど。。。

あれ、リファレンスマニュアルのトップページから参考文献とか参考になるサイトへの誘導がありますね。前からこんなのあったかな。整理されているし、るびまの入門記事へのリンクもありますね。いい感じですね。

オープンソースな e-Learning

e-Learning は学習者の要求、学習者と(居るとして)指導者の関係、学習内容などに応じて様々な形があるので、「これが正解」という一つの形は存在しない。ビジネスの文脈で語られる e-Learning は予備校の衛星授業みたいなものだが、exCampus の目指すところはどこにあるのか。大学で実験してるんだから高等教育以上になるのかな。

オープンソースな学習支援ということで、面白い企画だと思う。コケないでほしいね。ある意味学会などより確実にノウハウの共有が進むし。

About

例によって個人のなんちゃらです