(Rails4.2.5) Devise + omniauth-facebook (3.0.0) + dotenv-rails でFacebbok登録認証 (それと、:confirmableメール認証設定の過程も)

(2016/2/21現在)
プログラミング。
人生で初めて、HTMLの基本からプログラミングというものを学び始め、触れてまだ1ヶ月ちょっとなので   まっったく!と言っていいほど参考にはならないと思います。

むしろ、ハマってしまった部分について先人の方々の投稿に助けていただきながらアプリケーション作成をしています。ですのでそこを、是非プログラミングの先輩方からアドバイスをご教授頂ないかな...って思ってます。
<br />
<br />
<br />
では、本題へ。


<h2>今回の目的</h2>


devise,omniauth-facebook,dotenvでfacebook認証の実装

自分でもメールアドレス、パスワードなどの情報で登録できる機能は実装できるようになったものの、validationのemail正規表現だったり、本物のemailか見極める設定だったりはまだ自分には無理だったので、deviseを使ったユーザー登録機能実装を決断。
また、それに加えてFacebookでもログインできるように機能追加をする。
<br />
<br />
<h2>開発環境(ローカル開発中)と使うGem</h2>
<ul>
  <li>Cloud9</li>
  <li>Rails 4.2.5 </li>
  <li>Devise(現時点最新ver.)</li>
  <li>omniauth-facebook (3.0.0)</li>
  <li>Dotenv-rails</li>
</ul>
<br />



<h2>前提</h2>
```gem 'devise'```を使って、parameterで取得したメールアドレスに確認フォームを送信し、メール内容に貼られたurlを押すことでユーザ登録完了するオリジナルログイン機能は実装済み。
アプリケーションの枠組みやデザインもある程度できている。
自分のためにも軽くおさらいしながら現状の説明をして、ハマっている部分の解決方法をご教授していただければと思っています。
ですので、***特に必要のない方は「問題はここから!」へ飛ばしてください。***
<br />



<br />
<br />

参考にさせていただいたサイト
[1](http://chikuzo.hatenablog.com/entry/2015/03/19/100000) [2](http://ruby-rails.hatenadiary.com/entry/20140801/1406907000) [3](http://easyramble.com/create-users-index-show-on-devise.html)
などなど、大変参考になりました。
メールが送られてこない。等は上記参考サイトを参考にして解決しました。ユーザネームとメールアドレスのどちらからでもログインできるようにしたいのですが、上手くいかずまだ解決出来ないのでとりあえず後回しです。。
一応、他にも僕みたいにプログラミングがド初心者の方がお勉強&ネット上で疲れ果てているかもしれないので、過程も載せます。
</ul>
<br />
<br />

<h2>メールとパスワードの２つ + :confirmableを使用してユーザ認証を実装する時の内容</h2>

<br />
必要なところをコメントアウト

```lang:config/initializer/devise.rb

config.mailer_sender = '任意のメールアカウント@gmail.com'`
config.authentication_keys = [:email]
#(↑defaultでは確かコメントアウト'#'されてた?のをインさせた記憶が。)
config.reconfirmable = false
#(↑これはtrueだったりfalseだったりサイトごとで違ってあ良くわからないけど、
　　(初心者なもので、すいません)現状これで動いている。)
```

<br />
以下をコメントアウト&少し編集

```lang:config/enviroments/development.rb
  
# Don't care if the mailer can't send.
  config.action_mailer.raise_delivery_errors = false
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.default_url_options = { :host => "https://ホストurl" }
  config.action_mailer.smtp_settings = {
      :address => "smtp.gmail.com",
      :port => 587,
      :domain => 'https://xxxxxxxxxxxx',
      :user_name => ENV["GMAIL_ADDRESS"],
      :password => ENV["GMAIL_PASSWORD"],
      :authentication => :plain,
      :enable_starttls_auto => true
  }
```
ここでは大切な情報を ```gem 'Dotenv-rails'``` を使って ```ENV['GMAIL_ADDRESS']```と ```ENV['GMAIL_PASSWORD']```という環境変数に入れてある。
また、実際の機密情報は```secret.yml```ではなく、コマンドで'$ rails c ls -a'と叩くと表示される隠しファイルとして`.env`をアプリケーションディレクトリ直下に作ってそこに情報を入れる。

＊Githubを使っていて、そこにレポジトリの開発編集履歴を記録している場合は、pushした時にファイル(emailやそのpasswordの個人情報や後々のFacebook認証で取得するAPIのidであったりを反映させないように).gitignoreさせた方がいいらしいが、まだやっていない。

<br />
<ul>Dotenvについて。以下の、ド初心者でも分かり易かったサイトを参考に
  <li>http://shuzo-kino.hateblo.jp/entry/2014/04/15/225517</li>
  <li>http://tnakamura.hatenablog.com/entry/2014/09/22/dotenv</li>
</ul>
<br />
<br />

次に、user.rbでconfirm!を定義する

```lang:models/user.rb
class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  #  :lockable, trckable, ...ect
  devise :database_authenticatable, :registerable, :rememberable,
         :validatable, :timeoutable, 　　　　:confirmable←を追加！


  # user.rbでdeviseのconfirmableモデルをオーバーライド    
  # override Devise::Models::Confirmable#confirm!
  def confirm!
    super
    if confirmed?
      UserMailer.welcome_email(self).deliver
    end
  end
