RailsでFacebookページにいいねしないと見れないコンテンツを作る方法

Ruby on Railsを使ってFacebook認証+ページにいいねしないとコンテンツを見ることが出来ないサービスを作ったので、実装方法を書いておきます。広告用にアプリを作りたい！という時とかに役立つ機能だと思います。
実装例：[「同じ誕生日の有名人は誰？」](http://same-birthday-2zigexn.sqale.jp)
このWebアプリと同じ実装をしていきます。

## 環境

* Ruby (2.1.1p76)
* Rails (4.1.1)
* devise (3.2.4)
* omniauth-facebook (1.6.0)
* koala (1.8.0)

## Gemのインストール

Gemfileに以下のコードを追加して`bundle install`します。

```ruby
# Gemfile

gem 'devise'
gem 'omniauth-facebook'
gem 'koala'
```

# ユーザ認証機能の実装

ユーザ認証にdeviseとomniauth-facebookを使っていきます。

## Deviseの導入

```bash
# config/inistializer/devise.rbを(設定ファイル)作成
$ rails g devise:install

# deviseの認証用のviewの作成
$ bundle exec rails g devise:views
　
# 認証用のモデルを作成(今回はUserにした)
$ rails g devise user

```

## Deviseのmigration設定

Facebookの認証に必要なカラムをUserモデルに追加していきます。

```bash
# db/migrate/*_devise_create_users.rb

class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|

      ## この3つを追加する！！
      t.integer :uid, null: false, limit: 8
      t.string :provider
      t.string :token

      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      t.timestamps
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true

  end
end
```

追加し終わったらmigrateしましょう

```bash
$ bundle exec rake db:migrate
```

## deviseのモデルを編集
Userモデルにomniauthを使用することを記入します。

```ruby
# app/models/user.rb

class User < ActiveRecord::Base

  devise :database_authenticatable, :omniauthable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end
```

## Facebookアプリの登録

1. [こちら](http://princesswell.rocketserver.jp/web-cheat-sheet/facebook-developers-application/)のサイトを見て、開発者登録、アプリの登録を済ませる

2. [Settings]から[Add Platform]をクリックし、[Website]を選択
3. [App Details]で各種設定をすませる

※ SiteURLは開発環境なら http://localhost:3000/ とかとりあえずいれといて下さい。

## API Keyの設定

取得したApp ID, App Secretをdevise.rbに記入していきます。

```ruby
# config/initializers/devise.rb

Devise.setup do |config|
  # ...
 
  # API key
  config.omniauth :facebook, "App ID", "App Secret",
    scope: 'basic_info, email, user_likes, public_profile'

end
```

## OAuth の callback 用ルーティングを追加

config/routes.rb に callback 用のルーティングを追加します。

```ruby
# config/routes.rb

devise_for :users, :controllers => {
  :omniauth_callbacks => "users/omniauth_callbacks" 
}
```

## Users::OmniauthCallbacksController を作成

omniauth_callbacks_controller.rbというファイルをapp/controllers/users/に作成し、以下の内容を記述します。

```ruby
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    # You need to implement the method below in your model (e.g. app/models/user.rb)
    @user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
 
    if @user.persisted?
      set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
      sign_in_and_redirect @user, :event => :authentication
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end

end
```

## find_for_facebook_oauthメソッドの定義

コールバックメソッドの中でfind_for_facebook_oauthというメソッドを使用するので、これを定義します。app/models/user.rbに以下の内容を追加して下さい。

```ruby
# app/models/user.rb

def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
  user = User.where(:provider => auth.provider, :uid => auth.uid).first
  unless user
    user = User.create(name:     auth.extra.raw_info.name,
                       provider: auth.provider,
                       uid:      auth.uid,
                       email:    auth.info.email,
                       password: Devise.friendly_token[0,20]
                      )
  end
  user
end
```

## ViewにOauth認証のリンクを追加
トップ画面等、Facebook認証をさせたい画面に以下のリンクを挿入します。

```
<%= link_to "Facebookでサインイン", user_omniauth_authorize_path(:facebook) %>
```
とりあえずここまででfacebook認証は実装出来たはずです。

# いいねしないと表示出来ない機能の実装
では、いいねをしないと表示出来ないコンテンツを作成していきましょう。
ここでは、例として、pages_controllerを作成し、checkアクションでいいねしているかどうかのチェック、およびにいいねをさせる。resultアクションでコンテンツを表示していきます。

## コントローラの作成

まずはコントローラを作成しましょう。

```bash
$ rails generate controller page check result
```
続いて、ログインしてるユーザのみアクセスできるように、pages_controlerに :authenticate_user!メソッドを追加

```ruby
# app/controllers/pages_controller.rb

class PagesController < ApplicationController
  before_filter :authenticate_user!

  def result
  end

  def check
  end

end
```

ルーティング設定もしておきます。

```ruby
# config/routes.rb

match "/result", to: "pages#result", via: "get"
match "/check", to: "pages#check", via: "get"
```


## checkを通らずにresultにいけないようにする

checkを通らずにresultを表示出来ないようにしていきます。まずは画面遷移をsessionに記録するようにします。

```ruby
# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base

  protect_from_forgery with: :null_session
  after_filter :store_location

  def store_location
    session[:previous_url] = request.fullpath 
  end
end
```

次に、pages_controllerのresultメソッドに以下の内容を記入します

```ruby
# app/controllers/pages_controller.rb

class PagesController < ApplicationController
  before_filter :authenticate_user!

  def result
    if session[:previous_url] != check_path && session[:previous_url] != result_path
      redirect_to check_path
    end
  end

#...
end
```

## ページにイイネしているかのチェック！
koalaを使って、特定のfacebookページにイイネしているかどうかのチェックをしていきます。
まずはuserモデルにユーザのfacebook graphを取得するメソッドを追加します。

```ruby
# app/models/user.rb

class User < ActiveRecord::Base
  # ...

  def graph
    Koala::Facebook::API.new(self.token)
  end
end
```

次にpages_controllerのcheckアクションでユーザがいいねをしていたらresultに飛ばす実装をしていきます。

```ruby
# app/controllers/pages_controller.rb

class PagesController < ApplicationController
  # ...
  def check
    client = current_user.graph
    likes = client.get_connections("me", "likes")
    likes.each do |like|
      if like["id"] == "あなたのFacebookページのID"
        redirect_to result_path
      end
    end
  end

end
```

## ビューにいいねボタンを追加

最後に、checkアクションに使うviewにいいねボタンを埋め込みましょう。

```html
<!-- app/views/pages/check.html.erb -->

<p>結果を見るには下のいいね!ボタンを押して下さい</p>
<div class="like-box"><div class="fb-like" data-href="あなたのfacebookページのURL" data-width="500" data-layout="box_count" data-action="like" data-show-faces="true" data-share="false"></div></div>
<div id="fb-root"></div>

<script>
// facebook
window.fbAsyncInit = function() {
  FB.init({
    appId      : 'あなたのAPP ID',
    status     : false, // check the login status upon init?
    cookie     : true, // set sessions cookies to allow your server to access the session?
    xfbml      : true  // parse XFBML tags on this page?
  });

  // いいねしたときの処理
  FB.Event.subscribe('edge.create',
    function(response) {
      location.href = "<%= result_url %>";
    }
  );
};
</script>
```
以上です。後は好きにviewやコントローラをいじってコンテンツを作成して下さい。
お疲れさまでした。

# 参考

* [「plataformatec/devise」](http://github.com/plataformatec/devise)
* [EasyRamble - Rails4 で Devise と OmniAuth で、Twitter/Facebook のOAuth認証と通常フォームでの認証を併用して実装](http://easyramble.com/implement-devise-and-ominiauth-on-rails.html)
* [arsduo/koala](https://github.com/arsduo/koala)

ブログやってます！！
=>http://alex23drum.hatenablog.com