ruby-on-railsactiverecordomniauthruby-on-rails-5clearance

Stop Associations from Validating in Rails 5


Using Rails 5, I'm trying to implement Omniauth-Facebook and Clearance for user authentication.

Note: My code is exactly like this Gist

I've gotten it mostly working. However when using Facebook to register (ie a user has never visited the site), Rails throws an error saying Validation failed: User must exist. I've narrowed down the problem to this block in the Gist:

  def self.create_with_omniauth(auth_hash)
    create! do |auth|
      auth.provider = auth_hash["provider"]
      auth.uid = auth_hash["uid"]
      auth.token = auth_hash["credentials"]["token"]
    end
  end

When it hits that, it tries to create! without a auth.user object present, and fails. Here is the relevant code from the sessions controller:

#-- Spectically, the line below
authentication = Authentication.find_by_provider_and_uid(auth_hash["provider"], auth_hash["uid"]) || Authentication.create_with_omniauth(auth_hash)
#-- More code, for context
if authentication.user
  user = authentication.user 
  authentication.update_token(auth_hash)
  @next = root_url
  @notice = "Signed in!"
else
  user = User.create_with_auth_and_hash(authentication,auth_hash)
  @next = edit_user_path(user)   
  @notice = "User created - confirm or edit details..."
end

The only thing I'm missing out of the Gist is the structure of his Authentications table. Using the context clues I found, I created this table:

  def change
    create_table :authentications do |t|
      t.string :provider
      t.string :uid
      t.string :token
      t.references :user, foreign_key: true

      t.timestamps
    end
  end

If any more information is needed, I'll provide what I can


Solution

  • In Rails 5 belongs_to is required by default http://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html, so you'll get a validation error without it.

    In this example you are trying to create Authentication object without a User, that's why you get "Validation failed: User must exist".

    If you really want to create Authentication object without User, this should work:

    class Authentication < ActiveRecord::Base
      belongs_to :user, optional: true
    end