[Ruby on Rails] Devise + Omniauth Authentication

### [Sample Application](https://yuto-devise-omniauth.herokuapp.com/)

```ruby:Gemfile
gem 'devise'
gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-twitter'
gem 'paperclip'
gem 'fog'
```

`rails g devise:install`
`rails g devise User`
`rails g devise:controllers users`
`rails g migration AddAttributesToUsers name uid provider token`
`rails g paperclip user image`

```ruby:config/routes.rb
devise_for :users, controllers: {
  omniauth_callbacks: 'users/omniauth_callbacks',
  registrations: 'users/registrations'
}
```

```ruby:config/initializers/devise.rb 
config.omniauth :facebook, ENV['FACEBOOK_API_KEY'], ENV['FACEBOOK_API_SECRET'],
  secure_image_url: true
config.omniauth :twitter, ENV['TWITTER_API_KEY'], ENV['TWITTER_API_SECRET']
```

```ruby:config/environments/production.rb
  config.paperclip_defaults = {
    use_timestamp: false,
    url: '/:attachment/:class/:id/:style.:extension',
    storage: :fog,
    fog_directory: ENV['FOG_DIRECTORY'],
    fog_credentials: {
      provider: :aws,
      region: 'ap-northeast-1',
      aws_access_key_id: ENV['AWS_API_KEY'],
      aws_secret_access_key: ENV['AWS_API_SECRET']
    }
  }
```

```ruby:app/models/user.rb
  devise :database_authenticatable, :registerable, :omniauthable,
         :recoverable, :rememberable, :trackable, :validatable

  has_attached_file :image, styles: { thumb: '50x50#' }
  validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/

  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,
        token: auth.credentials.token,
        name: auth.info.name,
        email: User.get_email(auth),
        password: Devise.friendly_token[0, 20]
      )
    end
    if auth.info.image
      user.update_attribute(:image, auth.info.image)
    end
    user
  end

  private

  def self.get_email(auth)
    auth.info.email || "#{auth.provider}-#{auth.uid}@example.com"
  end
```

```ruby:app/controllers/users/registrations_controller.rb
protected
  # If you have extra params to permit, append them to the sanitizer.
  def configure_sign_up_params
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :image])
  end

  # If you have extra params to permit, append them to the sanitizer.
  def configure_account_update_params
    devise_parameter_sanitizer.permit(:account_update, keys: [:name, :image])
  end

  # Can update without current password
  def update_resource(resource, params)
    # Require current password if user is trying to change password
    return super if params['password']&.present?

    # Allows user to update registration information without password
    resource.update_without_password(params.except('current_password'))
  end
```

```ruby:app/controllers/users/omniauth_callbacks_controller.rb
  def facebook
    callback_from :facebook
  end

  def twitter
    callback_from :twitter
  end

  private

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

```ruby:app/views/layouts/application.erb.slim
          ul.nav.navbar-nav.navbar-right
            - if user_signed_in?
              li = image_tag current_user.image(:thumb)
              li.navbar-text = current_user.name
              li = link_to 'Sign out', destroy_user_session_path, method: :delete
            - else
              li = link_to 'Sign in', new_user_session_path
              li = link_to 'Sign up', new_user_registration_path
              li = link_to 'Sign up with Facebook', user_facebook_omniauth_authorize_path
              li = link_to 'Sign up with Twitter', user_twitter_omniauth_authorize_path
```
![スクリーンショット 2017-06-13 18.23.21.png](https://qiita-image-store.s3.amazonaws.com/0/35605/097e2eef-0eb3-695d-3de6-9a9293bc941b.png)


*Paperclip::AdapterRegistry::NoHandlerError　というエラーが発生した場合*

```ruby:config/initializers/paperclip.rb
Paperclip::DataUriAdapter.register
```