Active Record joinsについて

Active Recordのjoinsmergeについて調査したレポートです。

準備

まずは、migrationファイルを設定

class CreateUserPlans < ActiveRecord::Migration[5.2]
  def change
    create_table :user_plans do |t|
      t.integer :user_id
      t.integer :plan_code
    end
  end
end


class CreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      t.string :name
      t.string :state
    end
  end
end

続いて、Userモデルを書きます

class User < ApplicationRecord
  has_many :user_plans
  scope :active, -> { where state: 'active' }
  scope :inactive, -> { where state: 'inactive' }
  has_many :active_plans, -> { where plan_code: 2 }, class_name: UserPlan.name
end

そして、Userと1対多の関連を持つUserPlanも

class UserPlan < ApplicationRecord
  belongs_to :user
  scope :active_plan, -> {
    includes(:user).where(users: { state: 'active' })
  }
  scope :po, -> {
    where(plan_code: 1)
  }
end

最後に、seed.rbを下記のようし、db:migrate && db:seedで準備完了です。

User.create!(
  name: "Admin",
  state: "active"
)

User.create!(
  name: "Imaharu",
  state: "inactive"
)

8.times do |n|
  active = [true, false].sample ? "active" : "inactive"
  User.create!(
    name: "User#{n+3}",
    state: active
  )
end

40.times do |n|
  UserPlan.create!(
    user_id: rand(8) + 1,
    plan_code: rand(3) + 1
  )
end

本題

これでは、実験してみましょう

User.joins(:user_plans).each do |user|
  p "user_id: #{user.id}, state: #{user.state}"
end

SELECT "users".* FROM "users" INNER JOIN "user_plans" ON
  "user_plans"."user_id" = "users"."id"

joinsは、INNER JOINを実行していますね。

次に、active scopeを追加してクエリを発行して見るとどうなるのでしょうか?

User.active.joins(:user_plans) を実行するとINNER JOINのクエリ結果に対してWHERE句で絞り込みをしています。Limitは無視して下さい。consoleの設定で治りそうですか

ちなみに、User.joins(:user_plans).activeとしても同じクエリが発行されます。これは、Active Recordがおそらく優先順位も持っていてうまく解釈してるのではないかと思います。そのうち、 Gemの中身を覗いてみたいです。

SELECT  "users".* FROM "users" INNER JOIN "user_plans" ON
  "user_plans"."user_id" = "users"."id"
  WHERE "users"."state" = ? LIMIT ?

続いて、mergeを使ってみましょう。mergeは結合したモデル。ここでは、UserPlanに対してアクションを可能にします。

ここで、ポイントなのだが、activeと並列のWHERE句にある点です。

このことから、mergeはINNER JOINで得られた結果に評価を加えていることがわかります。

User.active.joins(:user_plans).merge(UserPlan.po)

SELECT  "users".* FROM "users" INNER JOIN "user_plans" ON
  "user_plans"."user_id" = "users"."id"
  WHERE
    "users"."state" = ?
  AND
    "user_plans"."plan_code" = ?
  LIMIT ?
    [["state", "active"], ["plan_code", 1], ["LIMIT", 11]]

最後に、INNER JOIN前に絞り込む方法をみていきましょう

has_many :active_plans, -> { where plan_code: 2 }, class_name: UserPlan.nameが該当箇所です。

ANDで条件をしてできていることが確認できました。上記の関連付けに特別な名前がありそうな雰囲気ですが、ちょっとわからないです。 もし、知っていればコメントして下さい!

User.joins(:active_plans)

SELECT  "users".* FROM "users" INNER JOIN "user_plans" ON "user_plans"."user_id" = "users"."id" AND "user_plans"."plan_code" = ? LIMIT ?  [["plan_code", 2], ["LIMIT", 11]]

以上で調査結果でした。ご静聴ありがとうございました。

sendメソッドについて

RSpecを用いたServiceクラスのテストにて、 __send__ メソッドが使われていました。

知らないメソッドだったので、調査してみました。

Ruby 2.5.0リファレンスマニュアルには、send__send__ について下記のように記載されています。

オブジェクトのメソッド name を args を引数に して呼び出し、メソッドの実行結果を返します。

