OSC2007Kansai

投稿者 nanki 2007-07-22 07:30:00 GMT

に行ってきました。

今回は、Railsハンズオンセミナーの講師をやったけど、一日目は、プロジェクタへの接続を確認してなくて、みなさまにご迷惑をおかけしました。ごめんなさい。

ちゃんと設定したのに、二日目もやっぱりつながらなくて、okkezさんに迷惑かけました。ごめんなさい。

二日目の懇親会で見た楽器、ウダーがスゴかった。
販売してたら危うく購入するところだったのに。残念。
今後に期待しています。

あと、お子様連れのお子様たちがとってもかわいかったよぅ。子供ほしー。

帰りは、京都駅から四条まで、数人で散歩。
翻訳の仕事をしている外国の方(といってももうほとんど日本の方)も一緒で、東本願寺に掲げてあった看板のコピーをだしに、面白い話が色々聞けた。

OSCの内容の話が無い!

参考:


発展課題の解答を用意してみました。
一解答例にすぎませんが、参考にしてください。

急いで作ったので間違ってたらツッコんでください。

:per_page に指定した数字に合わせて、前のン件, 次のン件としてみよう。

ActionController::Pagination::Paginator#items_per_pageを使って、
$ vi app/views/bbs/list.rhtml

<%= link_to "前の#{@comment_pages.items_per_page}", { :page => @comment_pages.current.previous }
            if @comment_pages.current.previous %>
<%= link_to "次の#{@comment_pages.items_per_page}", { :page => @comment_pages.current.next }
            if @comment_pages.current.next %>

リファレンスマニュアルでは、Attributesのところにあって、なんの説明もないので、見つけにくいかもしれません。

http://localhost:3000/bbs/edit/1 と言う風に直接アクセスすると、誰の発言でも自由に編集できてしまう。コントローラから使ってないメソッドを削除して、編集ができないようにしよう。

app/controllers/bbs_controller.rb中の、edit,show,updateメソッドを削除し、verify の行にある、:updateも消す。
app/views/bbs/edit.rhtmlapp/views/bbs/show.rhtml二つのファイルも消します。

投稿フォームを /list/bbs の一番上に移動して、直接投稿できるようにしてみよう。

app/views/bbs/list.rhtmlの上の方に、

<div>
  <%= start_form_tag :action => 'create' %>
    <%= render :partial => 'form' %>
    <%= submit_tag "投稿" %>
  <%= end_form_tag %>
</div>

を追加。

# app/controllers/bbs_controller.rb
   def list
     @comment_pages, @comments = paginate :comments, :per_page => 10, :order => 'created_at desc'
     @comment ||= Comment.new # ||= は、create から呼ばれた時に@commentを上書きしないため。
   end
  
   def create
     @comment = Comment.new(params[:comment])
     if @comment.save
       flash[:notice] = 'Comment was successfully created.'
       redirect_to :action => 'list'
     else
       list # この行追加
       render :action => 'list' # エラーがあった場合の戻り先を変更
     end
   end

   # new アクションは削除

app/views/bbs/new.rhtmlも消してしまいましょう。

Commentにvalidatesを追加して、必須項目を決めよう。

title, body, name を必須項目に、email, homapage は空じゃなかったら、正規表現で判定をしています。 email の方の正規表現は、 validates_format_of のサンプルコードから、homepageの方は先頭がhttp://またはhttps://かをチェックしています。 凝りたい人はどうぞ。

# app/models/comment.rb
class Comment < ActiveRecord::Base
  validates_presence_of [:title, :body, :name]
  validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :if => proc{|comment| !comment.email.blank?}
  validates_format_of :homepage, :with => %r|^https?://|, :if => proc{|comment| !comment.homepage.blank?}
end

また、次のようなテストコードを書いて、

$ rake test:units

を実行することで、正しそうに動いているかチェックできます。

テストコード↓を書いてから、実装↑を書くと、TDD.

# test/unit/comment_test.rb
require File.dirname(__FILE__) + '/../test_helper'
  
class CommentTest < Test::Unit::TestCase
  def setup
    @comment = Comment.new(:title => 'hi!', :body => 'hello!', :name => 'bob', :email => "", :homepage => "")
  end
  
  def test_validation
    assert_valid @comment
  end
  
  def test_presence_on_title
    @comment.title = nil
    @comment.save
    assert_not_nil @comment.errors.on(:title)
  end
  
  def test_presence_on_body
    @comment.body = nil
    @comment.save
    assert_not_nil @comment.errors.on(:body)
  end
  
  def test_presence_on_name
    @comment.name = nil
    @comment.save
    assert_not_nil @comment.errors.on(:name)
  end
  
  def test_email
    @comment.email = 'bob@rails6.com'
    @comment.save
    assert_valid @comment
  
    @comment.email = 'bob.rails6.com'
    @comment.save
    assert_not_nil @comment.errors.on(:email)
  end
  
  def test_homepage
    @comment.homepage = 'https://bob.rails6.com'
    @comment.save
    assert_valid @comment
  
    @comment.homepage = 'http://bob.rails6.com'
    @comment.save
    assert_valid @comment
  
    @comment.homepage = 'ftp://bob.rails6.com'
    @comment.save
    assert_not_nil @comment.errors.on(:homepage)
  end
