はじめに
rails-APIでもcurrent_userを使えるようにするために、ログイン時/新規登録時のレスポンスにaccess_token
を付与しましょう。
ApiKeyモデル作成
> rails g model ApiKey user:references access_token:string expires_at:datetime
マイグレーションファイル確認
NOT NULL制約や、t.index ["access_token"], unique: true
の追記をしましょう。
class CreateApiKeys < ActiveRecord::Migration[6.0]
def change
create_table :api_keys do |t|
t.references :user, null: false, foreign_key: true
t.string :access_token, null: false
t.datetime :expires_at
t.timestamps
t.index ["access_token"], unique: true
end
end
end
ApiKeyモデルに追記
作成されたapi_key.rb
に、必要な記述を追記します。
class ApiKey < ApplicationRecord
DEFAULT_EXPIRES_WEEK = 1.week
belongs_to :user
validates :access_token, uniqueness: true
scope :active, -> { where('expires_at >= ?', Time.current) }
def initialize(attributes = {})
super
self.access_token = SecureRandom.uuid
self.expires_at = DEFAULT_EXPIRES_WEEK.after
end
end
DEFAULT_EXPIRES_WEEK = 1.week
1.weekを定数にしています。scope :active, -> { where('expires_at >= ?', Time.current) }
こちらはscopeですが、SQLインジェクションを防ぐ書き方の1種で、プレースホルダーを使った書き方です。 ?はプレースホルダーと呼ばれ、第二引数で指定した値が置き換えられます。 下の場合は、Time.currentの部分が?に置き換えられます。
scope :active, -> { where('expires_at >= ?', Time.current) }
# 上のコードは下記のコードと同じ
scope :active, -> { where('expires_at >= Time.current') }
下記ではinitializeを設定しています。インスタンスが生成された際に呼び出されるメソッドです。
def initialize(attributes = {})
super
self.access_token = SecureRandom.uuid
self.expires_at = DEFAULT_EXPIRES_WEEK.after
end
ActiveModelのルールとして、initialize時に何か処理を行う際にはsuperを呼び出して、attributesのhash値を渡してます。
initializeメソッドでattributesにハッシュを渡すときは、superを呼ぶこと。とおぼえておくと良いでしょう。
Userモデル追記
has_many :articles
has_many :comments
has_many :social_profiles
has_many :api_keys # 追記
validates :name, presence: true
validates :email, presence: true, uniqueness: true
def activate_api_key! # 追記
return api_keys.active.first if api_keys.active.exists?
api_keys.create
end
end
active_api_key!
ユーザーが既にvalidなApiKeyを持っている場合はそのApiKeyを使用するという処理をするメソッドです。 そうでなければ、新しいApiKeyを作成します。
authenticationsコントローラー
ログインのタイミングでApiKey
を作成する処理を追記します。 作成したApiKey
のaccess_token
をHeader
に含めましょう。
raise ActiveRecord::RecordNotFound unless @user
json_string = UserSerializer.new(@user).serialized_json
api_key = @user.activate_api_key! # 追記
response.headers['AccessToken'] = api_key.access_token # 追記
render json: json_string
end
end
registrationsコントローラー
新規登録のタイミングでApiKey
を作成する処理を同様に追記します。
if @user.save
json_string = UserSerializer.new(@user).serialized_json
api_key = @user.activate_api_key! #追記
response.headers['AccessToken'] = api_key.access_token #追記
render json: json_string
else
render_400(nil, @user.errors.full_messages)
参考
ActiveModel::Model
Active Model Basic Model Allows implementing models similar to ActiveRecord::Base.
コメント