Ruby 簡単なテスト駆動開発とリファクタリング

Rubyチュートリアル3章を試してみました。

テスト駆動開発リファクタリングを行いました
重要なとこをまとめてみました

まず静的なページに対する結合テスト(request spec) を生成します

$ rails generate integration_test static_pages
      invoke  rspec
      create    spec/requests/static_pages_spec.rb

static_pages_spec.rbが生成されました

中身はこんな感じになっていて

require 'spec_helper'

describe "Static pages" do

  describe "Home page" do

    it "should have the content 'Sample App'" do
      visit '/static_pages/home'
      expect(page).to have_content('Sample App')
    end
  end
end

it "…" doで始まるのがテストですね

visit '/static_pages/home'

上の行は、Capybaraのvisit機能を使って、ブラウザでの/static_pages/homeURLへのアクセスをシミュレーションします。

expect(page).to have_content('Sample App')

その次の行 (上のコード) では、これもCapybaraが提供するpage変数を使って、アクセスした結果のページに正しいコンテンツが表示されているかどうかをテストしています。

ちなみにテストが正常に実行されるようにするためにはspec_helper.rbに

RSpec.configure do |config|

これを追加する必要があります

実際にテストを行ってみます

$ bundle exec rspec spec/requests/static_pages_spec.rb

bundle execをrspecのコマンドの前に置くことで、Gemfile内で定義された環境でRSpecが実行されるように、明示的に指示することができるみたいです。

まずこれを実行するとテストが失敗します
Failure / Error expect (page).to have_content('Sample App') ........
... app/views/static_pages/home.html.erb
...
1 example, 1 failure
間省きますがこんな感じででます

一般的にはこれを「赤色 (Red)」
パスするコードを「緑色 (Green)」と言うそうです

テストにパスするHomeページ用コードを書きます
app/views/static_pages/home.html.erb

<h1>Sample App</h1>
<p>
    This is the home page for the
  <a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a>
    sample application.
</p>

見出しがSample Appに変更されたため上のコードはパスします
もう一度見てみると

$ bundle exec rspec spec/requests/static_pages_spec.rb

Finished in.......
1 example, 0 failures
.......

とでます

ちなみに同じようなhelpページとaboutページを追加して

<!DOCTYPE html>
<html>
  <head>
    <title>Ruby on Rails Tutorial Sample App | Home</title>
  </head>
  <body>
    <h1>Sample App</h1>
    <p>
    This is the home page for the
      <a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a>
    sample application.
    </p>
  </body>
</html>

このようなHTML構造で書いてます
これは
・ページのタイトルがどれもほぼ同じ。
・“Ruby on Rails Tutorial Sample App” が3つのタイトルで共通している。
・HTMLの構造全体が各ページで重複している。

このコードはDRYの原則に反しているのでまとめます

まず埋め込みrubyを使ってhome.html.erbビューのタイトルを直していきます

<% provide(:title, 'Home') %>
<!DOCTYPE html>
<html>
  <head>
    <title>Ruby on Rails Tutorial Sample App | <%= yield(:title) %></title>
  </head>

ERbと呼ばれている、Rubyの埋め込みの例です
※HTMLビューのファイルの拡張子が.html.erbとなっている理由

provide関数で関連づけてyield関数で挿入します

ちなみに<% ... %>書くと単に実行するだけで
<%= ... %>結果がテンプレートに挿入されます

<%= ... %>はphpで言うところのechoですね
同様に他のページでも編集していきます。

ここで各ページをみていくとタイトルをのぞいてだいたいこーなってます

<% provide(:title, 'Foo') %>
<!DOCTYPE html>
<html>
  <head>
    <title>Ruby on Rails Tutorial Sample App | <%= yield(:title) %></title>
  </head>
  <body>
      Contents
  </body>
</html>

同じにつくったので同じ構造になってる思いますww

Railsには、共通の構造をまとめるためのapplication.html.erbという
特別なレイアウトファイルがあるみたいなので使ってみます。

