【Rails, Docker】コンテナが起動後すぐに落ちてしまうトラブルの原因とその対処法
概要
DockerでRails環境を構築すると, コンテナが起動しないトラブルに見舞われることがあります. その原因と対処法を説明します.
トラブルケース
以下のようなコマンドでRails Serverが稼働しているコンテナに入ったとします.
docker-compose exec <Rails container> bash
一通り作業を終え, コンテナから出る際に
Ctrl+D
で抜けるとコンテナが停止してしまいます. そこであわてて
docker-compose up -d
としても, ほんの一瞬起動するだけで, すぐコンテナが停止してしまいます.
対処法
原因よりも大事であろう対処法を先に書きます. 以下のファイルを削除してください.
application_root/tmp/pids/server.pid
普通applicaion_root
はローカルマシンにマウントしているでしょうから, コンテナが起動できなくても削除できるはずです. 削除し終わったら, いつも通り起動させれば問題なく動きます.
docker-compose up -d
原因のヒント
ここから原因について述べていきましょう. まずは原因のヒントとなるログメッセージを見ます.
この症状が見られた際, -d
をつけずに起動を試みると, 起動中のログメッセージが表示されます.
docker-compose up
ログメッセージを見ると, このように書かれた行が見つかります.
web_1 | => Rails 5.2.0 application starting in development web_1 | => Run `rails server -h` for more startup options web_1 | A server is already running. Check /myapp/tmp/pids/server.pid. web_1 | Exiting micropost_web_1 exited with code 1
起動しようと頑張っていますが, 最終的にはExit
していますね. その理由がまさにこれです.
A server is already running.
つまり原因は, 「すでにサーバーが起動しているんだし, 俺の出番は無ぇな」とRailsが判断してしまっていることにあります. Rails Serverが起動しているものと, Railsが勘違いしてしまったわけですね.
その勘違いの原因となっているのが, tmp/pids/server.pid
というファイルです. 中身を見てみましょう.
$ cat tmp/pids/server.pid 1
ひとつだけ書かれた数字はRails ServerのPIDです. 大学で数学を専攻していた方は単項イデアル整域だと勘違いするかもしれませんが, これはProcess ID
の略です.
Linuxでは各プロセスにIDをつけて管理しています. またDockerでは, プロセスIDが1であるプロセスが終了した場合, コンテナも終了するようになっています.
これでトラブルが発生した流れが見えてきましたね.
トラブル発生の流れ
Ctrl+D
で強制終了してしまったことにより, tmp/pids/server.pid
が残ったままになってしまいました. docker-compose down
で終了したならば, これらの一時ファイルやネットワーク, コンテナを自動で消去してくれるはずでした.
この状態で起動を試みると, Railsはtmp/pids/
内の消去されなかったファイルを見て, Rails Serverが起動していると勘違いを起こします.
するとRails Serverは起動を中止します.
プロセスIDが1であるプロセスが終了したため, コンテナも停止します.
まとめ
- 正しいコマンドで終了しましょう.
- トラブルが起きたら落ち着いて対処しましょう.
Railsチュートリアル 第6章
6.1 Userモデル
6.1.1
演習1
schema.rb
の内容は以下の通りです.
ActiveRecord::Schema.define(version: 2018_06_25_044152) do create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| t.string "name" t.string "email" t.datetime "created_at", null: false t.datetime "updated_at", null: false end end
演習2, 3
省略.
6.1.2
演習1, 2
以下のコマンドを実行し, コンテナの中に入ります.
$ docker-compose exec web bash
Railsの対話モードに入ります.
$ rails console
クラスについて調べます.
>> user = User.new (0.5ms) SET NAMES utf8, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483 => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> >> user.class.superclass => ApplicationRecord(abstract) >> user.class.superclass.superclass => ActiveRecord::Base
6.1.3
演習1
たしかにString
クラスです.
>> user = User.new(name: "Michael Hartl", email: "mhartl@example.com") => #<User id: nil, name: "Michael Hartl", email: "mhartl@example.com", created_at: nil, updated_at: nil> >> user.name.class => String >> user.email.class => String
演習2
こんな感じです.
>> user.created_at.class => ActiveSupport::TimeWithZone >> user.updated_at.class => ActiveSupport::TimeWithZone
6.1.4
演習1
find_by_name
メソッドも使えました.
>> User.find_by(name: "Michael Hartl") User Load (0.8ms) SELECT `users`.* FROM `users` WHERE `users`.`name` = 'Michael Hartl' LIMIT 1 => #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2018-06-25 05:01:54", updated_at: "2018-06-25 05:01:54"> >> User.find_by_name("Michael Hartl") User Load (0.9ms) SELECT `users`.* FROM `users` WHERE `users`.`name` = 'Michael Hartl' LIMIT 1 => #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2018-06-25 05:01:54", updated_at: "2018-06-25 05:01:54">
演習2, 3
>> User.all.class => User::ActiveRecord_Relation >> User.all.length User Load (1.0ms) SELECT `users`.* FROM `users` => 2
6.1.5
演習1
>> user.name = "Michael Jackson" => "Michael Jackson" >> user.save (0.6ms) SAVEPOINT active_record_1 User Update (1.0ms) UPDATE `users` SET `name` = 'Michael Jackson', `updated_at` = '2018-06-25 05:23:28' WHERE `users`.`id` = 1 (0.6ms) RELEASE SAVEPOINT active_record_1 => true
演習2
>> user.update_attributes(email: "mjackson@example.com") (0.6ms) SAVEPOINT active_record_1 User Update (0.6ms) UPDATE `users` SET `email` = 'mjackson@example.com', `updated_at` = '2018-06-25 05:24:00' WHERE `users`.`id` = 1 (0.9ms) RELEASE SAVEPOINT active_record_1 => true
演習3
>> user.created_at = 1.year.ago => Sun, 25 Jun 2017 05:24:28 UTC +00:00
6.2 ユーザーを検証する
6.2.1
省略.
6.2.2
演習1
name
とemail
は空白であってはならないからですね.
>> u = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> >> u.valid? => false >> u.errors.full_messages => ["Name can't be blank", "Email can't be blank"]
演習2
ハッシュに使われているキーがシンボルであることに注意すると, 以下のようにエラーメッセージを取得することができます.
>> u.errors.messages => {:name=>["can't be blank"], :email=>["can't be blank"]} >> u.errors.messages[:email] => ["can't be blank"]
6.2.3
演習1, 2
以下のようなエラーメッセージが得られます.
>> u = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> >> u.name = "a"*51 => "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" >> u.valid? => false >> u.errors.full_messages => ["Name is too long (maximum is 50 characters)", "Email can't be blank"]
6.2.4
省略.
6.2.5
- アプリケーションレベルの一意性
- データベースレベルの一意性
- インデックス
- コールバックメソッド
などかなり盛りだくさんなセクションでしたが, チュートリアル通りに進めればよいだけなので, 省略します.
6.3 セキュアなパスワードを追加する
6.3.1
パスワード保存用のカラムをマイグレーションファイルに定義してdb:migrate
. ここまでしっかりやってくれば予想ができる手順ですね. それにしてもhas_secure_password
の万能感がハンパないです.6.3.2
rails console
にて確かめました.
>> user = User.new(name: "Michael Hartl", email: "mhartl@example.com") => #<User id: nil, name: "Michael Hartl", email: "mhartl@example.com", created_at: nil, updated_at: nil, password_digest: nil> >> user.valid? => false >> user.errors.full_messages => ["Password can't be blank"]
6.3.3
rails console
にて確かめました.
>> user = User.new >> user.name = "Foo" >> user.email = "foo@bar.com" >> user.password = "pass" >> user.valid? => false >> user.errors.full_messages => ["Password is too short (minimum is 6 characters)"]
6.3.4
演習1
まずはUser
を作り, 保存します.
>> user = User.new(name: "Michael Hartl", email: "mhartl@example.com", password: "foobar", password_confirmation: "foobar") >> user.save
一旦exit
してから再びconsole
を起動します. 検索してみると確かにさっき保存したレコードが存在しますね.
>> user = User.find_by_name("Michael Hartl") => #<User id: 4, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2018-06-25 09:33:51", updated_at: "2018-06-25 09:33:51", password_digest: "$2a$10$tM4ebAaSFIzfhqzi6.Lo/Ofs6/TfKpnP7LrgkCRV/z0...">
演習2
名前を書き換えて保存を試みます.
>> user.name = "Michael Jackson" => "Michael Jackson" >> user.save => false >> user.errors.full_messages => ["Password can't be blank", "Password is too short (minimum is 6 characters)"]
パスワードを要求されてしまいました. データを更新するには認証が必要ということでしょうかね.
演習3
検証を回避しつつデータを更新する方法が, 6.1.5に書かれています.
>> user.update_attribute(:name, "Michael Jackson") => true
Railsチュートリアル第5章
5.1 構造を追加する
5.1.1
レイアウトファイルを更新し, home.html.erb
も編集をします. curl
コマンドでRailsのロゴをダウンロードしました. 確認のためにFinderからロゴ画像を開いたところ, 邪魔な.DS_Store
ファイルが生成されてしまいました.
$ git status # 中略 Untracked files: (use "git add <file>..." to include in what will be committed) ../../../.DS_Store ../../.DS_Store ../.DS_Store rails.png
調べてみると, いらないファイルのようですね. 一気に削除してしまいましょう. しかしこの削除作業は今後も行う可能性があるので, 削除コマンドのエイリアスを作成することにします. ~/.bashrc
にエイリアスを定義します.
# ~/.bashrc alias delds='find ~/path/to/app/root/ -name .DS_Store | xargs rm -v'
変更を適用しましょう.
$ source ~/.bashrc
あとは定義したコマンドを実行すればファイルを削除できます. これらのファイルは今後発生する可能性があるわけですが, Gitにも追跡して欲しくありません. ということで.gitignore
にも書いておきましょう.
# .gitignore .DS_Store
演習1, 2, 3
本文と同様なので省略しますが, 猫画像は消しておきましょう.
5.1.2
省略します.
5.1.3
こちらも書かれている通りにやるだけなので省略します.
5.2 Sassとアセットパイプライン
省略します.
5.3 レイアウトのリンク
5.3.1
このセクションの内容はすでに3章で終えていますね.
5.3.2
演習1, 2, 3
エディタのUNDO機能を使って変更を元に戻すと書かれていますが, Gitの機能を使うほうが楽な気がします. まずは演習以前の内容をコミットしておきます.
$ git commit -a
演習を終えたら, ワークツリーの変更をなかったことにします.
# アプリケーションルートで実行 $ git checkout .
5.3.3
省略します.
5.3.4
演習1
省略します.
演習2
application_helper_test.rb
は以下のようになりました.
require 'test_helper' class ApplicationHelperTest < ActionView::TestCase def setup @base_title = 'Ruby on Rails Tutorial Sample App' end test "full title helper" do assert_equal full_title ,@base_title assert_equal full_title("Help"), "Help | #{@base_title}" end end
5.4 ユーザー登録: 最初のステップ
5.4.1
はじめ間違って以下のように実行してしまいました.
docker-compose exec -T web rails generate controller User new
どこが違うのかというと, User
が単数形になっています. これのせいでエラーが出て, 少し時間を無駄にしてしまいました.
5.4.2
演習1, 2
省略します.
演習3
テストコードは以下のようになりました.
# test/integration/site_layout_test.rb get signup_path assert_select "title", full_title("Sign up")
Railsチュートリアル 第4章
Railsチュートリアルの第4章です. この章はわりと演習が楽しかったですね.
4.1 動機
トピックブランチを作成し, チェックアウトします.
4.1.1
省略.
4.1.2
カスタムヘルパーの作成は, 4.2を終えてからにします.
4.2 文字列とメソッド
4.2.1
省略.
4.2.2
省略.
4.2.3
ぱっと見, 文字列展開ちゃんとされるの?と思いましたが大丈夫でしたね.
>> string = "foobar" >> puts "The string '#{string}' is nonempty." unless string.empty?
演習1
省略.
演習2
リバースしたかどうかが分かる単語でも試してみるとよいですね.
演習3
true
が返ってきました.
演習4
nil
が返ってきました.
>> s = "onomatopoeia" >> puts "It's a palinrome!" if s == s.reverse => nil
4.2.4
演習1, 2
真似して書くだけですね.
演習3
次のようになりました.
>> palindrome_tester("racecar").nil? It's a palindrome! => true
4.2.5
ここでやり残していたカスタムヘルパーの作成を行いました.
テストコードを書き直します.
# test/controllers/static_pages_controller_test.rb # の一部を抜粋しています def setup @base_title = "Ruby on Rails Tutorial Sample App" end test "should get root" do get root_url assert_response :success end test "should get home" do get static_pages_home_url assert_response :success assert_select "title", @base_title #書き直し end
レイアウトを変更します.
# app/views/layouts/application.html.erb # の一部を抜粋しています <title><%= full_title(yield(:title)) %></title>
Home
ではbase_title
しか表示させないので, タイトル設定を消します.
# app/views/static_pages/home.html.erb <% provide(:title, "Home") %> # この行を削除 <h1>Sample App</h1> <p> This is the home page for the <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a> sample application. </p>
4.3 他のデータ構造
4.3.1
演習1, 2, 3
# 指定された文字列を変数sに格納 >> s = "A man, a plan, a canal, Panama" => "A man, a plan, a canal, Panama" # 文字列を分割して配列にする >> a = s.split(", ") => ["A man", "a plan", "a canal", "Panama"] # 再びひとつの文字列に >> s = a.join => "A mana plana canalPanama" # スペースを無くします >> s = s.split.join => "AmanaplanacanalPanama" # このままでは回文ではありませんが, >> s == s.reverse => false # 小文字に揃えれば回文です # メソッドチェーンの順番を変えたものもチェックしておきました. >> s.downcase == s.downcase.reverse => true >> s.downcase == s.reverse.downcase => true
演習4
# 範囲オブジェクトを配列に変換し, 変数tに格納 >> t = ("a".."z").to_a => ["a", "b", (途中省略), "z"] # 指定された2つとも取り出せるかと思いきやダメ >> t[7,-7] => nil >> t[7] => "h" >> t[-7] => "t" # インデックス2以降から3つ取り出す, という意味なんですね >> t[2,3] => ["c", "d", "e"]
4.3.2
演習1
範囲オブジェクトをかっこで囲うのを忘れてはいけませんね. またputs
を書かないと出力が目に見えません.
>> (0..16).each {|n| puts n**2} 0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 => 0..16
演習2
ブロックを使わずとも定義できてしまいますね.
>> def yeller (array) >> array.join.upcase >> end => :yeller >> yeller("abc".split) => "ABC"
ブロックを使うなら以下のようになりますかね.
>> def yeller (array) >> array.map {|s| s.upcase}.join >> end => :yeller >> yeller("abc".split) => "ABC"
演習3
本文中にある方法だと, 異なる8文字の順列を作ることになります. ここはもう一歩踏み込んで, 重複ありの文字列を生成させてみます. 以下のような実装を思いつきました.
>> def random_dubdomain >> (0..7).map do >> ("a".."z").to_a.shuffle[0] >> end >> .join >> end => :random_dubdomain >> random_dubdomain => "uknjxsoa" >> random_dubdomain => "htoenews"
はじめ8.times
を使うことを思いつきましたが, 無駄にローカル変数を定義することになりそうです.
>> def random_subdomain >> tmp = [] >> 8.times do >> tmp << ("a".."z").to_a.shuffle[0] >> end >> tmp.join >> end => :random_subdomain >> random_subdomain => "xruoispc" >> random_subdomain => "wqdizcoc"
演習4
ヒント通りにやりました. split('')
がポイントですね.
>> def string_shuffle (s) >> s.split('').shuffle.join >> end => :string_shuffle >> string_shuffle("foobar") => "ofbaro"
4.3.3
演習1
rails console
では日本語が打てないので英語で対処しました.
>> hash = { "one" => "uno", "two" => "dos", "three" => "tres" } => {"one"=>"uno", "two"=>"dos", "three"=>"tres"} >> hash.each do |key, value| >> puts "'#{key}' is '#{value}' in Spanish" >> end 'one' is 'uno' in Spanish 'two' is 'dos' in Spanish 'three' is 'tres' in Spanish => {"one"=>"uno", "two"=>"dos", "three"=>"tres"}
演習2
サザエさんにご登場いただきました. 本文にあるように, 中括弧{ }
の内側には空白を入れています.
>> person1 = { first: "Masuo", last: "Fuguta" } => {:first=>"Masuo", :last=>"Fuguta"} >> person2 = { first: "Sazae", last: "Fuguta" } => {:first=>"Sazae", :last=>"Fuguta"} >> person3 = { first: "Tarao", last: "Fuguta" } => {:first=>"Tarao", :last=>"Fuguta"} >> params = { father: person1, mather: person2, child: person3 } => {:father=>{:first=>"Masuo", :last=>"Fuguta"}, :mather=>{:first=>"Sazae", :last=>"Fuguta"}, :child=>{:first=>"Tarao", :last=>"Fuguta"}} >> params[:father][:first] == person1[:first] => true
演習3
ランダムな文字列を作るメソッドを定義します.
>> def random_string >> (0..15).map do >> ("a".."z").to_a.shuffle[0] >> end >> .join >> end => :random_string
user
を作ります.
>> user = { name: "logicoffee", email: "logicoffee@example.com", password_digest: random_string } => {:name=>"logicoffee", :email=>"logicoffee@example.com", :password_digest=>"wjvqvczpmxmmvdwe"}
演習4
ここを見てみると, 2つのハッシュを組み合わせて新たなハッシュを返すメソッドのようですね. キーが重複している場合は上書きされるようです. やってみましょう.
>> { "a" => 100, "b" => 200 }.merge({ "b" => 300 }) => {"a"=>100, "b"=>300}
やはりそのようですね.
4.4 Rubyにおけるクラス
4.4.1
演習1, 2, 3
範囲オブジェクトの比較には注意が必要ですね.
>> r = Range.new(0,10) => 0..10 >> r == 0..10 Traceback (most recent call last): 1: from (irb):4 ArgumentError (bad value for range) >> r == (0..10) => true
4.4.2
演習1
>> r = 0..10 => 0..10 >> r.class => Range >> r.class.superclass => Object >> r.class.superclass.superclass => BasicObject >> h = { name: "Taro" } => {:name=>"Taro"} >> h.class => Hash >> h.class.superclass => Object >> h.class.superclass.superclass => BasicObject >> s = :name => :name >> s.class => Symbol >> s.class.superclass => Object >> s.class.superclass.superclass => BasicObject
演習2
たしかにself
キーワードを省略できますね.
>> class Word < String >> def palindrome? >> self == reverse >> end >> end => :palindrome? >> s = Word.new("level") => "level" >> s.palindrome? => true
4.4.3
演習1
例のように=> :String
とはなりませんでした.
>> class String >> def palindrome? >> self == self.reverse >> end >> end => :palindrome? >> "racecar".palindrome? => true >> "onomatopoeia".palindrome? => false >> "Malayalam".downcase.palindrome? => true
演習2, 3
>> class String >> def shuffle >> self.split("").shuffle.join >> end >> end => :shuffle >> "abcdefg".shuffle => "dgcbeaf" >> class String >> def shuffle >> split("").shuffle.join >> end >> end => :shuffle >> "onomatopoeia".shuffle => "eopiooataonm"
4.4.4
省略します.
4.4.5
演習1, 2, 3
example_user.rb
を用意します. full_name
メソッドと, alphabetical_name
メソッドで, インスタンス変数へのアクセス方法を変えてみました.
class User attr_accessor :first_name, :last_name, :email def initialize (attributes = {}) @first_name = attributes[:first_name] @last_name = attributes[:last_name] @email = attributes[:email] end def full_name "#{first_name} #{last_name}" end def alphabetical_name "#{@last_name}, #{@first_name}" end def formatted_email "#{full_name} <#{email}>" end end
特に問題なくできました.
>> require './example_user.rb' => true >> user = User.new(first_name: "Michael", last_name: "Hartle", email: "mhartl@example.com") => #<User:0x000055993280b6c0 @first_name="Michael", @last_name="Hartle", @email="mhartl@example.com"> >> user.full_name => "Michael Hartle" >> user.alphabetical_name => "Hartle, Michael" >> user.formatted_email => "Michael Hartle <mhartl@example.com>" >> user.full_name.split == user.alphabetical_name.split(', ').reverse => true
Railsチュートリアル 第3章
Railsチュートリアルの第3章を進めた際のメモです. チュートリアルに書かれていることは書かないようにしています. かなり個人的なメモですから, 参考程度にご覧ください.
3.1 セットアップ
Dockerを使って環境を構築しました. 詳しくはこちらで解説しています.
その他は省略します.
3.2 静的ページ
トピックブランチを作成しチェックアウト.
git checkout -b static-pages
3.2.1
rails
コマンドはコンテナの中で実行しなくてはなりませんから, docker-compose exec
を使うとよいでしょう.
docker-compose exec -T web rails generate controller StaticPages home help
デフォルトでは標準入出力にTTYが割り当てられてしまいますが, オプション-T
でそれをオフにしています.
rails destroy
も試したあと, git commit
しておきました.
3.3 テストから始める
「テスト駆動」にするのか「一括テスト」にするのかについてのガイドラインは, 今後ためになりそうですね.
3.3.1
テストを実行します.
docker-compose exec -T web rails test
気なる文字列が表示されましたが, テストはうまくいったようです.
Running via Spring preloader in process 168 /myapp/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /myapp/config/application.rb to limit the frameworks that will be loaded. Run options: --seed 47859 # Running: .. Finished in 1.537890s, 1.3005 runs/s, 1.3005 assertions/s. 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
3.3.2
指示通り実行し, テストはひとつだけ失敗しました. テストコードはDRY原則にあてはまっていないですが, これはきっと3.4.3でやるんでしょうね.
3.3.3
ルーティングの設定を書き加えて再びテストを実行します. テストは失敗しますが, エラーメッセージが変わりました.
アクションを追加してテストを実行します. テストは失敗しますが, またエラーメッセージが変わりました.
Viewファイルを追加することにより, やっとテストにパスしました. ブラウザでも確認ができました.
3.4 少しだけ動的なページ
レイアウトが自動設定されないように, レイアウトファイルの名前を変更しておきます. ただしGitにそれを知らせるため, git mv
コマンドを使います.
git mv application.html.erb layout_file
3.4.1
テストを書き, 失敗することを確認.
3.4.2
タイトルを追加し, テストをパス.
演習1
テストコードには繰り返しの部分がたくさんあったので, インスタンス変数でまとめます.
3.4.3
レイアウトを利用することで, 各Viewファイルがかなりスッキリしました.
演習1
まずテストコードを書きます.
# test/controllers/static_pages_controller_test.rb test "should get contact" do get static_pages_contact_url assert_response :success assert_select "title", "Contact | #{@base_title}" end
テストを実行し, 正しいエラーメッセージが出ることを確認します.
$ docker-compose exec -T web rails test NameError: undefined local variable or method `static_pages_contact_url'
URLがないというエラーがでているので,ルーティング設定を追加しましょう.
# config/routes.rb Rails.application.routes.draw do get 'static_pages/home' get 'static_pages/help' get 'static_pages/about' get 'static_pages/contact' # 追加 end
再びテストを実行すると, エラーメッセージが変わります.
$ docker-compose exec -T web rails test AbstractController::ActionNotFound: The action 'contact' could not be found for StaticPagesController
アクションがないというエラーが出ているので, アクションを追加しましょう.
# app/controllers/static_pages_controller.rb class StaticPagesController < ApplicationController #追加 def contact end end
再びテストを実行すると, さらにエラーメッセージが変わります.
$ docker-compose exec -T web rails test ActionController::UnknownFormat: StaticPagesController#contact is missing a template for this request format and variant.
Viweファイルがないというエラーが出ているので作りましょう.
# app/views/static_pages/contact.html.erb <% provide(:title, "Contact") %> <h1>Contact</h1> <p> Contact the Ruby on Rails Tutorial about the sample app at the <a href="https://railstutorial.jp/contact">contact page</a>. </p>
テストもパスし, ブラウザでも確認することができます.
3.4.4
rootルーティングの設定をしました.
演習1
テストコードを追加し, テストを実行します. パスできました.
次にrootルーティングの設定をコメントアウトしてテストを実行します. すると以下のようなエラーメッセージが表示されました.
NameError: undefined local variable or method `root_url'
コメントアウトを外すとテストをパスできます.
3.5 最後に
現在のトピックブランチであるstatic-pages
をmaster
ブランチにマージします.
3.6 高度なセットアップ
3.6.1
色付きで進捗状況が表示されるようになりました.
3.6.2
テストの自動化はDocker環境でも問題ないのでしょうか...? ひとまず試してみます.
docker-compose exec -T web bundle exec guard init
Guardfile
が作成されるので, 指示通りに書き換えます. Git
がspring files
を追跡しないように.gitignore
を編集します.
以下のコマンドを実行し, Guardをオン?にします.
$ docker-compose exec -T web bundle exec guard 05:38:32 - INFO - Guard::Minitest 2.4.6 is running, with Minitest::Unit 5.11.3! 05:38:34 - INFO - Guard is now watching at '/myapp' [1] guard(main)>
するとプロンプトが表示されたので, そのままEnterを押しました. するとテストが実行されて, 再び同じプロンプトが表示され待機状態になりました. exit
を入力することで抜けられました.
[1] guard(main)> exit exit 05:39:05 - INFO - Bye bye...
これでいいんでしょうか...?
05:39:05
などの数字は時刻っぽいですね. でも現時刻は14:41
. つまり世界標準時が表示されるようになっているようです.
以上で3章終えましたああ〜〜.
Railsチュートリアル 第2章
Railsチュートリアルの第2章を進めました. 概観をつかむ章ですね.
2.1 アプリケーションの計画
省略
2.2 Usersリソース
書かれている通りにコマンドを実行します. ただしコンテナの中に入る必要があるので, 以下を実行します.
docker exec web bash
するとコンテナに入ることができますから, チュートリアル通りに進めることができます.
$ rails generate scaffold User name:string email:string $ rails db:migrate
ブラウザでlocalhost/users
へアクセスすると, チュートリアル通りになっています.
rails server
は実行しなくてOKです.
2.2.1
好きなダーツプレイヤーの名前を入れていろいろ試しました.
演習1
ブラウザはSafariを使っているので,
Cmd + Option + U
でソースを表示します.
新しくユーザーを作成すると, 演習で問われている箇所が発見できます.
<p id="notice">User was successfully created.</p>
リロードすると, タグだけが残りました.
<p id="notice"></p>
演習2, 3
問題なくユーザーが作成できました. バリデーションはまだ実装されていないということですね.
演習4
Are you sure?
というダイアログが表示されました.
2.2.2
MVCやRESTなどのキーワードが登場.
演習1
省略
演習2
app/controllers/users_controller.rb
のedit
アクションを見てみると,
def edit end
あれ? 空っぽ...
と思ったらprivate methodが定義されていました.
private # Use callbacks to share common setup or constraints between actions. def set_user @user = User.find(params[:id]) end
これが各アクションの前に実行されることは, UsersController
のはじめの方を見るとわかります.
class UsersController < ApplicationController before_action :set_user, only: [:show, :edit, :update, :destroy]
演習3
以下の通りです.
app/views/users/edit.html.erb
2.3 Micropostsリソース
2.3.1
Usersリソースと同様ですね
演習1
これもUsersリソースと同様でした.
演習2
ContentもUserも空っぽであっても, Micropostは作成できました.
演習3
abc...xyz
を6回入力して試してみましたが, 問題なく投稿できました.
演習4
Usersリソースの場合と同様にAre you sure?
とダイアログが表示されました.
2.3.2
はじめmaximam
とスペルミスをしてしまいましたが, バリデーションが追加されたことがチェックできました. ただエラーメッセージが真っ赤でどぎつい!
演習1
バリデーションを追加すると同時にチェックしてしまいました.
演習2
見てみましたが, これだけでよいのでしょうかね.
<div id="error_explanation"> <h2>1 error prohibited this micropost from being saved:</h2> <ul> <li>Content is too long (maximum is 140 characters)</li> </ul> </div>
2.3.3
指定された通りにリレーションを定義します.
rails console
を使うためにコンテナの中に入ります.
$ docker-compose exec web bash
対話的に, ひとつのuserに複数のmicropostsが結びついていることがわかりました.
演習1
userの取得はすでにコントローラーに実装されているので, Viewファイルだけを編集すればいいですね. 以下をshow.html.erb
に追加すればよいです.
# app/view/users/show.html.erbの一部 <p> <strong>First micropost:</strong> <%= @user.microposts.first.content %> </p>
演習2, 3
指示通りに編集し, バリデーションが設定されたことが確認できました.
2.3.4 以降
演習もありますが簡単なので省略します.
Railsチュートリアル 第1章
環境構築
開発環境はDockerを使って構築しました. 詳細な手順は以前の投稿にて詳しく解説しています.
環境構築の時点で, rails new
まで終わらせています. ファイルを編集する前にGitリポジトリを作成しました.
Gemfileの編集
チュートリアル通りのバージョンではなく, rails new
によってインストールされた番号を指定するようにしました.
jquery-rails
はインストールされなかったようなので, 最新バージョンを指定してGemfileに追記しました.
sqlite3
もインストールされていませんでしたが, DBコンテナにMySQLをインストールしているので, 必要ないと判断しました.
またWindowsに必要であると書かれているGemの指定はコメントアウトしました.
公式ドキュメントに書かれているように,
Now that you’ve got a new Gemfile, you need to build the image again. (This, and changes to the Gemfile or the Dockerfile, should be the only times you’ll need to rebuild.)
Gemfileに変更があった場合はイメージを再構築します.
docker-compose build
Dockerファイルにbundle install
と書いているので, jquery-rails
がしっかりインストールされます.
Gemfileの変更を記録するためにgit commit
しておきました.
その他
リモートリポジトリ, herokuのあたりはまた今後やっていこうと思います.