Effective Ruby 第6章まとめ

こんにちは!kossyです!




さて、今回はEffective Rubyの第6章の覚えておくべき事項を
ブログにまとめてみたいと思います。

前回までの章をまとめたものはこちら
Effective Ruby 第1章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第2章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第3章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第4章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第5章まとめ - その辺にいるWebエンジニアの備忘録



第6章 テスティング

6-1. MiniTestユニットテストに慣れよう

  • テストメソッドの名前には、"test_"というプレフィックスを付けなければならない。
  • トラブルシューティングやメンテナンスを楽にするために、テストメソッドは短くする。
  • エラー時により良いメッセージを表示させるために、最も適したアサーションを使うようにする。
  • アサーションとその逆(refute_)は、MiniTest::Assertionsモジュールでドキュメントされている。

6-2. MiniTestスペックテストに慣れよう

  • テストクラスの作成にはdescribeメソッド、テスティングの定義にはitメソッドを使う。
  • アサーションメソッドも使えるが、スペックテストでは一般にObjectクラスに注入されたエクスペクテーションメソッドを使う。
  • エクスペクテーションは、MiniTest::Expectationsモジュールでドキュメントされている。

6-3. モックオブジェクトで決定論をシミュレートしよう

  • 外の世界の非決定性からテストを切り離したいときにはモックを使うとよい。
  • モックテストなどのメソッドを交換するテストは、本番でエラーを起こす未テストコードを残す危険がある。
  • テストメソッドを終える前に、必ずMiniTest::Mock#verifyを呼び出す。

6-4. 効果的なテストを追求しよう

  • コードのハッピーパスと例外パスの両方を試すためにはファズテスト、プロパティテストツールを使おう。
  • テストで実行されたからといって必ずしも正しいコードと言うわけではないため、コードカバレッジツールは間違った安心感を与える可能性がある。
  • 機能を書いているときにテストをする方があとでテストをするよりもずっと簡単だ。
  • バグの根本原因を探し始める前にそのバグのために失敗するテストを書こう。
  • できる限りテストを自動化しよう。


出典: https://www.shoeisha.co.jp/book/detail/9784798139821

Rails 6 APIモードのエラーハンドリング例

こんにちは!kossyです!





さて、今回は、Rails 6 APIモードのエラーハンドリングについて、ブログに残してみたいと思います。



環境
Ruby 2.6.3
Rails 6.0.3
MacOS Mojave



流れとしては、
・捕捉したいエラーをクラス化するerrorsモジュールの定義
・exceptionをjson化してrenderするerror_jsonモジュールの定義
・application_controller.rbで両モジュールをincludeし、class_eval内でrescue_fromを用いて捕捉したいエラークラスを定義


です。

ではコードに注釈を入れたものを晒します。


app/controllers/concerns/errors.rbの作成

