ハイパーニートプログラマーへの道

頑張ったり頑張らなかったり

Rails Tutorial Chapter3をやる 断片的なメモ

2章はさくっと飛ばしまして、今章で作成するsample_appを今後も使っていく、ということで作るのですが。

断片的なメモなので、あまり参考にならないかと。Nitrous.io上で開発してます。



Testing

$ ls test/controllers/                                                                      
static_pages_controller_test.rb

コントローラ作成時にそれに対応したテストファイルも生成されている。そこにテストメソッドを書いていく。

require 'test_helper'

class StaticPagesControllerTest < ActionController::TestCase
  test "should get home" do
    get :home
    assert_response :success
  end

  test "should get help" do
    get :help
    assert_response :success
  end

end
  test "should get home" do
    get :home
    assert_response :success
  end

ホーム画面にアクセスしたら成功してほしいよね! というメソッド

bundle exec rake test または rake test

コケる例

  test "should get about" do
    get :about
    assert_response :success
  end

これを追加してみる。当然aboutページはまだ用意してないので、コケるはず。

Finished in 0.139130s, 21.5625 runs/s, 14.3750 assertions/s.                                                                                                     
                                                                                                                                                                 
  1) Error:                                                                                                                                                      
StaticPagesControllerTest#test_should_get_about:                                                                                                                 
ActionController::UrlGenerationError: No route matches {:action=>"about", :controller=>"static_pages"}                                                           
    test/controllers/static_pages_controller_test.rb:15:in `block in <class:StaticPagesControllerTest>'                                                          
                                                                                                                                                                 
3 runs, 2 assertions, 0 failures, 1 errors, 0 skips                                                                                                              
3 tests                                                                                                                                                          
2 assertions, 0 failures, 1 errors

errorでました。マッチするrouteがないよと。

なので色々ルート追加すると。そんな感じでテストを進めていく。

assert_select "title", "Home | Ruby on Rails Tutorial Sample App"

titleタグ内のテキストを調べる。

provideとyield

<% provide(:title, "Home") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Sample App</h1>
    <p>
      This is the home page for the
      <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
      sample application.
    </p>
  </body>
</html>

<% provide(:title, "Home") %>で:titleというシンボルで"Home"という文字列を設定するよと。
それをtitleタグ内で受け取る。<%= yield(:title) %>として表示。


setupメソッド

require 'test_helper'

class StaticPagesControllerTest < ActionController::TestCase

  def setup
    @base_title = "Ruby on Rails Tutorial Sample App"
  end

  test "should get home" do
    get :home
    assert_response :success
    assert_select "title", "Home | #{@base_title}"
  end

  test "should get help" do
    get :help
    assert_response :success
    assert_select "title", "Help | #{@base_title}"
  end

  test "should get about" do
    get :about
    assert_response :success
    assert_select "title", "About | #{@base_title}"
  end

end

setupメソッドは各testメソッドの前に1回ずつ実行される。ベースタイトルを定義しているだけの簡単なものだが、いちいちassert_selectにベタに書いていく、ということを避けることができる。


Bitbucketへリモート追加してプッシュ

ここでBitbucketにてsample_appというリポジトリを作っておく。

そしてリモート追加してプッシュ

$ git remote add origin git@bitbucket.org:noriyotcp/sample_app.git
$ git push -u origin --all

マイグレーションロールバック

$ bundle exec rake db:migrate We can undo a single migration step using $ bundle exec rake db:rollback

これでマイグレーションをひとつ戻せる、ということかな。これは知らんかった。


Rails コマンドとその省略形

Full command Shortcut
$ rails server $ rails s
$ rails console $ rails c
$ rails generate $ rails g
$ bundle install $ bundle
$ rake test $ rake

TopicブランチをBitbucketにプッシュ

$ git status
$ git add -A
$ git commit -m "Add a Static Pages controller"
$ git push -u origin static-pages

最後のコマンドはstatic-pagesブランチをBitbucketにプッシュしている。


Advanced testing setup

3.7.2 Backtrace silencer

backtraceは長くて不便なので、

config/initializers/backtrace_silencers.rb

Rails.backtrace_cleaner.add_silencer { |line| line =~ /rvm/ }

注意点は必ずサーバーを再起動させること。

3.7.3 Automated tests with Guard

いちいちrake testと打つのめんどい。Gemfileに以下を記述してbundle install

gem 'guard-minitest'

インストール後、アプリのルートディレクトリにて初期化

$ guard initではなく

$ guard init minitest

guard/guard-minitest · GitHub

$ guard init minitest                                                                               
04:48:39 - INFO - Writing new Guardfile to /home/action/workspace/sample_app/Guardfile                                                                             
04:48:40 - INFO - minitest guard added to Guardfile, feel free to edit it

Guardファイルが生成されるので、そこに色々設定する。Rails Tutorialのをそのままコピペ。

# Defines the matching rules for Guard.
guard :minitest, spring: true, all_on_start: false do
  watch(%r{^test/(.*)/?(.*)_test\.rb$})
  watch('test/test_helper.rb') { 'test' }
  watch('config/routes.rb')    { integration_tests }
  watch(%r{^app/models/(.*?)\.rb$}) do |matches|
    "test/models/#{matches[1]}_test.rb"
  end
  watch(%r{^app/controllers/(.*?)_controller\.rb$}) do |matches|
    resource_tests(matches[1])
  end
  watch(%r{^app/views/([^/]*?)/.*\.html\.erb$}) do |matches|
    ["test/controllers/#{matches[1]}_controller_test.rb"] +
    integration_tests(matches[1])
  end
  watch(%r{^app/helpers/(.*?)_helper\.rb$}) do |matches|
    integration_tests(matches[1])
  end
  watch('app/views/layouts/application.html.erb') do
    'test/integration/site_layout_test.rb'
  end
  watch('app/helpers/sessions_helper.rb') do
    integration_tests << 'test/helpers/sessions_helper_test.rb'
  end
  watch('app/controllers/sessions_controller.rb') do
    ['test/controllers/sessions_controller_test.rb',
     'test/integration/users_login_test.rb']
  end
  watch('app/controllers/account_activations_controller.rb') do
    'test/integration/users_signup_test.rb'
  end
  watch(%r{app/views/users/*}) do
    resource_tests('users') +
    ['test/integration/microposts_interface_test.rb']
  end
end

# Returns the integration tests corresponding to the given resource.
def integration_tests(resource = :all)
  if resource == :all
    Dir["test/integration/*"]
  else
    Dir["test/integration/#{resource}_*.rb"]
  end
end

# Returns the controller tests corresponding to the given resource.
def controller_test(resource)
  "test/controllers/#{resource}_controller_test.rb"
end

# Returns all tests for the given resource.
def resource_tests(resource)
  integration_tests(resource) << controller_test(resource)
end

guard :minitest, spring: true, all_on_start: false do

このラインはSpringサーバーを使いつつ、頭からフルテストをするのを防いでくれる?

SpringとGitのコンフリクトをさけるため、.gitignoreに記述する。

/spring/*.pid

ちょっと注意点のメモ

$ bundle exec guardでならないなあ。

$ guardでもなんか変なんだけど。

WARN: Unresolved specs during Gem::Specification.reset:                                                                                                            
      minitest (>= 3.0)                                                                                                                                            
WARN: Clearing out unresolved specs. 

ちょっと忘れてしまいましたが、その後chrubyを使いRubyのバージョンを2.0.0にして、gemを入れ直していったんですが、そのせいなのかどうなのかguardにおいてcommand not foundとでてしまいました。

Gemfileにguard追加しないとだよね。

group :test do                                                                                                                                                   
  gem 'minitest-reporters'                                                                                                                                       
  gem 'mini_backtrace' 
  gem 'guard' # 追加
  gem 'guard-minitest'                                                                                                                                           
end                                                                                                                                                              

これで怒られずにguardを使えるようになった。テスト自動化は楽チン。


ブランチ作成してBitbucketにも追加

マスターだけでなく、トピックブランチをローカルに作って、それをBitbucketに反映させたい。

tomoのconcrete5 :: Bitbucketでbranchを使ってみた(メモ)

ブランチの作成

git branch (branch name)
git push origin (branch name)

上記コマンドでブランチ名を指定して作成します。2行目で、Bitbucketに反映させます。

するとgit pushだけでなく

Bitbucketへの反映、従来は、git push だけでよかったですが、今後は、都度ブランチ名の指定が必要です。

git push origin (branch name)

ブランチ名を指定してプッシュ。

引数なしでプッシュすると

引数なしのgit pushは危険なので気をつけましょう - DQNEO起業日記

引数なしで"git push"すると、何がpushされるかご存知でしょうか?

デフォルトでは、ローカルブランチと同名のブランチがリモート上にあるならそれらを一気にpushしてしまいます。 カレントブランチが何であろうと関係ないのです。

これを人よんで絨毯爆撃pushといいます。(←いま思いついた)

(中略)

すると、どこに何がpushされると思いますか?

実は、master -> masterにpushされます。 masterがまだpushできる状態でない場合、これはかなり痛い。すごく痛い。頭が頭痛でおなかが腹痛。

しかもpushしたかった当のbr1ブランチはpushされないというオチ。(リモートにbr1ブランチがない限りは)

この挙動は大半のユーザの期待とは異なるのではないでしょうか。

(中略)

その4:デフォルトの挙動を"simpleモード"に変更する(ただしGit1.7.11以降のみ) git config --global push.default simple git push simpleモードとは、「カレントブランチと同名のリモートブランチが存在する場合のみ、カレントブランチのpushが行われる」モードだそうです。

simple - like upstream, but refuses to push if the upstream branch's name is different from the local one. This is the safest option and is well-suited for beginners. It will become the default in Git 2.0. https://github.com/git/git/blob/master/Documentation/config.txt

公式アナウンスによれば、Git次期バーション(おそらく2.0)あたりからこの"simple"モードがデフォルトになるそうです。 今からこの設定にして馴れておくのがよいでしょう。

とうとう Git 2.0 が現実のものに。便利な機能満載 - Atlassian Japan

重要! git push (引数なし) のデフォルトが simple なプッシュの仕組みに 単純な引数なしの git push のデフォルトの動作は、これまで直感的に理解できるものではありませんでした。ローカルとリモートでブランチ名が一致する限り、ブランチはすべてリモートに送られ、これが、matching オプションの意味でした。

Git 2.0 で、push のデフォルトが simple に変更され、より具体的・直感的で、対象範囲が狭まりました。これにより、

同じリモートでカレントブランチが対象リモートブランチと連携するように設定されている場合のみ、カレントブランチが同名ブランチへ、

通常のフェッチ先ではないリモートにプッシュする場合は、カレントブランチが同名ブランチへ、push されるようになります。

デフォルトになっているのなら心配はない?
でも一応ブランチ名を指定してpushする方法を覚えておくといいかなと。

すぐ分かる! git の origin と master ってなんだ? - Qiita

git push はデフォルトでは、同じブランチ名がリモート上にある場合、全部のブランチを push しちゃう?

git push -b bitbucket master


なんかあまりRailsの話じゃなくなってますね・・・。