ブロック付きで呼ばれたときはブロックもそのまま引き渡します。

send が再定義された場合に備えて別名 send も 用意されており、ライブラリではこちらを使うべきです。また send は再定義すべきではありません。

send, send は、メソッドの呼び出し制限 にかかわらず任意のメソッドを呼び出せます。 クラス/メソッドの定義/呼び出し制限 も参照してください。

[PARAM] name:

 文字列かSymbol で指定するメソッド名です。

[PARAM] args:

 呼び出すメソッドに渡す引数です。

利用方法

まずは、基本的な利用方法をみていきましょう

class User
  def name1
    "Taro"
  end

  def name2
    "Hanako"
  end
end

user1 = User.new.send("name1")
user2 = User.new.send(:name2)
p user1
p user2

Userクラスのオブジェクトについて send メソッドを呼び出すと、指定したインスタンスメソッドが実行されることがわかります。

次に、クラスメソッドを定義するとどうなるのでしょうか?

class User
  def self.name3
    "Tom"
  end
end

p User.methods.grep /name/
user3 = User.send(:name3)
p user3

クラスメソッドに対しても呼び出すことができますね。

引数を渡すことができるかを確認しましょう。

class User

  def self.name4 name4=nil
    if name4.nil?
      p "You pass class method but value is nil"
    else
      p name4
    end
  end
end

user4 = User.send(:name4)
user4 = User.send(:name4, "Emma")

メソッドの呼び出し制限 にかかわらず任意のメソッドを呼び出せます

Privateメソッドも呼び出すことができるのでしょうか?

class User
  private
  def private_name
    "殿下"
  end
end

p User.new.send(:private_name)

無事、秘密の名前を出力できたようです。

利用場面

さて、send メソッドの利用場面について考えてみましょう。

一つは、先ほど確認したPrivateメソッドも呼び出せることです。これは、テストで重宝するでしょう。

次に、メソッドを動的に決定できる点ではないでしょうか?

例えば、以下のように例があります

class User
  def dynamic_dispatch(dyName)
    send(dyName)
  end

  def user_name
    "クッパ"
  end

  def house_name
    "クッパ城"
  end

  def enemy_name
    "マリオ"
  end
end

user = User.new
["user", "house", "enemy"].each do |dyName|
    p user.dynamic_dispatch("#{dyName}_name")
end

このように、動的にメソッドを呼び出すことを 動的ディスパッチ と呼びます。

以上で、send の調査は終了です。

ご静聴ありがとうございました。

git logオプションを調べてみた

rebaseで困りログを確認しているとメンターに、 git log --decorate --all --graph というコマンドを教えてもらいました。

俺は、まだまだGitのことを知らない!ということで、 git log --help で今後使いそうなオプションを調べてみました。

  • -n 10 過去10件分のログを表示

  • --pretty=oneline コミットを一行で表示

  • --relative-date 現在からの相対的な時間を知れる。ex. 3day ago

  • --graph ログをいい感じで出力する

  • --grep コミットメッセージに対するgrep

  • --merges マージコミットのみ出力

  • --no-merges マージコミットを含めない

  • --reverse ログの出力を逆にする

  • --date=human ex. Thu May 30 16:48

 使いそうな例

  • 1日前のログ

git log --relative-date --since="1 day"

  • 3日前のログ

git log --relative-date --since="3 days"

  • 過去1週間のログ

git log --relative-date --since="1 week"

  • 現在ブランチでコミットしたログ

git log --no-merges master..brach_name

  • 特定のフォルダーのログ

git log -p -- spec/models

  • 特定文字列の削除・追加を含むコミットログとコミット内容を表示

git log -S"def update" --patch

この場合は、updateメソッドの変更を表示

  • リモートブランチのログ

git log origin/hoge

Learn Betterを読んだ

Learn Better――頭の使い方が変わり、学びが深まる6つのステップ

Learn Better――頭の使い方が変わり、学びが深まる6つのステップ

目次

イントロダクション

第一章 価値を見いだす

第二章 目標を決める

第三章 能力を伸ばす

第四章 発展させる

第五章 関係づける