module Errors
  # 捕捉したいエラーをハッシュで定義
  HTTPResponseErrors = {
    bad_request: 400,
    unauthorized: 401,
    forbidden: 403,
    not_found: 404,
    internal_server_error: 500,
  }.freeze

  # StandardErrorを継承した新たなクラスを定義
  # アプリケーションレベルの例外であれば、StandardErrorを使うべきという思想に基づいている
  class HTTPResponseError < StandardError
    # エラーコード、エラーメッセージの読み書きができるようにattrsを定義
    attr_accessor :code, :message

    def initialize(args = {})
      # StandardError内のinitializeを呼び出す
      super
      if args.is_a? Hash
        @code    = args[:code] # エラーコード
        @message = args[:message] # エラーメッセージ
      end
      self
    end

    # not_foundをNotFoundのように、_で単語として分割して、それぞれの文字の[0]を大文字にして、連結する。
    def capitalize_with_space(str, delimiter = '_')
      str.split(delimiter).map(&:capitalize).join(' ') if str.present?
    end
  end

  # class_evalメソッドでHTTPResponseErrorをまとめて定義する。
  HTTPResponseErrors.each do |code ,status|
    class_eval <<-RUBY
      class #{code.to_s.camelize} < HTTPResponseError
        def status
          HTTPResponseErrors[:#{code}]
        end

        def code
          @code || "#{code}" # 例: 400, 401等の数値が入る
        end

        def message
          @message || ("#{status} " + capitalize_with_space("#{code}")) # 例: "400 Bad Request" のようにエラーコードに応じた文字列が入る
        end
      end
    RUBY
  end

end

exceptionをrenderするメソッド等を定義するapp/controllers/concerns/error_json.rbを定義

次にerror_jsonモジュールを定義します。

module ErrorJson
  extend ActiveSupport::Concern

  def parse_error_for_json(exception)
    {
      type: 'error',
      status: Rack::Utils.status_code(exception.status), # https://www.rubydoc.info/gems/rack/Rack/Utils#status_code-class_method
      code: exception.code,
      message: exception.message,
    }.to_json
  end

  def render_error(exception)
    render json: parse_error_for_json(exception), status: exception.status
  end
end


Rack::Utils.status_codeメソッドについてはコード内のリンクを参考にしてみてください。

あとは上記2モジュールをapplication_controller.rbに定義して、rescue_fromを定義するだけです。

class ApplicationController < ActionController::API
  # 外部ファイルのConsernのErrorsとErrorActionsをinclude
  include Errors
  include ErrorActions

  # class_evalで400系と500エラーをrescue_fromする
  HTTPResponseErrors.each do |code, status|
    class_eval <<-RUBY
      rescue_from(#{code.to_s.camelize}) {|e| render_error e } # 400 bad_requestの場合 rescue_from(BadRequest) { |e| render_error(e) } のように定義される。
    RUBY
  end
end

rescue_fromでエラーハンドリングを行う場合、withオプションを用いて定義する方法が一般的かも知れませんが、ブロックを渡すやり方もできます。

参考: https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html


以上の定義を行うと、controller内で

  raise BadRequest, code: 'invalid_parameter_error' if params[:status_str].is_a?(String)

のように、raiseで例外を起こすと、
application_controller.rbでrescue_fromで予め捕捉したいエラーとして定義されていたBadRequestが捕捉されます。

捕捉された後、render_errorの引数にexceptionが渡され、エラー内容がjsonとして返却されます。

実際の返り値は、

{"type":"error","status":400,"code":"invalid_parameter_error","message":"400 Bad Request"}

のようになります。

これで、controller内でerrors.rbで定義した例外クラス達を使って柔軟にエラーハンドリングを行えるようになります。



参考にさせていただいたサイト
rubyの例外についてまとめてみた - Qiita
【Rails5】rescue_fromによる例外処理:アプリ固有のエラーハンドリングとエラーページ表示 - Qiita

Effective Ruby 第5章まとめ

こんにちは!kossyです!




さて、今回はEffective Rubyの第5章の覚えておくべき事項を
ブログにまとめてみたいと思います。

前回までの章をまとめたものはこちら
Effective Ruby 第1章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第2章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第3章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第4章まとめ - その辺にいるWebエンジニアの備忘録


第5章 メタプログラミング

5-1. モジュール、クラスフックを使いこなそう

  • すべてのフックメソッドは、特異メソッドとして定義してなければならない。
  • メソッドが追加、削除、定義解除されるときに呼び出されるフックは、メソッド名しか受け取らず、変更が行われるクラスは与えられない。クラス名が知りたい場合には、selfの値を使う。
  • singleton_method_addedを定義すると、自分自身の呼び出しが発生する。
  • extend_object、append_features、prepend_featuresメソッドをオーバーライドしてはならない。代わりに、extended、included、prependedフックを使おう。

5-2. クラスフックからはsuperを呼び出そう

  • クラスフックの中にはsuper呼び出しを入れよう。

5-3. method_missingではなくdefine_methodを使うようにしよう

  • method_missingではなくdefine_methodを使うようにしよう。
  • どうしてもmethod_missingを使わなければならないときには、respond_to_missing?を定義することを検討しよう。

5-4. evalの多様な変種間の違いを把握しよう

  • instance_evalやinstance_execで定義されるメソッドは、特異メソッドである。
  • class_eval、module_eval、class_exec、module_execメソッドのレシーバは、モジュール、クラスに限られる。これらのどれかで定義されたメソッドは、インスタンスメソッドになる。

5-5. モンキーパッチの代わりとなるものを検討しよう

  • Refinementsはもう実験的機能ではなくなったが、機能の成熟とともに変化する可能性はまだ残っている。
  • Refinementsは、それを使いたい個々のレキシカルスコープでアクティブ化しなければならない

5-6. エイリアスチェイニングで書き換えたメソッドを呼び出そう

  • エイリアスチェインをセットアップするときには、別名が一意になるようにしなければならない。
  • エイリアスチェイニングが取り消せるメソッドを提供することを検討しよう。

5-7. Procの引数の個数の違いに対応できるようにすることを検討しよう

  • 弱いProcオブジェクトとは異なり、強いProcオブジェクトは、引数の個数が間違っていると、ArgumentError例外を生成する。
  • Proc#arityメソッドを使えば、Procオブジェクトが期待する引数の数がわかる。正数なら、Procが期待する引数の数そのものを表す。負数なら、オプション引数があるということであり、その数は必須引数の個数の1の補数になっている。

5-8. モジュールのprependを使うときには慎重に考えよう

  • prependメソッドを使うと、クラス階層内でレシーバの前にモジュールを挿入できる。これは、レシーバとスーパークラスの間にモジュールを挿入するincludeとは大きく異なる。
  • included、extendedモジュールフックと同様にモジュールをprependするとprependedフックが実行される。


出典: https://www.shoeisha.co.jp/book/detail/9784798139821

Effective Ruby 第4章まとめ

こんにちは!kossyです!




さて、今回はEffective Rubyの第4章の覚えておくべき事項を
ブログにまとめてみたいと思います。

前回までの章をまとめたものはこちら
Effective Ruby 第1章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第2章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第3章まとめ - その辺にいるWebエンジニアの備忘録



第4章 例外

4-1. raiseにはただの文字列ではなくカスタム例外を渡そう

  • 例外としてraiseに文字列を渡すのは避けよう。この場合汎用のRuntimeErrorオブジェクトが使われる。そうではなく、カスタム例外クラスを作ろう。
  • カスタム例外クラスはStandardErrorを継承し、クラス名がErrorで終わるようにしよう。
  • 1つのプロジェクトのために複数の例外クラスを作るときには、まずStandardErrorを継承する基底クラスを作り、ほかの例外クラスはそのカスタム基底クラスを継承するように構成しよう。
  • initializeでエラーメッセージを設定するときには、raiseでエラーメッセージを設定すると、initializeのメッセージが上書きされてしまうことに注意しよう。

4-2. できる限りもっとも対象の狭い例外を処理するようにしよう

  • 修復方法がわかっている特定の例外だけrescueで捕まえよう
  • 例外を捕まえるときには、もっとも限定されたタイプのものを最初に処理しよう。例外の階層構造の上位にあるものほど、rescue節は下流に作る。
  • StandardErrorのような汎用例外クラスをrescue節で捕まえるのは避けよう。もしそうしたいと思う場合には、ほんとうに必要なものはensure節なのではないかということを考えるべきだ。
  • rescue節で例外を生成すると、新しい例外が現在の例外を押しのけ、現在のスコープを抜けて例外処理を最初からやり直す。

4-3. リソースはブロックとensureで管理しよう

  • 確保したリソースを解放するためにensure節を書こう。
  • リソース管理を抽象化するために、クラスメソッドでblockとensureパターンを使おう。
  • ensure節で変数を使うときには、その前に変数が初期化されているかどうかを確かめよう。

4-4. ensure節は最後まで実行して抜けるように作ろう

  • ensure節のなかでreturn文を明示的に使うのは避けなければならない。これが必要だと感じられる場合には、メソッド本体のロジックに何かしら問題があるはずだ。
  • 同様に、ensureのなかで直接throwを使ってはならない。throwはメソッド本体で使うべきものだ。
  • 反復処理では、ensure節のなかでnextやbreakを使ってはならない。反復処理のなかに本当にbeginブロックが必要かよく考えよう。大抵の場合、逆にbeginの中に反復処理を配置する方が正しいものだ。
  • より一般的に、ensure節のなかで制御フローを変更してはならない。制御フローの変更は、rescue節で行うべきだ。その方が、あなたの意図がはっきりと伝わる。

4-5. retryでは回数の上限を設け、頻度を変化させ、オーディットトレイルを残そう

  • 無条件のretryを使ってはならない。retryはコード内の暗黙のループとして扱うようにしよう。beginブロックの外側のスコープに境界変数を作り、上限に達するまで例外を再生成するのである。
  • retryを使うときには、オーディットトレイルを作ろう。問題のあるコードを再試行してもうまくいかないときには、最終的なエラーまでのイベントの連鎖を知りたいと思うはずだ。
  • 再試行の前にディレイを入れるときには、問題を悪化させないようにrescue節のなかで値を増やしていくことを検討しよう。

4-6. スコープから飛び出したいときにはraiseではなくthrowを使おう

  • 複雑な制御フローが必要なときには、raiseではなく、throwを使うようにしよう。throwを使うと、ボーナスとしてスタックの上位にオブジェクトを送ることができる。
  • できる限り単純な制御構造を使おう。catchとthrowの組み合わせは、単純にreturnでスコープから抜け出すメソッドとそれに対する呼び出しで置き換えられることが多い


出典: https://www.shoeisha.co.jp/book/detail/9784798139821

独自Docker Registryがなぜ必要なのか?

こんにちは!kossyです!




さて、今回はコンテナイメージを保存する独自Docker Registryがなぜ必要なのかについて、
ブログに残してみたいと思います。


Docker Hub、Harbor等と行ったパブリックレジストリサービスの利用を避けざるを得ないシチュエーションがある

Docker Hubはイメージのパブリックレジストリサービスとして最も有名なサービスですが、ユースケースによってはいくつかの問題があります。

レイテンシーの問題
Docker Hubの場合、イメージが保存されているサーバーが海外のデータセンターのため、
日本から利用する場合レイテンシの問題が発生する可能性があります。

・セキュリティの問題
セキュリティポリシー的にパブリックな空間にイメージを配置することができない場合や、
オンプレ利用でインターネットに接続されていないレジストリが求められる場合、やはり問題になる可能性があります。

そこで、独自のDocker Registryやプライベートレジストリサービスを利用する必要があります。


主なプライペートレジストリを提供するサービス

クラウド大手3社は一様にプライベートレジストリサービスを提供しています。ご自身のプロジェクトで使われている会社のサービスを用いればいいと思います。

AWS

GCP

・Azure




勉強になりました。

よく使うDockerfileのコマンドまとめ(その1)

こんにちは!kossyです!





さて、今回はDockerfileでよく使うコマンドをまとめてみたいと思います。




FROM

https://docs.docker.jp/engine/reference/builder.html#id43

ビルドするイメージのベースイメージを指定します。取得するイメージはDocker Hubのパブリックレジストリから取得されます。

FROM ruby:2.6
FROM node

のように指定することでイメージを指定できます。
ruby:2.6のように:の後の数字はタグと呼ばれるもので、特に指定しない場合はlatestタグが付されたイメージが取得されます。

RUN

https://docs.docker.jp/engine/reference/builder.html#id45

イメージをビルドする際、コンテナで実行するコマンドを定義するものです。

FROM ruby:2.6

RUN mkdir /myapp

RUNを記述した後に、linuxコマンド等を割り当てることで、コンテナ内で実行されるようになります。

COPY

https://docs.docker.jp/engine/reference/builder.html#copy

ホスト側からコンテナ側にファイルやディレクトリをコピーしたい時に使います。

FROM ruby:2.6

RUN mkdir /myapp

COPY Gemfile /myapp/Gemfile

srcにはワイルドカードも指定することできます。

FROM ruby:2.6

RUN mkdir /myapp

COPY Gem* /myapp

Gem*はGemから始まる名前が付けられたファイル全てを追加するのを想定しています。
Railsの場合だとGemfileとGemfile.lockが追加されると思います。


ADD

https://docs.docker.jp/engine/reference/builder.html#add

COPYの機能に加えて、アーカイブの自動展開やURLを指定してファイル・ディレクトリをコンテナに追加。
OSのベースイメージ作成時のような特殊なケースで活用されます。

FROM alpine

# Auto unarchive
ADD add.txt.gz /tmp

# Can ADD from remote
ADD https://github.com/github/fetch/blob/master/README.md /tmp

出典: https://qiita.com/YumaInaura/items/1647e509f83462a37494

COPYとの違いは以下の点があります。
・リモートサーバーからもファイルを追加できる
・圧縮ファイルが自動解凍される

こちらの記事によると、ADDよりもCOPYコマンドを使った方がいいとのことです。(公式もその見解らしい)



CMD

https://docs.docker.jp/engine/reference/builder.html#cmd

コンテナがフォアグラウンドで実行するコマンドを定義できます。

FROM ruby:2.6.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]

出典: https://qiita.com/kodai_0122/items/795438d738386c2c1966

Dockerfile内ではCMDコマンドは1つしか記述できません。
2つ目のCMDコマンドを記述した場合、1つ目のCMDコマンドは無視され、2つ目のものしか実行されないので注意してください。


ENTRYPOINT

https://docs.docker.jp/engine/reference/builder.html#entrypoint

コンテナを実行可能ファイルとして使用する際に定義するコマンドで、
CMDとENTRYPOINTは併用可能です。

FROM ruby:2.6

ENTRYPOINT ["ruby"]
CMD [""]

この状態のDockerfileをbuildして実行すると、

docker image build -t test/ruby2.6
docker container run -it test/ruby2.6 version

のように、rubyコマンドを省略して実行することができます。


ARG

https://docs.docker.jp/engine/reference/builder.html#arg

docker image build に利用する変数を設定できます。
イメージビルド時のみ使用できる一時的な環境変数です。

Rails向けのDockerfileだと思ってください


ARG RAILS_MASTER_KEY
ENV RAILS_MASTER_KEY ${RAILS_MASTER_KEY}
docker build --build-arg RAILS_MASTER_KEY=${RAILS_MASTER_KEY} ...

上記のようにmaster.keyを環境変数として渡すことで、動的にmaster.keyを渡すことができます。

出典: https://qiita.com/hiko1129/items/c0a27ce0c46fcaeaac7b


ENV

https://docs.docker.jp/engine/reference/builder.html#env

コンテナ内に環境変数を定義するために用いられます。

ARG RAILS_MASTER_KEY
ENV RAILS_MASTER_KEY ${RAILS_MASTER_KEY}

ENVを用いて設定された環境変数は、そのイメージから実行されたコンテナであれば維持され、
コンテナ内部で使用することができます。

上記の例では、コンテナ内でmaster.keyを参照できるようにENVで環境変数化しています。





参考にさせていただいた記事・書籍
https://docs.docker.jp/engine/reference/builder.html
https://qiita.com/YumaInaura/items/1647e509f83462a37494
https://qiita.com/momotaro98/items/bf34eef176cc2bdb6892
https://qiita.com/kodai_0122/items/795438d738386c2c1966
https://qiita.com/nacika_ins/items/cf8ceb20711bd077f770#env%E3%81%A8%E3%81%AE%E4%BD%BF%E3%81%84%E5%88%86%E3%81%91

RailsでDBにindexを貼る際のis too long the limit is 64 charactersの対処法

こんにちは!kossyです!




さて、今回はRailsでDBにindexを貼る際のis too long the limit is 64 charactersの対処法について、
ブログに残してみたいと思います。




環境
Ruby 2.6.3
Rails 6.0.3
MacOS Mojave



エラー詳細

まずエラーメッセージを記載します。

ArgumentError: Index name ‘index_user_joined_recture_subjects_on_user_next_recuture_facilities’ on table ‘user_joined_recture_subjects’ is too long; the limit is 64 characters

64文字以上のindex_nameを設定した場合、このエラーが発生します。

長いテーブル名 + 長いカラム名 の組み合わせになってしまうと、ハマってしまいますね、、、

次項で回避策について記載します。



回避するには

以下のように記述すれば回避できます。

add_index :user_joined_recture_subjects, :user_next_recuture_facilities, name: 'index_user_joined_recture_subjects_on_next_recture_faililities'

add_indexメソッドのnameオプションを用いることで、自由にindex_nameを定義できます。



勉強になりました。

Effective Ruby 第3章まとめ

こんにちは!kossyです!




さて、今回はEffective Rubyの第3章の覚えておくべき事項を
ブログにまとめてみたいと思います。

前回までの章をまとめたものはこちら
Effective Ruby 第1章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第2章まとめ - その辺にいるWebエンジニアの備忘録

第3章 コレクション

3-1. コレクションを書き換える前に引数として渡すコレクションのコピーを作っておこう

  • Rubyのメソッド引数は値渡しではなく参照渡しである。ただし、この規則には、Fixnumオブジェクトという顕著な例外がある
  • 引数として渡されたコレクションは、書き換える前にコピーを作ろう
  • dup、cloneメソッドは、シャローコピーしか作らない
  • ほとんどのオブジェクトでは、Marshalを使えば必要なときにディープコピーを作れる

3-2. nilスカラーオブジェクトを配列に変換するには、Arrayメソッドを使おう

  • nilスカラーオブジェクトを配列に変換するには、Kernel#Arrayメソッドを使う。
  • ArrayメソッドにHashを渡してはならない。Hashは一連のネストされた配列に変換されてしまう。

3-3. 要素が含まれているかどうかの処理を効率よく行うために集合を使うことを検討しよう

  • 要素が含まれているかどうかの高速チェックではSetを使うことを検討しよう
  • Setに挿入されるオブジェクトは、ハッシュキーとしても使えなければならない
  • Setを使う前に、require('set')を実行しよう

3-4. reduceを使ってコレクションを畳み込む方法を身につけよう

  • アキュムレータの初期値は必ず使おう
  • reduceのブロックは、必ずアキュムレータを返すようにする。現在のアキュムレータを書き換えるのは問題ないが、それをブロックから返すのを忘れないようにすることだ。

3-5. ハッシュのデフォルト値を利用することを検討しよう

  • Hashのデフォルト値を使うことを検討しよう
  • ハッシュがキーを含んでいるかどうかをチェックする時には、has_key?またはその別名を使おう。つまり、存在しないキーにアクセスしたらnilが返されることを前提としてコードを書いてはならない
  • デフォルト値を使うよりもHash#fetchを使った方が安全な場合がある

3-6. コレクションクラスからの継承よりも委譲を使うようにしよう

  • コレクションクラスからの継承よりも委譲を使うようにしよう
  • 委譲のターゲットのコピーを作るinitialize_copyメソッドを忘れずに書こう
  • 委譲ターゲットに対応するメッセージを送ってからsuperを呼び出すという形でfreeze、taint、untaintメソッドを書こう


出典: https://www.shoeisha.co.jp/book/detail/9784798139821

Dockerの開発環境でbinding.pryを使う

こんにちは!kossyです!




さて、今回はDockerでデバッグツールであるpryを使う方法についてブログに残してみたいと思います。





環境
Docker 19.03.12
docker-compose 1.26.2
Docker Desktop for Mac 2.3.0.4

Ruby 2.6.3
Rails 6.0.3



手順

予めDockerで開発環境が立ち上がっていて、pryを導入済みの想定で話を進めます。

ttyとstdin_openをtrueにする


docker-compose.ymlに以下の記述があるのが第一条件です。

version: '3'
services:
  web:
  # 省略
    tty: true <=
    stdin_open: true <=

tty: true はコンテナ起動後にコンテナがすぐに終了してしまうのを防ぐために記述してます。
stdin_open: true は、コンテナの標準入力をオープンしたままにすることができます。

上記の記述がdocker-compose.ymlファイル内になければ、追加するようにしてください。

docker attachコマンドでコンテナにアタッチする。

docker attachコマンドを使ってアタッチした状態で、binding.pry記述箇所を呼び出すと、
いつものpryの画面になってくれます。


// 実行中のコンテナIDを調べる

$ docker ps

// 調べたIDにアタッチする

$ docker attach CONTAINER_ID

アタッチしたコンテナから抜ける


ctrl + P または ctrl + Q でアタッチしたコンテナから抜けられます。




勉強になりました。



参考にさせていただいたサイト
docker上でbinding.pryを実行する - Qiita
Dockerでbinding.pryをする - haayaaa’s diary
【Rails】Docker環境下でbinding.pryを使えないとき確認すべきポイント4つ - Qiita

AngularのAoTコンパイルについて

こんにちは!kossyです!



さて、今回はAngularのbuild時に用いることができる、AoTコンパイルについて、ブログに残してみたいと思います。




AoTコンパイルとは?

まず、用語について調べてみました。

事前コンパイラ (Ahead-Of-Timeコンパイラ、AOTコンパイラ)とは、アプリケーション実行前に事前にコンパイルするコンパイラのこと。
主に、Javaバイトコード、.NET CIL、IBM System/38 や System i の "Technology Independent Machine Interface" コードといった
システムから独立した(プロセス仮想機械)のバイナリである中間言語コンパイルで使われる言葉である。
対義語は、実行時コンパイラ(Just-In-TimeコンパイラJITコンパイラ)。

出典: https://ja.wikipedia.org/wiki/%E4%BA%8B%E5%89%8D%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9

一般的な用語の意味についてなんとなく理解できました。

次に、AngularにおいてAoTコンパイルを使用する意図について、
公式Docに記載がありました。

AOTを使用する理由は次のとおりです。

より速いレンダリング AOT では、ブラウザはコンパイル済みのアプリケーションをダウンロードします。 ブラウザは実行可能コードをロードするので、最初にアプリケーションをコンパイルするのを待たずにアプリケーションをすぐにレンダリングできます。

より少ない非同期リクエスコンパイラは外部の HTML テンプレートと CSS スタイルシートをアプリケーションの JavaScript 内に インライン化し 、 それらのソースファイルに対する別々の ajax リクエストを排除します。

より小さい Angular フレームワークのダウンロードサイズ アプリがすでにコンパイルされている場合は、Angular コンパイラをダウンロードする必要はありません。 コンパイラは Angular 自体の約半分なので、これを省略するとアプリケーションのペイロードが大幅に減少します。

テンプレートエラーを早期に検出する AOT コンパイラは、ユーザーが目にする前にビルドステップ中にテンプレートバインディングエラーを検出して 報告します。

より良いセキュリティ AOT は、HTML テンプレートとコンポーネントがクライアントに提供されるずっと前から JavaScript ファイルにコンパイルします。 読み取るテンプレートがなく、危険なクライアントサイドの HTML または JavaScript の評価もないため、 インジェクション攻撃の機会が少なくなります。

出典: https://angular.jp/guide/aot-compiler

AoTコンパイルを用いることで、ファイルサイズの圧縮によるパフォーマンスの向上、
アプリケーションの高速化を実現できるようです。

Angular10でのaotコンパイルの実行方法

Angular 10を使用している場合、
aotコンパイルはデフォルトで有効になっています。

{
  "projects": {
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/sfa-angular",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": true, <=




勉強になりました。