concernとは
app/concerns
というディレクトリが存在する。concerns
は
・複数のコントローラー(モデル)から利用される処理を共通化する目的
・ある特定のまとまった処理を切り出して見通しをよくする目的
上記の目的で使われることが多い。
Concernの書き方
まずはconcern
のファイルを記入し、その後コントローラーにてinclude
で表記する。
module MyConcern
extend ActiveSupport::Concern
# Scope や Callbackなどの処理を実装する
included do
scope :without_deleted, lambda{ where(deleted_at: nil) }
end
module ClassMethods
def foo
puts 'foo'
end
end
def bar
puts 'bar'
end
end
class ApplicationController < ActionController
include MyConcern
処理
.
.
end
エラーレスポンスを記入
module Api::ExceptionHandler
extend ActiveSupport::Concern
included do
rescue_from StandardError, with: :render_500
rescue_from ActiveRecord::RecordNotFound, with: :render_404
end
private
def render_400(exception = nil, messages = nil)
render_error(400, 'Bad Request', exception&.message, *messages)
end
def render_404(exception = nil, messages = nil)
render_error(404, 'Record Not Found', exception&.message, *messages)
end
def render_500(exception = nil, messages = nil)
render_error(500, 'Internal Server Error', exception&.message, *messages)
end
def render_error(code, message, *error_messages)
response = {
message: message,
errors: error_messages.compact
}
render json: response, status: code
end
end
・rescue_from
rescue_from
は、特定の種類または複数の種類の例外を1つのコントローラ全体およびそのサブクラスで扱えるようにするもの。
▶︎rescueとrescue_from
・exception
例外オブジェクトを生成して返すメソッド。
e = Exception.new("some message")
p e # => #<Exception: some message>
p e.message # => "some message"
・exception&.message
ぼっち演算子。レシーバーがnil
のときだけは、メソッドが呼び出されないでnil
を返す。
▶︎Ruby ぼっち演算子について
・*messages
メソッドの引数にアスタリスクがある。アスタリスク1つなら可変長引数、アスタリスク2つならオプション引数という。
可変長引数(アスタリスクが1つ)
*
をつければ引数を配列に指定できる。
メソッドには1つの引数の定義で、複数の引数を設定でき、配列として結果を返す。ただしこの可変長引数は1メソッドにつき、1つだけしか指定できない。
*
と記述することで受け取った引数を無視するようにも使用できる。
#複数の引数を配列にする
def array(*a)
p a
end
> array(1,2)
=> [1, 2]
> array(1, 2, 3)
=> [1, 2, 3]
オプション引数(アスタリスクが2つ)
**
をつければ引数を、ハッシュに指定できる。
メソッドには一つの引数の定義で、複数の引数を設定でき、ハッシュとして結果を返す。
#複数の引数をハッシュにする
def array(**a)
p a
end
> array(b: 1, c: 2)
=> {:b=>1, :c=>2}
> array(b: 1, c: 2, d: 3)
=> {:b=>1, :c=>2, :d=>3}
・compact
compact
は自身からnil
を取り除いた配列を生成して返す。
ary = [1, nil, 2, nil, 3, nil]
p ary.compact #=> [1, 2, 3]
p ary #=> [1, nil, 2, nil, 3, nil]
ary.compact!
p ary #=> [1, 2, 3]
p ary.compact! #=> nil
▶︎compact
rspec
RSpec.describe 'Api::ExceptionHandler', type: :request do
let!(:user) { create(:user) }
describe 'render 500' do
it 'returns errors in json format' do
allow(Article).to receive(:all).and_raise(StandardError)
get api_v1_articles_path, headers: { CONTENT_TYPE: 'application/json', ACCEPT: 'application/json' }
expect(body['message']).to eq('Internal Server Error')
expect(body['errors'].size).to eq(1)
expect(response).to have_http_status(500)
end
end
describe 'render 404' do
let(:id) { 1 }
it 'returns errors in json format' do
get api_v1_article_path(id), headers: { CONTENT_TYPE: 'application/json', ACCEPT: 'application/json' }
expect(body['message']).to eq('Record Not Found')
expect(body['errors']).to eq(["Couldn't find Article with 'id'=#{id}"])
expect(response).to have_http_status(404)
end
end
end
▶︎使えるRSpec入門・その3「ゼロからわかるモック(mock)を使ったテストの書き方」
・allow(Article).to receive(:all)
allow(モックオブジェクト).to receive(メソッド名)
の形で使われる。英語の意味からも分かるように、allow A to receive B
で、「A が B を受け取ることを許可する」の意味になる。
つまり上記は、Articleの全てを受け取ることを許可する、と言う意味になる。