end

削除キーを入力しないと削除できないようにしてみよう。

まず、migration でdelete_key というカラムを追加します。

$ script/generate migration AddDeleteKey
      exists  db/migrate
      create  db/migrate/004_add_delete_key.rb
# vi db/migrate/004_add_delete_key.rb
class AddDeleteKey < ActiveRecord::Migration
  def self.up
    add_column :comments, :delete_key, :string
  end
  
  def self.down
    remove_column :comments, :delete_key
  end
end

$ rake db:migrate

次に、投稿フォームに、削除キー入力フィールドを作り、

<!-- app/views/bbs/_form.rhtml -->
<p><label for="comment_delete_key">削除キー</label><br/>
<%= text_field 'comment', 'delete_key'  %></p>

削除ボタンのとなりにテキストフィールドを追加。

<!-- app/views/bbs/list.rhtml -->
     <td>投稿日時:<%= comment.created_at.strftime("%Y/%m/%d %H:%M:%S") %></td>
     <td>
       <%= start_form_tag :action => 'destroy', :id => comment %>
       <%= text_field_tag 'delete_key' %>
       <%= submit_tag "削除" %>
       <%= end_form_tag %>
     </td>

その値を受けて、保存された削除キーと、入力された削除キーが一致しないとdestroyしないように、コントローラを書き換える。

# app/controllers/bbs_controller.rb
   def destroy
     c = Comment.find(params[:id])
     c.destroy if !c.delete_key.blank? && c.delete_key == params[:delete_key]
     redirect_to :action => 'list'
   end

今回のテストコードは、コントローラのテストなので、以下の通り。

まず、テストデータを二つ用意。 片方は、削除キー’bob123’、片方は削除キーなし(削除できない)

# test/fixtures/comments.rb
bob:
  id: 1
  title: hi
  body: hello
  name: bob
  delete_key: bob123
undeletable:
  id: 2
  title: hi
  body: hello
  name: bob
  delete_key: ''
# test/functional/bbs_controller_test.rb
require File.dirname(__FILE__) + '/../test_helper'
require 'bbs_controller'
  
# Re-raise errors caught by the controller.
class BbsController; def rescue_action(e) raise e end; end
  
class BbsControllerTest < Test::Unit::TestCase
  # テスト用データである、fixture をロード。(上で書いたやつ)
  fixtures :comments
  
  # test_* の前に実行される。
  def setup
    @controller = BbsController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
  end
  
  # 削除キーを指定しないと削除されない
  def test_destroy_without_delete_key
    id = comments(:bob).id
    assert_not_nil Comment.find(id)
    post :destroy, :id => id
    assert_not_nil Comment.find(id)
  end
  
  # 削除キーを指定すると削除される
  def test_destroy_with_delete_key
    id = comments(:bob).id
    assert_not_nil Comment.find(id)
    post :destroy, :id => id, :delete_key => comments(:bob).delete_key
    assert_raise(ActiveRecord::RecordNotFound) {
      Comment.find(id)
    }
  end
  
  # 削除キーが空のレコードは、空の削除キーで削除できない
  def test_destroy_record_having_empty_delete_key
    id = comments(:undeletable).id
    assert_not_nil Comment.find(id)
    post :destroy, :id => id, :delete_key => comments(:undeletable).delete_key
    assert_not_nil Comment.find(id)
  end
end

Rails勉強会@関西6

投稿者 nanki 2007-01-22 05:51:00 GMT

土曜日は、Rails勉強会に行ってきました。

今回は、初心者レッスンの担当。

朝8時に起きて準備するはずが、前日5時くらいまで(というか、三時間前まで)いろいろやっていたので、目覚まし時計の思いも届かず、2時間寝坊。 ひげを剃るのも会場で。 11時到着に合わせて計算していたので、なんとか12時前にはたどりつけたけど、あせったなぁ。

発表は、なんとか終了。 途中で場内を回ってみると、思いの外、進み具合がバラバラだったので、最後の部分は演習時間を延長してカット。

なにから解放されたのか、昼御飯は食べる気も起こらなかったのに懇親会まではずっとお腹が鳴りっぱなしなのでした。

終わってから気がついたけど、初期のRails勉強会のように、教科書になるような本を写経とかでもいいんじゃないか、と思えてきた。
毎回、目的のテーマにたどり着くまでに、ActiveRecord, scaffold の道を進まねばならないので、なんとも大変。 三回目なので、シリーズ化はまだ止められそうだし。

「RailsでXML-DBにチャレンジ」by モバイル通信兵さん

おもしろそう。 DB2要求されるのが、ちょっとハードル高め。 使えそうな場所を探してみようっと。

「Rubyist SNS の実装について」by かずひこさん

最近コミットできてなくて申し訳ないです。 会場で、updateしていつものように一人で友達作って・・・
この作業がいつも寂しい。

「rails tips」by 氏久さん