end
```

<br />
<br />


また、devise標準の見た目をカスタムしたかったので、以下を作成、編集。
```< Devise::SessionsController```でクラスを継承すること。
登録やログイン後のアクションを変更したい場合は```def create super end```のようにオーバーライドで処理を追加してやれば良い。

```lang:controllers/user/sessions_controller.rb
class Users::SessionsController < Devise::SessionsController
  
  def create
    super
　　 #新たな処理を与え上書き変更する
  end

  def destroy
    super
  end
end

```


↓ログイン後のページをuserページにしたかったのでオーバーライド

```lang:controllers/user/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController

  def after_sign_up_path_for(resource)
     user_path(current_user)
  end

end
```


と、同時にルーティング

```lang:config/routes.rb
Rails.application.routes.draw do

  root to: "static_pages#home"
  
  devise_for :users, controllers: {
                       sessions: "users/sessions",
                       registrations: "users/registrations",
                     }
  resources :users, only: [:show]   #/views/users/show　を作ってlogin後のユーザページを作る
```

すると、このような  ```_path```  が生成 & 一部変更
(users/sessionsやusers/registrationsがそう)される。
![スクリーンショット 2016-02-21 2.40.46.png](https://qiita-image-store.s3.amazonaws.com/0/114475/f1f88569-0b93-1166-44d9-d9293278f98b.png)
<br />
<br />
<br />
そしてそして、実際にviewをカスタマイズするために```rails g devise:views users```で   ```views/users/.../```となるようにusers配下にviewファイルを作成。
ちなみに、```rails g devise:views users```をすれば、deviseのviewカスタマイズの為のファイルを自動的に色々と作成してくれます。　　入力formやらスタイルやらを１から作らなくていいって、ちょっと...いや、だいぶ嬉しい。
初心者なのにサボってたらプログラミング上達しな...orz

それはさておき、作成されたviewをbootstrapやらで好きなようにカスタマイズして..


※ ```gem 'devise-bootstrap-views'```を追加して```bundle install```

```lang:config/initializer/devise.rb
require "omniauth-facebook" ←追加

Devise.setup do |config|
・・・
end
```
ものすごく分かりやすい参考サイト。ありがとうございます！
https://www.tamurasouko.com/?p=929
<br />
<br />

さあ、```rails s -p $PORT -b $IP```(←Cloud9の場合)でサーバーを立ち上げて、実際にユーザー登録をしてみましょう。


メール送信元のhot server?にgmailを使っていて、メールが来ない場合は[安全性の低いアプリ]
(http://www.google.com/settings/security/lesssecureapps)で”安全性の低いアプリのアクセス”の設定をオンに変更してください。


これで、とりあえず僕は成功しました。:confirmable でハマっている誰かしらに貢献できていればいいですが。。




**<h2 class="text-center">問題はここからです!!!</h2>**
<p>タダでご教授いただこう何て甘ったれた事は思っていないので本題に入るここまでに時間かかったわけです!どうぞ、みなさま、何卒お力添えを。</p>


<h3>＊前置き＊</h3>

ちなみにここからは説明のために過程も載せていきますが、Facebookに飛ぶところまではできており、その(facebookに飛んだ)時にエラーが図れるのでそのことを頭に入れておいていただければと思います。
***エラー内容は一番下に写真を数枚貼っています。***

<br />

<h2>Facebookでログイン</h2>

Facebook用の```gem 'omniauth-facebook'```ライブラリを追加。

``` bundle install```



```rails g migration AddOmniauthToUsers provider:index uid:index```でカラムを追加。


https://developers.facebook.com/
Facebook Developerにログイン(またはアカウント作成)登録して、アプリを作りダッシュボードからApp IDとApp Secretを取得。
<br />
<br />

devise.rbにAPP_IDやAPI_SECRETを環境変数を使って入れる。

```lang:config/initializer/devise.rb

require "omniauth-facebook"　←追加する

Devise.setup do |config|
  # The secret key used by Devise. Devise uses this key to generate
  # random tokens. Changing this key will render invalid all existing
  # confirmation, reset password and unlock tokens in the database.
  # Devise will use the `secret_key_base` on Rails 4+ applications as its `secret_key`
  # by default. You can change it below and use your own secret key.
  # config.secret_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
  
  #　ここも追加編集
  config.omniauth( :facebook,
                   ENV['FACEBOOK_APP_ID'],
                   ENV['FACEBOOK_API_SECRET'],
                   {:scope => 'email'}　#email必須にしてるのでこれで合ってる？
                  )

・・・省略・・・

end
```


<br />
<br />

omniauthの認証を適応させるため ``omniauthable```などを追加。

```lang:models/user.rb
 devise :database_authenticatable, :registerable, :confirmable,
        :omniauthable, :omniauth_providers => [:facebook]　←この行を追加
  
```

