ruby-on-railsfacebookdeviseomniauth-facebook

ActionController::UnknownFormat error (missing template) in Users::OmniauthCallbacksController#facebook when using Devise gem in a rails application?


I'm attempting to finish up this facebook omniauth integration and ran into the error below. I'm not sure what's causing it to happen. It only occures the second time that I try to log in using the facebook auth. The first time (on user create) it works perfectly. But if I log out and hten log in it throws this error.

Here's the error

ActionController::UnknownFormat in Users::OmniauthCallbacksController#facebook

Users::OmniauthCallbacksController#facebook is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: [] NOTE! For XHR/Ajax or API requests, this action would normally respond with 204 No Content: an empty white screen. Since you're loading it in a web browser, we assume that you expected to actually render a template, not nothing, so we're showing an error to be extra-clear. If you expect 204 No Content, carry on. That's what you'll get from an XHR or API request. Give it a shot.

User.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable
  has_many :services
  has_paper_trail
  scope :referred, -> { where.not(:referral_id => nil) }

end

omniauth_callbacks_controller.rb

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  before_action :send_referral_event_email, only: [:create]


  def facebook
    service = Service.where(provider: auth.provider, uid: auth.uid).first

    if service.present?
      user = service.user
      service.update(
        expires_at: Time.at(auth.credentials.expires_at),
        access_token: auth.credentials.token,
      )
    else
      user = User.create(
         email: auth.info.email,
         name: auth.info.name,
         password: Devise.friendly_token[0,20]
      )
      user.services.create(
         provider: auth.provider,
         uid: auth.uid,
         expires_at: Time.at(auth.credentials.expires_at),
         access_token: auth.credentials.token,
      )
      if session[:cte_id]
        UserMailer.delay.send_referred_message(user)
        sign_in_and_redirect user, event: :authentication
        set_flash_message :notice, :success, kind: "Facebook"
      else
        ActionWins.create_advocate(user.email)
        UserMailer.delay.advocate_registration_email(user)
        sign_in_and_redirect user, event: :authentication
        set_flash_message :notice, :success, kind: "Facebook"
      end
    end

  end

  def auth
    p request.env['omniauth.auth']
  end

  def after_sign_in_path_for(resource)
    if session[:cte_id]
      static_thankyou_path
    else
      root_url
    end
  end

  def send_referral_event_email
    if params[:cte_id]
      UserMailer.delay.send_referred_message(@user)
    end
  end
end

I'm using GoRails.com FB omniauth tutorial to build this.

here's the user model from the db

 create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "",    null: false
    t.string   "encrypted_password",     default: "",    null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    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.datetime "created_at",                             null: false
    t.datetime "updated_at",                             null: false
    t.string   "referral_id"
    t.string   "first_name"
    t.string   "last_name"
    t.string   "phone_number"
    t.boolean  "redeemed",               default: false
    t.string   "dealership"
    t.integer  "points",                 default: 0
    t.boolean  "referral_completed",     default: false
    t.string   "name"
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

Thanks for the help!


Solution

  • The problem is that if the user is already present (i.e. the second time), there is no call to redirect the user to go to root or somewhere.

    You have an if-else block which check whether or not a user is visiting your application for the first time. If the user visits for the first-time, then you are creating the user and redirecting the user using

    sign_in_and_redirect user, event: :authentication
    

    However, if the user is already present (i.e. the if block), there is no redirect call. By default, Rails is therefore trying to find a view template facebook.html.erb, which is not present. Hence, the error

    Users::OmniauthCallbacksController#facebook is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: [] NOTE! For XHR/Ajax or API requests, this action would normally respond with 204 No Content: an empty white screen. Since you're loading it in a web browser, we assume that you expected to actually render a template, not nothing, so we're showing an error to be extra-clear. If you expect 204 No Content, carry on. That's what you'll get from an XHR or API request. Give it a shot.
    

    You can add a redirect call at the end of the if block

     if service.present?
          user = service.user
          service.update(
            expires_at: Time.at(auth.credentials.expires_at),
            access_token: auth.credentials.token,
          )
          #add the following line
          sign_in_and_redirect user, event: :authentication
     else
          ....