第六章 再考する

エピローグ

ツールキット

自分がタイトルをつけるなら?

どMの自己管理

学び・考えたこと

メタ認知とは何か

著書にて、メタ認知とは思考について思考することで、広い意味では自分が物事をどう理解するかを理解することを指す。

とある。今まで、雰囲気でメタ認知という言葉を理解していた気がするので一度自分の言葉で言語化すると

対象へのリンクを貼るということではないかと考える。メタという言葉の使われた方が次元をあげる印象をうけてしまう。

しかしながら、人間は高次元的な思考への理解が難しいと考えおり、どうもしっくりこない。

そこで、ネットワークのようにリンク結合で考えてみた。

メタ認知でない、つまり認知行動は対象のみの事象として存在している。しかしながら、実際には対象以外にも点々と存在する別の事象が存在しているのである。

メタ認知的な思考方法では、対象と意味づけによって露わになったリンクを関連付けを行う。

これが、メタ認知の理解である。

熟考すると、高次元化というのは正しい理解でないように思える。

本質は、角度や高さを変えてる。視点を変えることだ。

一度、事象の周りを散歩してみる感覚を持つことがメタ認知である。

知識効果(ナレッジ・エフェクト)

専門知識を理解するため際に、すでに持っている知識が学習促進を行うこと。

学習は難しくて当たり前

学習ゲームの効果はないということに、驚いた。与えられたものでなく苦労して脳みそで考えることが重要。

ネットワークに繋がっているだけで、集中力が切れてしまう。しかし、時代は加速度的にオンライン学習コンテンツに傾いている。

重要になるのは、誘惑に負けない学習体験を作り出すことだ。

フェードバックをもらうには

著書で、フェードバックの重要性が述べられている。

そもそも、フェードバックをもらうにはどうすればいいのだろうか?

答えは明確な気がして、「謙虚になる」ということだがこれがかなり難しい。

著書でも、過信を危惧していた。自分のスキルと人間性。二つで謙虚になる必要がある。

ところで、大人になればなるほど、関わっていてめんどくさい人は注意されなくなってしまう。

ここで悪循環が生まれるわけだが、これを解決する手段を見出せていない。

子供のころから、フェードバックの文化を徹底されば人は謙虚になるというユートピアを妄想してみたり

hodai.globis.co.jp

大学の誕生から研究としての大学再生までの歴史

概要

本記事は、「高等教育の大衆化は可能か」という自らの問いに答えを出すべく、大学の歴史について調べてたちょっとしたまとめです。

30冊ほど、読んで約2000文字程度にしかなりませんでしたが、大まかな流れがわかる内容になっているのではないかと思います。

まだまだ、大学史については日本における大学史とMoocなどがありますが一旦のアウトプットです。

本題

中世における大学の誕生からフンボルトによって再定義されたドイツのベルリン大学まで述べる.

大学が誕生するに至った中世ヨーロッパの時代背景について記述する.その時代は,三圃制の普及や犂など農業技術の進歩した.これらの技術発展に伴い,特権階級を養うだけの余剰生産物が生まれたのである。また、余剰生産物の交易を行うため都市間で交流が盛んになったことで、聖職者階級の読み書き能力の独占が打破されていく。このことによって、精神労働が職業として評価されることになる。最後に、十字軍の遠征によるアラビアとの接触により、アリストテレスを代表とする失われた数多くの書物が翻訳されたことだ。翻訳活動によって、知識の絶対量が大きく増大のだ。

これらを背景として、権威からの認可を大学誕生条件とするのであれば1158年、世界最古の大学、神聖ローマ皇帝フリードリヒ1世の「特許状」によってボローニャ大学が誕生した。これに続くように,パリ大学でも1231年、「諸学の父」によって教皇から特権が保証された。これらの大学は、後に設立される諸大学の模範となった。例えば、オックスフォードはパリ大学を模倣した。両大学の違いは、ボローニャ大学が同郷同士で結成されたナチオから派生した学生団体が主体であったのに対し、パリ大学ではカレッジと呼ばれる教師団体が主体であった点だ。しかしながら、両大学は、皇帝や教皇という権力からではなく、内発的な活動によって大学が設立したことは共通である。

