2013-02-22 63 views
3

我正在关注Ryan的Omniauth with Devise railscast。代码的一部分是:Rails异常声明:where().first_or_create()

class User < ActiveRecord::Base 
    def self.from_omniauth(auth) 
    where(auth.slice(:provider, :uid)).first_or_create do |user| 
     user.provider = auth.provider 
     user.uid = auth.uid 
     user.username = auth.info.nickname 
    end 
    end 
end 

我正在抓我的头在哪里()first_or_create做。这段代码究竟做了什么?

我的猜测是where()语句应用于类User。但Rails如何知道它相当于User.where(:provider => "provider_id passed by auth", :uid => "uid passed by auth")

我的猜测是它会产生一个集合,那么如果集合是空的,那么创建一个新的实例user并分配新的属性。否则,选择第一个实例并重新分配属性。

我的猜测是否正确?

回答

9

让我们把它分成几部分。

auth.slice(:提供商:UID)

AUTH是包含散列:提供商和:UID密钥。调用.slice以auth返回一个新的散列,只有这些作为键。即

auth = { provider: 'foo', uid: 'bar', some_other_key: 'blah' } 
new_hash = auth.slice(:provider, :uid) # { provider: 'foo', uid: 'bar' } 

first_or_create

find_or_create_by等效。您可以阅读documentation并查看它是否搜索与传递给where的选项相匹配的记录。如果没有找到记录,它会尝试使用这些选项创建一个记录作为属性。

块通过

user.provider = auth.provider 
user.uid = auth.uid 
user.username = auth.info.nickname 

实际上只需要最后一行。前两行是多余的,因为它位于where选项。

+0

感谢您的回答。您能否解释where()语句如何工作而不指定哪个属性与哪个值关联?另外,我不确定你最后的陈述是否正确。如果以前没有创建用户实例会怎么样? – AdamNYC 2013-02-22 04:25:55

+0

我已经用一个例子更新了我的答案。 'auth.slice'返回'where'用来构成sql语句的散列。对于该块,如果没有找到,'first_or_create'将使用传递给创建对象的位置的选项。 – jvnill 2013-02-22 04:29:35

+0

明白了。谢谢。 – AdamNYC 2013-02-22 04:34:40