GarageとDeviseを使ってみる

# 目的

クックパッド社のgarageを使ってAPIサーバを作る。
そして、アカウント管理には最近調べたDeviseを使う。

OAuthには、doorkeeperを使うため、garage-doorkeeperを採用します。

これで本当に正しいのか十分に検証できていないので、ツッコミ等ありましたが、どしどしくださいm(_ _)m

[ソースコード](https://github.com/kehra/garage_devise_sample)

# 環境

Ruby: 2.2.1
Rails: 4.2.3
devise: 3.5.1
devise_invitable: 1.5.2
garage: 1.5.1
garage-doorkeeper: 2.0.0

# インストール
## devise

[こちらを参照してください](http://qiita.com/kehra/items/6fab6ef0661824d0fa0d)

## devise_invitable

[こちらを参照してください](http://qiita.com/kehra/items/0cb6cc2575c8cadef6cc)

## garage

doorkeeperのインストールをします。

```
$ bundle exec rails g doorkeeper:install
      create  config/initializers/doorkeeper.rb
      create  config/locales/doorkeeper.en.yml
       route  use_doorkeeper

$ bundle exec rails g doorkeeper:migration
```

### 初期設定
#### config/initializers/garage.rb

garageの設定ファイルを作ります。
※installでtemplateを作って欲しいかも･･･。

`config/initializers/doorkeeper.rb`という設定ファイルも作られていますが、
こちらのファイルで一括管理するみたい。

```
Garage.configure {}

Garage::TokenScope.configure do
  # とりあえず、usersにアクセスできるように権限設定
  register :public, desc: 'accessing publicly available data' do
    access :read, User
    access :write, User
  end
end

Garage.configuration.strategy = Garage::Strategy::Doorkeeper

Doorkeeper.configure do
  orm :active_record
  default_scopes :public
  optional_scopes(*Garage::TokenScope.optional_scopes)

  resource_owner_authenticator do
    # devise用の設定
    current_user || redirect_to(new_user_session_path)
  end

  resource_owner_from_credentials do |routes|
    # devise用の設定
    request.params[:user] = { email: request.params[:username], password: request.params[:password] }
    request.env['devise.allow_params_authentication'] = true
    request.env['warden'].authenticate!(scope: :user)
  end
end

# トークンを発行するのに、パスワード認証を許可する
Doorkeeper.configuration.token_grant_types << "password"
```

## 使い方
### コントローラー
#### application_controller.rb

以下の記載を追記します。

```
# csrf対策を外す
skip_before_action :verify_authenticity_token

include Garage::ControllerHelper

# 更新等を行うにあたり、該当リソースのオーナーかを判別
# "user_signed_in?"はdeviseのメソッドです
def current_resource_owner
  @current_resource_owner ||= User.find(resource_owner_id) if user_signed_in?
end
```

#### 各リソースのコントローラー

ここでは、Userモデルを例にあげます。

```
class UsersController < ApplicationController
  include Garage::RestfulActions

  # index
  # @resources/@resource は変えられない決まり事
  def require_resources
    @resources = User.all
  end

  # create
  # def create_resource
  #   @resources.create(user_params)
  # end

  # show
  def require_resource
    @resource = User.find(params[:id])
  end

  # edit
  def update_resource
    @resource.update_attributes!(user_params)
  end

  # delete
  # def destroy_resource
  #   @resource.destroy!
  # end

  def user_params
    params.permit(:email)
  end

  # view option for index action
  def respond_with_resources_options
    {  }
  end

  # view option for show action
  def respond_with_resource_options
    {  }
  end
end
```

### モデル

ここでは、Usersモデルを例にあげます。

```
class User < ActiveRecord::Base
  # APIに使うためのinclude
  include Garage::Representer
  # 権限チェックに使うためのinclude
  include Garage::Authorizable

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :invitable, :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  # APIで使うプロパティ
  property :id
  property :email

  # index/create用権限設定
  def self.build_permissions(perms, other, target)
    perms.permits! :read
  end

  # show/update/delete用権限設定
  def build_permissions(perms, other)
    perms.permits! :read
    perms.permits! :write if self == other
  end
end
```

### doorkeeperの設定
#### OAuthを使うための設定

以下のURLにアクセスして、`$APPLICTION_ID`と`$APPLICATION_SECRET`を払い出す。

```
http://localhost:3000/oauth/applications
```

#### トークンの発行

以下のリクエストを送ると、アクセストークンが返却される

```
curl -u "$APPLICTION_ID:$APPLICATION_SECRET" -XPOST http://localhost:3000/oauth/token -d 'grant_type=password&username=【登録したメールアドレス】&password=【パスワード】'
curl -XGET -H "Authorization: Bearer $ACCESS_TOKEN" http://localhost:3000/api/users
```

# 参照ページ

https://github.com/cookpad/garage
https://github.com/cookpad/garage/blob/master/doc/restful_actions.md
https://github.com/taiki45/garage-example
http://qiita.com/arakaji/items/39818b207f9c1c3c4058
http://qiita.com/217/items/389de32ac340de81d532
https://github.com/gitlabhq/gitlabhq/issues/9073