次に、中世大学の特徴とは何であろうか。それは、特定の建物を持たないことによって移動の自由があった点である。これを脅しの材料として、大学側は特権が与えられた後も、様々な権利を求めた。権力者側は、大学からの利益が無視出来ないことから譲歩した。このことから、大学に権力に対する強い抵抗力があったことがわかる。また、移動により知識流動性が向上した。

しかしながら、大学は14世紀から衰退の一途をたどっていく。第一の原因は,初期の大学が学生や教師の内発的動機により発足したのに対して,君主や都市といった政治権力との関わりが強まったことにある.「大学の歴史」によると1500年は約60と1376年と比べ倍以上に増加している.第二の原因は,グーテンベルクによる活版印刷技術の発明である.この発明により庶民の間にも書籍が浸透し最早大学は知的好奇心を満たす唯一無二の場所ではなくなったのである。

最後に、1810年のベルリン大学の設立以降、大学の役割が教育のみならず研究機関としての役割を帯び始めた。「研究と教育」として大学を形成したベルリン大学がヴィルヘルム・フォン・フンボルト指導の元、設立された。まず、ベルリン大学が設立された経緯を述べる。イエナの戦いにて敗戦国となったプロイセン(ドイツ)は、ナポレオンとティルジット条約を締結した。プロイセンはフランスに追いつくべく、封建的な体制を改める内政改革が焦眉の急であった。教育においても例外ではなく、フンボルトが改革の指導者として抜擢された。

教育と研究は水と油と思われるかもしれないが、フンボルトが提唱した大学の理念は、教育を研究活動に求めた。フンボルトの大学理念は二つの観念に帰着する。第一は、学問という概念の再認識である。学問は、教師から享受するものではなく己の内発的な活動のよって産出されるものとなった。このことは、教授と学生との双方向の関係性を強めた。第二の理念は、学問の統一である。学問の統一とは、学問がひとつの有機体だということだ。各学問分野がそれぞれ自立しているのではなく、弱い結びつきによって成立しているということである。文明の成り立ちを例にとると、歴史学のみならず、なぜそこに川が流れていたかという地理学や生物の生態といった生物学の知識が必要となるだろう。そういう意味で、大学とは総合大学のように異なる学問領域が刺激し合う空間である必要がある。以上の理念からなる、研究による人間の陶冶がフンボルトの目指した大学の構想であった。

本節は、大学の誕生から近世大学の典型となったベルリン大学までの歴史について述べた。 学生と教師の組合から始まった大学という組織は、次第に政治権力に利用されることによって腐敗していった。大学の衰退は、国民国家形成機関として大学を定義するベルリン大学によって立ち直る。このことは、大学がごく少数のエリート層育成機関ではなく、国民を陶冶するという困難な課題へ立ち向かう道を歩む始めたことを示唆するのである。

Effective Testing with RSpec 3を読んだ

Amazonレビュー的な何か

RSpec3自体の効果的な使い方が網羅的に紹介されている書籍です。

RSpecのバージョンは、3.6.0です

どのように、RSpecでテストを書いていくかという具体的なテスト方法に関する内容より、しっかり調べていないと使わないようなオプションや機能などが紹介されていて、学ぶの多い書籍です。

はじめに、書籍の読み方が紹介されています。全15章のうち6章までが基礎的な内容のためそこまでは読むといいようです。

実務において、APIのテストをする機会があり、効果的なMockやstubの使い方がわかりませんでした。むしろ、MockやStub、正直に言うと、Test Doubleに関するあらゆる知識がありませんでした。書籍では、最後の3章にてRSpec Mocksについて解説しています。

13、14章を読むとTest Doubleに関する全体像がぼんやりと見えてきます。しかし、これがRSpecに基づく知識なのか、他のテストツールと比べることで理解を深める必要があるでしょう。一旦は、満足する自分の中での説明ができるようになりました。

最後の15章は、より実践的なTest Doubleの使い方が紹介されています。

特に、Using Partial Doubles Effectively の節は心にグッサリとくるものがあります。 追加機能を作る時、テストを置き換える前に既存コードをリファクタリングすること視点を学ぶことができました。

