Rails ActiveRecord无法使用两个表

时间:2015-03-16 06:34:45

标签: ruby-on-rails postgresql ruby-on-rails-4 activerecord

我一直在努力让我的rails项目只用用户唯一的facebook数据更新用户表。但是,我无法获取Facebook数据。我尝试了多种方法,但最终代码似乎是hacky并使用强力更新列(以及创建重复记录)

以下是我的例子:

用户

class User < ActiveRecord::Base
 has_one :facebook 

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

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

迁移:

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

创建用户时: SessionController(为用户调用create时)

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)

到目前为止,我对Rails ActiveRecord的理解是,如果我使用“has_one”和“belongs_to”,那么如果创建了用户表,它应该自动在facebook表中创建记录吗?

我的预期数据是:

SELECT * FROM users where id = 1;
id   email
1    email@email.com

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

facebook根本没有创建记录。

不确定我哪里出错了,我已经按照大量的教程进行操作,希望能掌握有效的记录。

谢谢!

@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

---否则每次登录时都会不断插入新记录。

2 个答案:

答案 0 :(得分:1)

在activerecord和Rails中有这么多移动的部分。我认为您必须回到迁移并解决一些问题,为MVC的视图和控制器部分设置坚实的模型基础。

我在您发布的迁移中看到了模型类型的功能,但这并不能很好地为您服务。迁移应尽可能灵活,约束应放在model.rb上。

  • 迁移:灵活。建立基本关系指数。
  • 型号:The model.rb定义了约束(has_one,belongs_to等) 修饰和验证数据关系(:依赖,:必需, 等)

您的用户模型看起来很好。

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

你的facebook迁移应该看起来更像这样。创建一个t.reference并添加索引。

    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

然后在您的Facebook模型中,您可以应用限制和要求

facebook.rb

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

您的用户model.rb应包含:

 has_one :facebook

关于您在控制器中的更高级别操作还有其他一些问题,但我认为设置模型可以帮助您朝着目标前进。

答案 1 :(得分:1)

下面的模型约束以及索引设置看起来会导致ActiveRecord到ROLLBACK并且不会为给定用户添加重复的facebook记录。但听起来重复的是添加到facebook表。那怎么样?

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

user.rb
 has_one :facebook

&#39; if&#39;你写的这个条目对我来说就好像没有必要设置用户/ facebook之间的关系并在模型和数据库表中工作,这让我觉得某处缺少验证。

要尝试一些事情,在Facebook数据描述上进行模型迁移(更改),以便为db表本身的user_id字段添加:唯一验证器。 (没有change_index命令,你必须删除然后添加。)

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

尝试拍摄&#39; if&#39;逻辑出来,看看你是否得到了欺骗。在继续执行控制器中的逻辑之前,需要正确设置关系,否则您将试图解开它。

对于您在评论中提出的问题,范围很适合根据参数创建集合。所以,在你的user.rb模型中:

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

user.important_thing_is_true引用的是返回集合或nil,然后您可以在其他逻辑或显示中测试或使用等等。但是,如果您没有重复记录问题,可能此范围不是& #39; t需要。