Rails
active_model_serializers

RailsのAMSとforemanについて学ぶ_100DaysOfCodeチャレンジ15日目(Day_15:#100DaysOfCode)

はじめに

この記事はTwitterで人気のハッシュタグ#100DaysOfCodeをつけて、
100日間プログラミング学習を続けるチャレンジに挑戦した15日目の記録です。

動作環境

  • ruby 2.4.1
  • Rails 5.0.1

現在学習している内容のリポジトリ

https://github.com/yuta-ushijima/notebook-api-on-rails

本日学んだこと

  • Foremanについて
  • リクエストを受け付けるJSONのフォーマットを指定するメソッドの実装

Foremanとは?

rails servernpm run devのような実行するコマンドが複数ある時に、このgemを入れることで
foreman startコマンド一発で同時に実行できる便利なgem。

公式リポジトリ

https://github.com/ddollar/foreman

製作者のページ

http://blog.daviddollar.org/2011/05/06/introducing-foreman.html

# Gemfile
gem 'foreman'

railsのルートディレクトリにforemanを起動させるために必要なファイルであるProcfileを作成しましょう。

作成したProcfileに、webサーバーを起動するコマンドを追記します。

# Procfile
web: PORT=3000 bundle exec rails s

この内容の意味としては、「webサーバーとして、rails serverを使ってね。ポート番号は3000を使うように。」といったところですね。

Foremanではデフォルトのポートが5000になっているので、そのほかのポートを指定したい場合は別途指定が必要なのです。

あとは、foremanコマンドを使うために、システムにもforemanのgemをインストールしましょう。

gem install foreman

TIPS

bundle exec foreman startのように実行すると、先に記述したポート指定箇所で以下のようなエラーが発生します。

Yutas-MacBook-Air:notebook-api-on-rails ushijimayuuta$ bundle exec foreman start
11:21:42 web.1  | started with pid 7745
11:21:42 web.1  | /Users/ushijimayuuta/workspace/Rails/notebook-api-on-rails/vender/bundle/ruby/2.4.0/gems/foreman-0.64.0/bin/foreman-runner: line 41: exec: PORT=3000: not found
11:21:42 web.1  | exited with code 127
11:21:42 system | sending SIGTERM to all processes

「bundle execで実行したけど、PORT=3000なんてものはないよ」と怒られているわけですね。

これを解消するために、-pオプションを使ってProcfileを以下のように書き換えます。

# Procfile
web: bundle exec rails  s -p 3000

これでエラーが出ずにforemanを実行することができました。
(「だったら、最初から上記の記述でいいんじゃね?」というツッコミは、なしでお願いします...笑)

ちなみに、gemがシステムのどこにインストールされたか知りたい時は、以下のコマンドを使うと確認できます。

gem environment

上記のコマンドを実行すると、以下のような情報が返ってきます。GEM PATHという項目がありますので、そこが該当箇所ですね。

RubyGems Environment:
  - RUBYGEMS VERSION: 2.6.11
  - RUBY VERSION: 2.4.1 (2017-03-22 patchlevel 111) [x86_64-darwin17]
  - INSTALLATION DIRECTORY: /Users/ushijimayuuta/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0
  - USER INSTALLATION DIRECTORY: /Users/ushijimayuuta/.gem/ruby/2.4.0
  - RUBY EXECUTABLE: /Users/ushijimayuuta/.rbenv/versions/2.4.1/bin/ruby
  - EXECUTABLE DIRECTORY: /Users/ushijimayuuta/.rbenv/versions/2.4.1/bin
  - SPEC CACHE DIRECTORY: /Users/ushijimayuuta/.gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /Users/ushijimayuuta/.rbenv/versions/2.4.1/etc
  - RUBYGEMS PLATFORMS:
    - ruby
    - x86_64-darwin-17
  - GEM PATHS:
     - /Users/ushijimayuuta/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0
     - /Users/ushijimayuuta/.gem/ruby/2.4.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /Users/ushijimayuuta/.rbenv/versions/2.4.1/bin
     - /usr/local/Cellar/rbenv/1.1.1/libexec
     - /Users/ushijimayuuta/.rbenv/shims
     - /Users/ushijimayuuta/.rbenv/bin
     - /usr/local/bin
     - /usr/bin
     - /bin
     - /usr/sbin
     - /sbin
     - /sbin

リクエストを受け付けるJSONのフォーマットを指定するメソッドの実装

APIを作成する時に、どのようなリクエストなら受け付けるかを指定できると、よりセキュリティを高めることができます。

今回はapplication_controller.rbに受け付けるJSONのフォーマットを制御するensure_json_requestメソッドをの学習しました。

# application_controller.rb

class ApplicationController < ActionController::API
  before_action :ensure_json_request

  def ensure_json_request
    return if request.headers["Accept"] =~ /vnd\.api\+json/
    render :head, status: 406
  end
end

メソッドの中身を説明しておきましょう。

before_actionにより、APIの各アクションが実行される前に、まずこのensure_json_requestが実行されるようになります。

中身の説明としては、まずensure_json_requestが呼ばれると、1行目による条件分岐が走りますね。

request.headerにより、リクエストヘッダーの"Accept"を取得し、=~で正規表現を使って右辺である/vnd\.api\+json/と比較。

それがtrueであればreturnされます。

そうじゃない場合は、ステータスコードの406(Not acceptable)を返すという処理ですね。

これによってAcceptにapplication/vnd.api+json、つまりJSONのフォーマットの一つであるJSON API以外が指定された場合は、リクエストを受け付けなくなります。

 ## まとめ

Active_Model_SerializerでMediaTypeを使うことで、リクエストのレスポンス形式を指定できるということですね。

参考リンク

https://wa3.i-3-i.info/word15786.html