Rails勉強会@関西6 初心者レッスン発展課題の解答例

Posted by nanki Mon, 22 Jan 2007 11:26:00 GMT

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

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

: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

Posted in ,  | Tags ,  | 1 comment | no trackbacks

Comments

  1. ばば said 2 days later:

    レッスンお疲れ様でした! ちゃんとフォローが!!!m(  )m ありがたく、メモさせてもらいます^^;

Trackbacks

Use the following link to trackback from your own site:
http://blog.netswitch.jp/articles/trackback/4853

(leave url/email »)

   Comment Markup Help Preview comment