デフォルトタイトルを埋め込みRubyのコードに差し替えます。
app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
<head>
  <title>Ruby on Rails Tutorial Sample App | <%= yield(:title) %></title>
  <%= stylesheet_link_tag    "application", media: "all",
                                            "data-turbolinks-track" => true %>
  <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= yield %>

</body>
</html>

<%= yield %>は各ページの内容をレイアウトに挿入するためのものです。

/static_pages/homeにアクセスすると、
home.html.erbの内容がHTMLに変換され、<%= yield %>の位置に挿入されるみたいです

下のこれはそれぞれにインクルードするためのものです

<%= stylesheet_link_tag ... %>
<%= javascript_include_tag "application", ... %>
<%= csrf_meta_tags %>

ではhome.html.erbのHTML構造を抜くとこんな感じになります

<% provide(:title, 'Home') %>
<h1>Sample App</h1>
<p>
    This is the home page for the
    <a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a>
    sample application.
</p>

まとめるのが難しかったためほとんどコピペのような形になってしまいました>_<

Ruby アップデート mac

Ruby on Railsチュートリアルを進めていく途中バージョンが原因でエラーが出たりしたので
バージョンアップ方法を書いておきます

現在のバージョン確認

$ruby -v  
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-darwin13.1.0]

現在使っているのがデフォルトで入っていた1.9.3

rbenvでruby2.1.1をインストール

$ rbenv install 2.1.1

rbenv versions コマンドで、インストール済み Ruby のバージョンを確認

$rbenv versions  

 system
* 1.9.3-p484 (set by /Users/sawanoissei/.rbenv/version)
  2.1.1

ちゃんとされてますねー
ただデフォルトが1.9.3になってます

2.1.1をデフォルトに設定

$ rbenv global 2.1.1

rbenv versions

  system
  1.9.3-p484
* 2.1.1 (set by /Users/ユーザー名.rbenv/version)

これでかわりました

いざプロジェクトを作成!

$ rails new static_app --skip-test-unit
rbenv: rails: command not found

