CanCeylan
CanCeylan

Reputation: 3010

Rails - Build does not create a record in database

I'm trying to add authentications controller for my current devise system, in order to provide multiple logins with facebook and twitter. To do that, I'm following this tutorial: http://railscasts.com/episodes/236-omniauth-part-2

My problem is, for the person, who hasn't registered yet, and trying to register with twitter. So I need to create both user and authentication for that.

My code is the following:

      user = User.new
      token = omni['credentials'].token
      token_secret = omni['credentials'].secret
      user.provider = omni.provider
      user.uid = omni.uid

      user.authentications.build(:provider => omni['provider'], :uid => omni['uid'], :token => token, :token_secret => token_secret)

      if user.save
        flash[:notice] = "Logged in."
        sign_in_and_redirect(:user, user)                
      else
        session["devise.user_attributes"] = user.attributes
        redirect_to new_user_registration_path
      end 

So at the end of the registration process, the new user is created. However in the database, I don't see any twitter authentication record with respect to that user.

Is that because of the user.authentications.build ?

That would be great if you can help me.

Thanks.

Upvotes: 0

Views: 260

Answers (4)

Adrien Coquio
Adrien Coquio

Reputation: 4930

Yes it is because of build, it is use to build a record without saving it in the database (like new).

If in your model you have a User has_many :authentications , you can set the autosave option to true to automatically save the authentications when you are saving the user :

has_many :authentications, autosave: true

Upvotes: 0

Chris
Chris

Reputation: 131

As a data point: The railscasts you're referring to references Omniauth pre-1.0, which had a slighly different strategy than what that railscsts reference. (Note: I'm using the exact method you're referencing on a live site ). In this case, the build calls "apply_omniauth" -

Make sure you've created (as they reference in the video), a registrations controller which builds the resource. Here is my current working example:

    class RegistrationsController < Devise::RegistrationsController
  def create
    super
    session[:omniauth] = nil unless @user.new_record?
  end

  private

  def build_resource(*args)
    super
    if session[:omniauth]
      # apply omniauth calls the user model and applies omniauth session to the info
      @user.apply_omniauth(session[:omniauth])

      #
      @user.valid?
    end
  end
end

However, you still need to create the authentication record, here is my exact call:

current_user.authentication.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])

Hope it helps.

Upvotes: 3

Jesse Wolgamott
Jesse Wolgamott

Reputation: 40277

Yes, it is because of build

User.build # allocates a new record for you
User.create # allocates and then saves a new record for you

So I think you want

user.authentications.create(:provider => omni['provider'], 
                            :uid => omni['uid'], 
                            :token => token, 
                            :token_secret => token_secret)

In addition, you should handle the case where the create does not save (validation problem)

Upvotes: 2

R Milushev
R Milushev

Reputation: 4315

I suppose if you are using Devise+Omniauth , you could take a look at this more recent Railscast. There is a native support of OmniAuth in the new version of Devise gem .

Upvotes: 0

Related Questions