本書は、RSpecを書き始めた全ての人に読んで欲しい本です。6章までは。

翻訳はされていませんが、かなりわかりやすい英語で書かれているので英語が苦手な人でも簡単に読むことができるでしょう。

学んだこと

  • filter_gems_from_backtraceでトレースするgemを制限できる

  • aggregate_failuresで、ブロックでまとめたテストが落ちても続けてブロック内を実行してくれる

  • --bisectオプションを付けることで、ランダムに失敗するspecの再現を最小のテスト構成を知ることができる

  • a_hash_including includeのalias。エラーメッセージが読みやすくなる。

RSpec Mocks

  • Stub I/Oなどを避けるために定型文を返す。

http_response = double(​'HTTPResponse'​, ​status: ​200, ​body: ​​'OK'​) がシンプルな書き方。

実務では、下記のように記載する。

http_response = double(​'HTTPResponse'​)
allow​(http_response).to receive_messages(​status: ​200, ​body: ​​'OK'​)
or
allow​(http_response).to receive(​:status​).and_return(200)
allow​(http_response).to receive(​:body​).and_return(​'OK'​)
  • Mock

テスト内で指定したメッセージを受け取らなければエラーを返す。

  • Spy

スタブやMockなどで実行する前に結果を明示するのは、やや違和感がある。

Spyを使うとテストコードを実行した後に、何が実行過程に起こったかを確認できる。

Spyを使う場合は、null objectかallowでメッセージを許可する必要がある。

  • PARTIAL DOUBLES

組み込みライブラリなどオブジェクトにスタブしたい時に使うdouble

  • VERIFYING DOUBLES

スタブやモックでは、仮の処理を許可しているため既存コードに変更があった場合、検知できない。

instance_double などを使うことで、メソッドなどに名前変更があった時にエラーを検知できるようになる。

  • STUBBED CONSTANTS

定数をスタブする。

hide_const(​'ActiveRecord'​) とすると、Active Recordを使わないようにできる。

  • withで引数を指定できる。

引数の名前にこだわらない場合は、anything を利用できる。

Effective Testing with RSpec 3: Build Ruby Apps with Confidence (English Edition)

Effective Testing with RSpec 3: Build Ruby Apps with Confidence (English Edition)

js-primerを読んだ

この書籍について · JavaScriptの入門書 #jsprimerという神サイトを読んで学んだことと疑問点

学んだこと

- 変数は大文字、小文字を区別する

- Automatic Semicolon Insertion
=> ; がないときに自動でついてくれる仕組み 

"use strict"
=> #include <stdio.c>的なものかと思っていた
strict modeで実行してレガシーな機能や構文を禁止

HTML-likeコメント
=> こういうやつ。名前を知らなかった
<!-- この行はコメントと認識される
console.log("この行はJavaScriptのコードとして実行される");
-->  この行もコメントと認識される

参照透過性
=> 定義した中身が常に一定あること

可能な限りconstを使う
constは定数ではない
ex. objectの中身を変更できる

REPL(read–eval–print loop)
よく使う開発者ツールでJavascriptを実行できるやつ

データ型
=> プリミティブ型とオブジェクト

プリミティブ型
=> 真偽値や数値などの基本的な値の型
イミュータブル

オブジェクト
=> ミュータブル

typeof nullが"object"となるのは、歴史的経緯のある仕様のバグ

基本的にtypeof演算子は、プリミティブ型またはオブジェクトかを判別するもの

リテラル
=> new String("string")とするが標準で使うので、const "string"みたいにできるもの

0から始まる浮動小数点数は、0を省略して書くことができる
=> 使わない方が良い

テンプレートリテラル
=> ``で囲む。複数行の文字列を表現

nullもリテラル

undefinedはリテラルではない
=> ただのグローバル変数

オブジェクトリテラル
プロパティ名
=> objectのkey

単項プラス演算子(+)
=> 数値文字列を数値にするときに利用
ex. console.log(+"1"); // => 1
parseIntなどを使うべき

NaNは、数値ではないがNumber型の値を表現
console.log(NaN === NaN); // false
=> .isNaNで判断

 分割代入