<%=h %>は、エディタのショートカットで出せるように設定していて、<%= %> にするには、hを削らないといけない、という安全スイッチがあるので、少人数での開発の場合はまあいいかな。 jitor は楽しそう。

「やさしいRailsの育て方(仮題)」by 西和則さん

DBモデリング?のお話。 火星エステ理論なる判別法で、本質的な項目を洗い出せ!

火星の鈴木さん(だっけ?)で何故か火星年代記を思い出してしまった。

懇親会は、内装がゴージャスなお店。

二次会では、非カラオケチームに合流しようとして連絡をしたら、途中で携帯の電池が切れてしまって、結局合流できなかった・・・。 今朝、僕の目を覚まそうとして、一時間に渡ってブルブルしてたはずだから、当然なのかも。

なので、はぐれ組三人で、駅前のサンマルクカフェで、お話しました。


Ruby勉強会@関西 10

投稿者 nanki 2006-05-16 04:28:00 GMT

今回は半分弱が初参加、60人の定員が満員という勢い。 バス一本乗り過ごして、10分ほど遅れて到着。

丸投げシリーズ(3) C

西本さんの発表。

CのライブラリをRubyから使うというもの。 * #include "ruby.h" * Init_foo(foorequire 'foo'される)の中に、クラス情報、あるいはメソッド情報をつらつらと書きつくる。 * mkmfライブラリを使って、Makefileを作る。 * makeする。 * 30倍から100倍程度の高速化ができることも。

実はなかなか踏み出せないでいた領域だけに(いつもRubyレベルでのアルゴリズムの最適化とかで逃げてる。逃げてるのか?)非常に役立つ内容だった。
さんざん最適化した上でNativeにしたら、相当速くなりそうだ。 非CygwinのWindowsコンパイラを探さないと。
大量のマクロとrb_*が次なる壁。

ゲーム用フレームワーク 「Miyako」

サイロス誠さんの発表。スライドの一枚目がCryossになってる気がしたけど。

本人曰く、女性参加者が予想外に多くて、ネタに対する反応が心配だったそうで、確かにちょっとヒヤヒヤ。
(概ね、高飛車な女性がMiyakoのなんたるかを博士&助手に説明するという内容)
僕は前のほうだったのであまり気にならなかったけど、文字のサイズが小さくて後ろのほうの人は見えなかったそうで、途中から、普段勉強会の会計を担当してくださっている、あゆさんが声優をやって、別の意味で盛り上がっていた。

肝心の内容のほうは、発表の形式がシナリオ形式だったので、記憶に残ってるのは主にデモ中心。
紙芝居的なゲーム(呼び方知らない)を作るなら一考の価値あり、だと思います。 Miyako自体のコードはあまりRubyっぽくないので、Rubyっぽい実装になって欲しい。 あと、プレゼンツールとしての使い道に期待する人もいるようで、今後のバージョンアップはそっちの方向に向かうとか。

それなら、フルスクリーン対応は必須になるね。

ライトニングトーク Ruby on Google SketchUP

兼重さんの発表。Googleが発表したブツを早速。 このスピード感がライトニング。 デモは、SketchUpでぐいぐい立体を作って(ここはRubyと関係ない)、PureImage(西本さん作)で作ったテクスチャーを貼り付けるというもの。

西本さん、丸投げばかりじゃなかったのね。
PureImageの回は参加できなかったのですっかり忘れてた。

Rubyと関係ないFollow Meツールがうまくいかないのでちょっとヒヤッとしてた。

Ruby 初級者向けレッスン 7 -ブロックとイテレータ-

最後はかずひこさん・コウザイさんによる発表。 もう七回目になるのか。僕が最初に参加したときは一回目だったかなぁ。 内容は、イテレータ・ブロックを使ってみる、というもの。 今回は、時間がよっぽど足りなかったらしく、途中のキリのいいところ?で終わってしまった。 * injectの引数省略知らなかった * 僕、Ruby歴2年半くらいなんですが・・・ * おじさん向け課題:パスカルの三角形

(1..9).inject([1]){|r,| p r;(r+[0]).zip([0]+r).map{|a| a[0]+a[1]}}
* いまいさんの解答、enum_consとか勉強になります。 * to_procのやつ(.map(&:+))、引数一個以上のメソッドを渡しても大丈夫なのか。むむ。 * &:+が梅干たべたパーマの外国人みたい。 * 偶然か必然か、途中までまったく一緒・・・。1..9 とか、10にすると文字が一文字増えるからだよなぁ。

小波ゼミでは最初からRubyを教え込まれるので、卒業するころにはRuby暦3年とか4年とかざらにいるみたいです。恐るべし。

発表の形式として、壇上で先生と生徒の対話みたいな形がとられていた?(→意図したものだったようで)のは聞いてる方としては入りやすいんじゃないかと思う。
Ruby/SDL上での先生と生徒の対話はちょっと食傷気味だけど。
後半の応用編(ログ解析)は次回に持ち越し?

プリンセスラインに対する京都女子大学の絶大なる影響力(ピポパで臨時便)を目の当たりにしつつ、懇親会へ。

懇親会の内容は日記になるので略。

参考:

第10回 Ruby勉強会@関西
Miyako メインサイト