The `rails' command exists in these Ruby versions:
  1.9.3-p484

そりゃそーなんだけどぉrailsの向き先が1.9.3なので

ちなみにこれでも調べられる

rbenv which rails

てことでもっかいgemにインストール

gem install rails 

そんで

$ rails new static_app --skip-test-unit

はいできたー

codeigniter DB接続テスト

codeigniterを使って家でも環境を作ろうと思いました。
会社でcodeigniterを使っているんだけど初期設定などは自分では行っていないのでちょうどいいかと

とりあえずDBの接続テストをしました。

まずapplication/config/database.phpを接続するDBに書き換えます。
こんな感じで

$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'root';
$db['default']['password'] = 'XXXX';
$db['default']['database'] = 'sample';
$db['default']['dbdriver'] = 'mysql';
$db['default']['dbprefix'] = '';
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = '';
$db['default']['char_set'] = 'utf8';
$db['default']['dbcollat'] = 'utf8_general_ci';
$db['default']['swap_pre'] = '';
$db['default']['autoinit'] = TRUE;
$db['default']['stricton'] = FALSE;

ちなみにテスト用にsampleというdatabaseを作っておきました

自動接続の設定を行ったので
application/config/autoload.php

$autoload['libraries' ] = array(’database’);

modelにファイルを追加します。
testディレクトリの下に配置しました。
application/models/test/user.php

<?php

class Users extends CI_Model {

    public $table_name_ = 'user';
    
    function __construct() {
         ※コンストラクタでは必ず親クラスを継承する
         parent::__construct();
        
        // database.php で定義したDBに接続する
        $this->load->database();
    }
    
    function getAllUsers() {
        $query = $this->db->get($this->table_name_);
        
        if($query->num_rows() > 0) {
            // 結果セットを連想配列として返す
            return $query->result_array();
        }
    }
?>

初期のままいじっていないので
welcome.php

public function database_test()
    {
        $this->load->model('test/users');
        $users = $this->users->getAllUsers();

        $this->load->view('database_test');
    }
}

print_rしてみたところ

Array ( [0] => Array ( [id] => 1 [name] => issey ) )

はいok

すごい簡単だけど今日はこれくらいしかできなかった(>_<)

技術を学ぶ上で大事な事

今日はcodeigniterの設定をしていてあまり書く事がないので勉強する上での事を書きたいと思います

技術的な事を勉強する上で
周りより始めるのが遅かったのでどーすれば効率的に
中身の濃い時間をすごせるかを考えていて、
効率的な学び方を調べていたので自分なりの考えをまとめておきます。

・ブログやニュースサイトを読む
だいたいこれはみんなやっているけど時間の合間ですかね
技術系だとはてなやqiitaやitproなど後は興味のある人のブログなど

・自分が学んだ事を相手が興味なさそうでもむりやり話して説明するw
以前働いていた職場で技術系の話を共有する場があってそこから人に教えたり繰り返す事によってより吸収する。

・勉強会やカンファレンスに積極的に参加するまたは企画する
当たりはずれあるけどけどだいたい新しく学ぶ事がある。

オープンソースソースコードを読んでみる
これは知り合いにおすすめされた。

・複数の言語を勉強する
これは学び方ではないが、パラダイムが違う言語を勉強したほうがいいと思う。
自分はphprubyを少しさわってみてるけどwこれはあまりよくないらしい

・自分よりレベルの高い人と仕事や休日の勉強時間をともにする
正直これが一番大事だと思う。モチベーションもあがるし、自分が遅れている事がよくわかるw

・ブログを書く
これもおすすめされたからやってるんですけどかなりの復習になる。

あと人脈がすごい大事ですね^^ いろんな話を聞いてみたい
それもあってivsサマーに申し込んでみました。
たぶん選ばれないと思うけど参加できたら仕事休みます-w

初深夜勤務

今日は今の会社で初の深夜勤務でした(^。^)

今帰宅です
只今午前6時

何故かというと昨日かなり重大なバグをだしてしまいその対応です(>_<)

自分のこの性格をわかったうえでテストしないと同じことを繰り返しそうだな〜~_~

ただ忙しくてテストする暇も十分にないけど、だからといってテストをおろそかにするとこーいう事になるし

本当気を付けよー(>_<)

Rails Usersリソース 追記

今日はRilsの基本概念Usersリソースにふれました。

リソースっていってもかなりいろいろな理解があるので
ここでいうリソースとはデータモデルwebインターフェイスが組み合わさったもの。

データモデルとはRDBMSに格納してあるデータと一緒ですね

データモデルをwebで取り扱えるよ的な理解でいいのかな

user用のデータモデルと組み合わさってUsersリソースみたいです

ユーザーをHTTPプロトコル経由で自由に(CURD)作成/読み出し/更新/削除できるオブジェクトとみなすことができるようになります。

前置きはこのへんで
実際作ってみます

Railsに標準装備されているscaffoldジェネレータを使って作成しました。 rails generateスクリプトにscaffoldコマンドを渡すことで生成されるみたいです。

$ rails generate scaffold User name:string email:string

scaffoldコマンドの引数には、リソース名を単数形にしたもの (この場合はUser) を使用します。
オプションのname:stringとemail:stringがRDBMSでいうカラムみたいなものなのかな
あとidパラメータはRailsによって自動的に主キーとしてデータベースに追加されるみたいです。

するとこんな感じで作成されました!

invoke  active_record
      create    db/migrate/20140526163117_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      invoke  resource_route
       route    resources :users
      invoke  jbuilder_scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    erb
      create      app/views/users
      create      app/views/users/index.html.erb
      create      app/views/users/edit.html.erb
      create      app/views/users/show.html.erb
      create      app/views/users/new.html.erb
      create      app/views/users/_form.html.erb
      invoke    test_unit
      create      test/controllers/users_controller_test.rb
      invoke    helper
      create      app/helpers/users_helper.rb
      invoke      test_unit
      create        test/helpers/users_helper_test.rb
      invoke    jbuilder
       exist      app/views/users
      create      app/views/users/index.json.jbuilder
      create      app/views/users/show.json.jbuilder
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.js.coffee
      invoke    scss
      create      app/assets/stylesheets/users.css.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.css.scss

続いてRakeを使用してデータベースをマイグレート (migrate) する必要があるみたいなので

$ bundle exec rake db:migrate
==  CreateUsers: migrating =================================
-- create_table(:users)
   -> 0.0017s
==  CreateUsers: migrated (0.0018s) ========================

ここでbundle execを使っているのはGem fileに対応するrakeが確実に実行されるようです。 ちなみにこのrakeはunixでいうmakeみたいな感じみたいです。

ここで
http://localhost:3000/usersにアクセスすると

f:id:issey1022:20140527021614p:plain

これが表示されるみたいなんだけど

僕のはこれw

f:id:issey1022:20140527021020j:plain

エラーをみてみるとrails:rootのアクセス先が違う! 以前作った方に向いていたので
一旦プロセスを殺して、新規作成の方に行き再度起動

f:id:issey1022:20140527021614p:plain

※補足 ただ、いちいちローカルの rails サーバーを落として新しいサーバーを立ち上げるとかめんどくさいってとき
デフォルトの起動ポートを変更
通常はlocalhost:3000

require 'rails/commands/server'
module Rails
  class Server
    def default_options
      super.merge({
        :Port => 4000
      })
    end
  end
end

これをconfig/boot.rbに追記するとlocalhost:4000 で立ち上がります ちなみに今回だけならこれで立ち上がります

rails s --port 4000

補足でした

ここでnewページを表示してユーザーを作成します!

f:id:issey1022:20140527021043j:plain

こんな感じ

URLアクションはいろいろあるので参考までに↓ 拾ってきたやつだけど

f:id:issey1022:20140527022131p:plain

今日は以上ですw

herokuセットアップ

Rubyといったらherokuって感じがするのでデプロイ先はherokuを使ってみます。

そもそもherokuとは
WEBサーバ・gitリポジトリ・管理機能をまとめた必要最低限の機能を無料で提供してます。
簡単に言うと、プログラムが動作可能なサーバーを無料で使えるってわけです。
有料もあり

あーあとブログのカテゴリーはほんとは分けた方がいんですけど元々herokuはRuby用に開発されたので、 Rubyのカテゴリーに入れちゃいます。

まずGemfileに下を追加

group :production do
  gem 'pg', '0.15.1'
  gem 'rails_12factor', '0.0.2'
end

herokuはポスグレが使えるので pg gem と
rails_12factorは画像やスタイルシートなどの静的なアセットを提供するためにHerokuで使用されるみたいです。

-without productionオプションを追加してインストールします

$ bundle install --without production

ローカルにはインストールしないという事です
まぁGemfile.lockを更新したいだけですね

でコミット

次にherokuのアカウント登録をしました

f:id:issey1022:20140522020002p:plain

ログインしてみました かっこいい笑

f:id:issey1022:20140522020003p:plain

アカウント登録がおわりーの
Heroku Toolbeltを使ってherokuソフトをインストールします。

ターミナルでherokuのアカウント設定

$ heroku login

herokuにアプリケーション作成

$ heroku create

このコマンドを実行するとRails専用のサブドメインが作成されてブラウザで確認することができます。

ブラウザで確認。

$ heroku open

Rails 4.0はルートへのルーティングを設定しなければいけません。

ただまだデプロイしていないので
gitでherokuにデプロイします

$ git push heroku master

まとめ herokuにはいっぱいコマンドがあるみたいなのでゆっくりみていきたいと思います。