=> 配列やオブジェクトの値を複数の変数へ同時に代入する

const array = [1, 2];
// aには`array`の0番目の値、bには1番目の値が代入される
const [a, b] = array;
console.log(a); // => 1
console.log(b); // => 2


falsyな値
----
false
undefined
null
0
NaN
""(空文字)
----

Javascriptは、関数の仮引数と呼び出しものと引数の数が異なっても実行可能

Rest parameters
=> 仮引数名の前に...をつけた仮引数のこと

こういうのはしっかり理解したい
const user = {
    id: 42
};
// オブジェクトの分割代入
const { id } = user;
console.log(id); // => 42

ファーストクラスファンクション(第一級関数)
=> 関数が値として扱えること
こういうのメタプロRubyでみた気がする....

### 関数式
=> こういうやつ。これよく出るが、雰囲気で読んでたので理解
// 関数式は変数名で参照できるため、"関数名"を省略できる
const MoringGreetings = function SayHello(){
  return "Hello";
}
ここで、関数式の関数名は省略できるので....
const MoringGreetings = function (){
  return "Hello";
}
と等価。これを無名関数(匿名関数)と呼ぶ

### Arrow function
無名関数の表現技法

const 関数名 = () => {
    // 関数を呼び出した時の処理
    // ...
    return 関数の返す値;
};

みたいに書ける。

ここで、
1. 関数の仮引数が1つのときは()を省略できる
2. 関数の処理が1つの式である場合に、ブロックとreturn文を省略できる
その式の評価結果をreturnの返り値とする

という省略記法があるので
const mulA = {x} => { return x * x; };
const mulB = x => x * x;
は等価
ここで注意しないといけないのは。=  x =  のxは仮引数であるということ

### コールバック関数
引数として渡される関数

### 高階関数
コールバック関数を引数として使う関数やメソッド

コールバック関数と高階関数の理解が絶対いる

objectのメソッドの短縮記法がES2015で登場

### Array length
=> このテクニック面白い
const array = [1, 2, 3];
array.length = 0; // 配列を空にする

### テンプレートリテラル
バックスラッシュで文字を囲むこと
複数行にしたり、Rubyの式展開みたいなことができる
const name = "JavaScript";
console.log(`Hello ${name}!`);

JavaScriptの文字列比較はCode Unit同士を比較

Arrow Function以外の関数におけるthisの基本的な参照先は
ベースオブジェクトである。thisは、動的に参照先を決定するので
変数などに代入すると、Errorとなる。
そのためにcall、apply、bindメソッドを使って対処する。

疑問に思ったこと

Q. オブジェクトは、ミュータブルだからconstでも再代入できる?
A. オブジェクトを代入した変数はデータの実体を持ってるわけではなくて、データが存在するメモリの番地を指してるだけだから、constで宣言した際に、変数そのものに再代入(番地を上書き)するのはアカンけど、プロパティを変更するのは再代入にあたらない

暗黙的な型変換があって便利なことってある?
バグの原因にしかならない気がする

関数の渡す引数が、実際より多いときに、エラーを吐かないのは便利なのか?

再帰処理とかするときには、無名関数は無理?

課題

Array functionを頭の中で、functionで置き換えられるようにしないと勘違いする

ex. 
const doubleArray = array.map(function(value) {
    return value * 2; // 返した値をまとめた配列ができる
});
const doubleArray = array.map(value => value * 2);

DockerでRailsチュートリアル

DockerでRailsチュートリアルの開発ができるようにします。

近年は、docker-composeが主流となっていると思うのでdocker-composeを使う。

環境
Railsチュートリアルの全章が終了した状態
Mac
Dockerはインストール済み

Docker-composeのインストール

Docker Desktop for Mac and Docker Toolbox already include Compose along with other Docker apps, so Mac users do not need to install Compose separately.

引用文から、Docker for Macを準備できた時点でDocker-composeも使えるようです。

試しに、端末でdocker-compose コマンドを実行するとリファレンスが表示されますね。

Install Docker Compose | Docker Documentation

set -e

「set」はシェルの設定を確認、変更するコマンド

