0
votes

I've been trying to have my rails project only update the user table with the users unique facebook data. However, I can't get the facebook data to populate. I've tried multiple approaches but the end code seems to be hacky and using brute force to update the columns (as well as creating duplicate records)

Here are my examples:

User

class User < ActiveRecord::Base
 has_one :facebook 

 def self.create_with_omniauth(auth)
   create! do |user|
    user.email = auth['email']
   end
  end
end

Facebook

class Facebook < ActiveRecord::Base
 belongs_to :user

def self.create_with_omniauth(auth)
  create! do |fb|

  if auth['info']
     fb.profile_link = auth['info']['profile_link'] || "test"
     end
    end
end

Migrations:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email
      t.timestamps null: false
    end
  end
end


class Facebooks < ActiveRecord::Migration
  create_table :facebooks do |f|
    f.belongs_to :user, index: true, :unique => true
    f.string :profile_link
    f.timestamps null: false
  end
end

While creating the user: SessionController (When calling create for user)

def create
  auth = request.env["omniauth.auth"]
  user = User.where(:provider => auth['provider'],
                  :uid => auth['uid'].to_s).first || User.create_with_omniauth(auth)

  Facebook.create_with_omniauth(auth)

My understanding of Rails ActiveRecord so far... is that if I use "has_one" and "belongs_to" then it should automatically create records in the facebook table if a user table was created?

My expected Data would be:

SELECT * FROM users where id = 1;
id   email
1    [email protected]

SELECT * FROM facebooks where user_id = 1;
id   user_id   profile_link
1      1       facebook.com/profile_link

facebook has no record created at all.

Not sure where I went wrong, I've followed tons of tutorials and hope I can master the active record.

Thanks!

Side Question for @val def self.facebook_handler(user, auth)

if Facebook.exists?(user_id: id)
  user = Facebook.find_by(user_id: id)

  user.update(name: me['name'])
  user.update(first_name: me['first_name'])
else
  create! do |fb|
    if me
      fb.name = me['name']
      fb.user_id = user.id
      fb.first_name = me['first_name']
     end
    end
   end
 end

--- otherwise it kept inserting new records each time I logged in.

2
I think you have to look in to accepts_nested_attributes_for :facebookAlbin
What if this was just a customer's table using orders? I'm able to save all the Facebook info into my users ... But I want it organized.Will
Have I implemented wrong? Shouldn't the Facebook s table at least show some rows?Will

2 Answers

1
votes

So many moving pieces in activerecord and in Rails. I think you have to go back to your migration and address a few things to set a solid model foundation for the view and controller parts of your MVC.

I see model-type function in the migration you posted, which is not going to serve you well. Migrations should be as flexible as possible, the constraints should be placed on the model.rb.

  • Migration: Flexible. Basic relationship indices set up.
  • Model: The model.rb defines constraints (has_one, belongs_to, etc) and further embellishes and validates data relationships (:dependent,:required, etc.)

Your users model looks fine.

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email
      t.timestamps null: false
    end
  end
end

Your facebooks migration should have looked more like this. Create a t.reference and add the index.

    class Facebooks < ActiveRecord::Migration
      create_table :facebooks do |f|
        t.references :user, index: true
        f.string :profile_link
        f.timestamps null: false
      end
      add_index :facebooks, [:user_id]
    end

Then in your Facebook model you can apply restraints and requirements

facebook.rb

belongs_to :user, 
validates :user_id, presence: true, :unique => true

Your user model.rb should include:

 has_one :facebook

There are some other questions about your higher level actions in the controller, but I think setting up your model will help you make progress towards your goal.

1
votes

The model constraints below, along with the index setup looks like it would cause ActiveRecord to ROLLBACK and not add a duplicate facebook record for a given user. But it sounds like duplicates are being added to the facebook table. So, how?

facebook.rb
   belongs_to :user, 
   validates :user_id, presence: true, :unique => true
     ...

user.rb
 has_one :facebook

The 'if' clause you wrote looks to me as if it would be unnecessary if the relationship between user / facebook are set up and working in the model and database table, which makes me think there's a missing validation somewhere.

There's something to try, a model migration (change) on Facebook data description to add a :unique validator to the user_id field of the db table itself. (There's no change_index command, you have to remove and then add.)

remove_index :facebooks, [:user_d] 
add_index :facebooks, [:user_id], :unique => true

Try taking your 'if' logic out and see if you're getting dupes. The relationships need to be properly setup before proceeding to the logic in the controller or you will break your head trying to unwind it.

And to your question in the comment, scopes are beautiful for creating collections based on parameters. So, in your user.rb model:

scope :important_thing_is_true, -> { where(:provider => auth['provider'],:uid => auth['uid'].to_s).first) } 

Which is referenced by user.important_thing_is_true returns the collection or nil, which then you can test or use in other logic or display, etc. But, if you don't have the dupe records problem, maybe this scope isn't needed.