また、```rake routes```でcallbackとauthorizeのurl_pathがそれぞれ生成されていることを確認。
![スクリーンショット 2016-02-21 18.37.22.png](https://qiita-image-store.s3.amazonaws.com/0/114475/3fae49ef-6f4c-3fb9-4310-c6ca3f004ade.png)

<br />
<br />


...で、最後にcallbackの設定をしていきます。

<h2>コントローラ作成</h2>

callback用のコントローラを作成する。
```rails g controller devise:users omniauthcallbacks```　だったかな。
とにかくファイルの中はこうなってます。　＊クラス継承など注意


```lang:controllers/users/omniauth_callbacks_controller.rb

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
    
  def facebook
    callback_from :facebook
  end


  private

  def callback_from(provider)
    provider = provider.to_s

    @user = User.find_for_oauth(request.env['omniauth.auth'])

    if @user.persisted?
      flash[:notice] = I18n.t('devise.omniauth_callbacks.success', kind: provider.capitalize)
      sign_in_and_redirect @user, event: :authentication
    else
      session["devise.#{provider}_data"] = request.env['omniauth.auth']
      redirect_to new_user_registration_url
    end
  end

end
```


コントローラーで使った```find_for_oauth```メソッドの処理をを定義する。
※ここでもemailは現段階では必須としているためFacebookでの認証時には取得した```uid, provider```に紐付いたダミーのアドレスを作らせる。

```lang:models/user.rb

# self.find_for_oauthを定義。
# callback後のユーザー登録で、取得した情報を参照しまだuserでない場合はダミーメール作成しユーザー情報を保存。
def self.find_for_oauth(auth)
    user = User.where(uid: auth.uid, provider: auth.provider).first

    unless user
      user = User.create(
        uid: auth.uid,
        provider: auth.provider,
        email: User.dummy_email(auth),
        
        #この下のpasswordの部分ですが他の参考サイトで
          「# ==> Configuration for :validatable
  　　　　　 # Range for password length. 
           config.password_length = 8..72」に
　　　　　　　合わせたほうがいいというのを読んだので合わせてますが..

        password: Devise.friendly_token[8..70] 
      )
    end
    user
  end
  
  private

  # Create dummy email for OAuth
  def self.dummy_email(auth)
    "#{auth.uid}-#{auth.provider}@example.com"
  end
end
```


で、そしたらcallbackの時に今設定したcallback_controllerが呼ばれるようルーティングを設定。

```lang:config/routes.rb

Rails.application.routes.draw do
  devise_for :users, controllers: {
                       sessions: "users/sessions",
                       registrations: "users/registrations",
                       omniauth_callbacks: 'users/omniauth_callbacks'  #この行を追加。

・・・

end
```

で、あとは認証用リンクを設置して実際にログインをしてみる。

```user_omniauth_authorize_path(:facebook) ```

参考URL
http://qiita.com/kami_zh/items/94aec2d94a2b4e9a1d0b
http://totutotu.hatenablog.com/entry/2015/10/06/Devise%E3%81%A7Facebook%E3%81%AEAOuth%E8%AA%8D%E8%A8%BC%E3%82%92%E5%B0%8E%E5%85%A5%E3%81%99%E3%82%8B

<h3 class="text-center">※ここからハマります。</h3>
<br />
<br />

Facebook Developersでサイトページを入れたりと設定をしてあるんですが
Facebookに飛んだ時このようなエラーが出てしまいます。
APP_IDやAPI_SECRETはこの前にエラーを解決したので渡せています。
開発環境でも書きましたが、ドメインやアプリケーションのデプロイはしていません。
ローカル開発中です。ですので、ドメインやらサイトURLなどは仮のもので設定しています。
多分その辺が関係あるのだと思いますが。。。



Facebook Developers上での設定内容
サイトURL```https://クラウド9アカウント名-ワークディレクトリ名-.c9users.io/```
app domains: ```上記と同じ。```
コンタクトEmail: 本物入力済み
Valid OAuth redirect URIs: ```https://クラウド9アカウント名-ワークディレクトリ名-.c9users.io/users/auth/:action/callback```

<br />

上記エラーに関する写真
1: ![スクリーンショット 2016-02-21 19.26.56.png](https://qiita-image-store.s3.amazonaws.com/0/114475/181e832b-0ec2-61d0-d1c4-1c8f4856999a.png)

2: ![スクリーンショット 2016-02-21 19.27.13.png](https://qiita-image-store.s3.amazonaws.com/0/114475/c4e71d07-a487-47f4-8b97-0ce2789ea957.png)

3: ![スクリーンショット 2016-02-21 19.26.32.png](https://qiita-image-store.s3.amazonaws.com/0/114475/c191e74d-13c1-77ea-9746-4ed09fa498b7.png)


どうか、参考になるサイトまたは同じエラーになったことのある方で解決方法をご教授頂ければ幸いです。
よろしくお願いいたします。

イージミスや挙動に多大な問題を発生させるような記述ミスがあれば、ご指摘の程よろしくお願いいたします。