「set -e」でコマンド実行時にエラーになれば即座にシェルを終了する

linux - What does set -e mean in a bash script? - Stack Overflow

rails server --help

-p, [--port=port] # Runs Rails on the specified port - defaults to 3000.
-b, [--binding=IP] # Binds Rails to the specified IP - defaults to 'localhost' in development and '0.0.0.0' in other environments'.

「-p」は、ポートを指定

「-b」は、特定IPアドレスへの外部公開設定。「0.0.0.0」はローカルマシン上の全てのIPv4アドレスである。

つまり、「-b 0.0.0.0」でローカルマシン上の全てのIPv4アドレスに外部公開可能となる。

本題

[Dockerfile]
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /sample_app
WORKDIR /sample_app
COPY . /sample_app

# Add a script to be executed every time the container starts.
# COPY entrypoint.sh /usr/bin/
# RUN chmod +x /usr/bin/entrypoint.sh
# ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

  

[docker-compose.yml]
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  app:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/sample_app
    ports:
      - "3000:3000"
    depends_on:
      - db

とした後、docker-compose run app するとbundleがinstallされていないという

エラーが出た

bundler: command not found: rails Install missing gem executables with bundle install

解決策としては

以下のようにDockerfileを編集して

docker-compose builddocker-compose up を行うと

Railsチュートリアルが立ち上がる。

[Dockerfile]
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
ENV APP_ROOT /sample_app
RUN mkdir $APP_ROOT

WORKDIR $APP_ROOT
ADD Gemfile $APP_ROOT
ADD Gemfile.lock $APP_ROOT
RUN  bundle install

ADD . $APP_ROOT

CMD ["set", "-e"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

Quickstart: Compose and Rails | Docker Documentation

Virtualboxで遊ぶ

Railsチュートリアルでdocker移行に伴う事前知識のキャッチアップ記事

Virtual BoxにCentOS環境を整えます

CUIをダウンロードしました

はじめに

Virtual Box上のCentOSスクロール「shift」+「function」+「↓ or ↑」

pingを通す

nmcli device
nmcli connection modify enp0s3 connection.autoconnect yes
cat /etc/sysconfig/network-scripts/enp0s3

ONBOOT=yesになっているを確認して、reboot

ping google.com

pingができてる!!!

コピペをできるようにする

Xvfbを使えば、いいらしいssh接続すればコピペできるので、やらない

sshで接続できるようにする

ネットワーク設定をする f:id:scratch_world:20190427140115p:plain

f:id:scratch_world:20190427135553p:plain

ゲストOSにて cat /etc/hostsでホスト名を確認

ホストOSにて

ssh -p 2222 root@localhost

パスワードを求められるので、入力すると接続完了

vimを使えるようにする

yum install vim-X11 vim-common vim-enhanced vim-minimal

Apache

yum -y install httpd
systemctl status httpd
systemctl start httpd
curl localhost | grep Apache

Apacheが動いていることを確認

次にsshと同様にホストOSの8080ポートとゲストOSの80ポートをひもづけた後

firewalldでhttpを解放します。

firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --reload

http://localhost:8888/にアクセスするとよくみるApacheサーバが立ち上がっている。

参考文献

VirtualBox に入れた CentOS のネットワーク設定 - 山崎屋の技術メモ

Apache - VirtualBox上のCentOS7のApacheにホストOSからアクセスできない|teratail

erbをslimにconvertする

Gemfileにて下記記述後、 bundle install した状態を前提。

gem 'html2slim'
gem 'slim'

html2slimを使います。

# erb2slim -h

Usage: erb2slim INPUT_FILENAME_OR_DIRECTORY [OUTPUT_FILENAME_OR_DIRECTORY] [options]
        --trace                      Show a full traceback on error
    -d, --delete                     Delete ERB files
    -h, --help                       Show this message
    -v, --version                    Print version

README.mdの通り、erb2slim app/views app/views -d を実行した後に rails test

Viewのエラーを潰すことで置き換え完了。

github.com

Qiitaでワンライナーでやってる人がいたので、別解

for file in `find app/views/* -type f | grep -E ".+?\.erb$"`; do erb2slim $file && rm $file; done