Rails 4与Devise,Omniauth和多个服务提供商

时间:2015-12-07 09:47:02

标签: ruby-on-rails devise omniauth omniauth-linkedin

我正在拼命寻找一种方法来设计我的Rails 4应用程序。我已经尝试了每个可以找到这个设置的教程。

目前的教程是:http://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook-and-linkedin/

我之前关于相关问题的赏金问题(通常被投票并且我不明白为什么),显示了我完成这项工作的其他尝试。

我目前的问题是用户模型中的这段文字:

def self.find_for_oauth(auth, signed_in_resource = nil)

    # Get the identity and user if they exist
    identity = Identity.find_for_oauth(auth)

    # If a signed_in_resource is provided it always overrides the existing user
    # to prevent the identity being locked with accidentally created accounts.
    # Note that this may leave zombie accounts (with no associated identity) which
    # can be cleaned up at a later date.
    user = signed_in_resource ? signed_in_resource : identity.user

    # Create the user if needed
    if user.nil?

      # Get the existing user by email if the provider gives us a verified email.
      # If no verified email was provided we assign a temporary email and ask the
      # user to verify it on the next step via UsersController.finish_signup
      email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
      email = auth.info.email if email_is_verified
      user = User.where(:email => email).first if email

      # Create the user if it's a new registration
      if user.nil?
        user = User.new(
          name: auth.extra.raw_info.name,
          #username: auth.info.nickname || auth.uid,
          email: email ? email : "#{auth.uid}-#{auth.provider}.com",
          password: Devise.friendly_token[0,20]
        )
        user.skip_confirmation!
        user.save!
      end
    end

问题是(指向这一行:user = User.new)在上面的方法中:

unknown attribute 'name' for User.

在我尝试的上一个教程中,我发现当我将属性更改为:

时,linkedin工作正常
# self.email = omniauth['extra']['raw_info']['emailAddress'] 
 #      self.first_name = omniauth['extra']['raw_info']['firstName']
    #     self.last_name = omniauth['extra']['raw_info']['lastName']

omniauth策略的字段名称与教程中显示的字段名称不同(至少对于linkedin)。但是如果Facebook或Twitter再次使用不同的字段名称,教程如何解决这个问题?

此外,在我的用户表中,我有名为first_name和last_name的属性,但我尝试将该行更改为:

first_name: auth.extra.raw_info.'firstName',

这也不起作用。

当我尝试:

first_name: auth.extra.raw_info.name

我收到此错误:

undefined method `password_required?' for #<User:0x007fb7bc2ce6f8>

但无论如何,我只想在该领域中使用名字,我认为这会将整个名字放入名字(虽然我不确定)。此外,如果要修改这个以适用于linkedin,这是否意味着它不适用于Facebook和Twitter?

一切都很糟糕。我对此越来越感到沮丧。有谁知道如何解决这个特殊问题。我已经尝试了2。5年才能让设计/ omniauth工作。

我最近的教程链接问题是:

https://stackoverflow.com/questions/33888972/rails-devise-omniauth-strategies-omniauthcallbackscontroller

Devise Omniauth - setup & defining strategies

Rails, Devise & Omniauth - problems with setup

还有其他几个,但我不是通过自己的努力来解决这个问题。我在codementor.io上有过几次会议,但却找不到帮助。非常感谢帮助来源。

因此尝试下面的建议时,我尝试将用户模型中的方法更改为:

def self.find_for_oauth(auth, signed_in_resource = nil)

    # Get the identity and user if they exist
    identity = Identity.find_for_oauth(auth)

    # If a signed_in_resource is provided it always overrides the existing user
    # to prevent the identity being locked with accidentally created accounts.
    # Note that this may leave zombie accounts (with no associated identity) which
    # can be cleaned up at a later date.
    user = signed_in_resource ? signed_in_resource : identity.user

    # Create the user if needed
    if user.nil?

      # Get the existing user by email if the provider gives us a verified email.
      # If no verified email was provided we assign a temporary email and ask the
      # user to verify it on the next step via UsersController.finish_signup
      email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
      email = auth.info.email if email_is_verified
      user = User.where(:email => email).first if email

      # Create the user if it's a new registration
      if user.nil?
        user = User.new(
          case auth.provider
            when 'linkedin'
              first_name: auth.extra.raw_info.firstName,
              last_name: auth.extra.raw_info.lastName,
              email: emailAddress ? email : "#{auth.uid}-#{auth.provider}.com",
              #username: auth.info.nickname || auth.uid,
              # email: email ? email : "#{auth.uid}-#{auth.provider}.com",
              password: Devise.friendly_token[0,20]
            when 'facebook'
              first_name: auth.extra.raw_info.first_name,
              last_name: auth.extra.raw_info.last_name,
              email: auth.extra.raw_info.email ? email : "#{auth.uid}-#{auth.provider}.com",
              password: Devise.friendly_token[0,20]

            when 'twitter' 
            first_name: auth.extra.raw_info.nickname, 
          end
        )
        user.skip_confirmation!
        user.save!
      end
    end

这有几个问题,是:

unexpected ':', expecting keyword_end first_name: auth.extra.raw_info.firstName,
unexpected tLABEL, expecting '=' last_name: auth.extra.raw_info.lastName
unexpected tLABEL, expecting '=' email: emailAddress ? email : "#{au... ^
unexpected ',', expecting keyword_end
unexpected keyword_when, expecting keyword_end when 'facebook' ^
unexpected ':', expecting keyword_end first_name: auth.extra.raw_info.first_name, ^ 
unexpected tLABEL, expecting '=' last_name: auth.extra.raw_info.last_name,
unexpected tLABEL, expecting '=' email: auth.extra.raw_info.email ? ... ^
unexpected ',', expecting keyword_end
unexpected keyword_when, expecting keyword_end when 'twitter' ^ 
unexpected ':', expecting keyword_end first_name: auth.extra.raw_info.nickname, ^
unexpected keyword_end, expecting '='

我不知道如何解决这个问题 - 我找不到任何关于如何解决这个问题的例子(除了下面的帖子中的例子) - 这显然不起作用。

除上述所有内容外,我如何处理Twitter?它有一个昵称字段。如何将单词分开,以便将第一个单词保存为first_name,将第二个单词保存为last_name?

从下面特别讽刺的评论中推断,我再次尝试了这个建议,if语句。它仍然无法运作。

def self.find_for_oauth(auth, signed_in_resource = nil)

    # Get the identity and user if they exist
    identity = Identity.find_for_oauth(auth)

    # If a signed_in_resource is provided it always overrides the existing user
    # to prevent the identity being locked with accidentally created accounts.
    # Note that this may leave zombie accounts (with no associated identity) which
    # can be cleaned up at a later date.
    user = signed_in_resource ? signed_in_resource : identity.user

    # Create the user if needed
    if user.nil?

      # Get the existing user by email if the provider gives us a verified email.
      # If no verified email was provided we assign a temporary email and ask the
      # user to verify it on the next step via UsersController.finish_signup
      email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
      email = auth.info.email if email_is_verified
      user = User.where(:email => email).first if email

      # Create the user if it's a new registration
      if user.nil?
        user = User.new(
          if auth.provider = linkedin
              first_name: auth.extra.raw_info.firstName,
              last_name: auth.extra.raw_info.lastName,
              email: emailAddress ? email : "#{auth.uid}-#{auth.provider}.com",
              #username: auth.info.nickname || auth.uid,
              # email: email ? email : "#{auth.uid}-#{auth.provider}.com",
              password: Devise.friendly_token[0,20]
          end

          if auth.provider = facebook    
              first_name: auth.extra.raw_info.first_name,
              last_name: auth.extra.raw_info.last_name,
              email: auth.extra.raw_info.email ? email : "#{auth.uid}-#{auth.provider}.com",
              password: Devise.friendly_token[0,20]

          end

          if auth.provider = twitter
            first_name: auth.extra.raw_info.firstName, 
          end
        )
        user.skip_confirmation!
        user.save!
      end
    end

如果没有在这个董事会上找到解决方案的话,我会很感激您认为支付专业人员帮助解决这些问题的合理程度。

我已经退回并评论了与DEVISE和OMNIAUTH相关的所有代码,并且现在再次尝试,在OMNIAUTH WIKI上发布了DOC:管理多个提供商

看来这个文档可能有错误,有经验的编码员可以阅读过去。

目前,生成的错误消息如下:

/Users/config/routes.rb:35: syntax error, unexpected [, expecting keyword_do or '{' or '(' ...', to: 'sessions#create', via [:get, :post] ... ^ /Users/config/routes.rb:36: syntax error, unexpected [, expecting keyword_do or '{' or '(' match '/logout', to: 'sessions#destroy', via [:get, :post] ^

我已直接从用户指南中复制了这些路线。我远非专家,但我也很困惑为什么'=='在某些地方使用,而'='在本文档的其他地方使用。例如:

if signed_in?
            if @identity.user == current_user

虽然:

@identity.user = current_user

在同一方法中存在差异。

我也很困惑为什么会话控制器不会从设计控制器继承。在我已经完成的每个其他教程中都有一个会话控制器,它继承自设计。

本教程还有其他一些令人困惑的方面(比如为什么它没有注册控制器,为什么没有其他的设计路径,为什么应用程序控制器有创建和销毁方法)?

拼命寻求帮助。

2 个答案:

答案 0 :(得分:0)

这不是一个完整的答案,但我已经解决了部分问题。

oauth gem的重点是从每个社交媒体策略中获取属性,并将它们统一为一种常见的表达形式。<​​/ p>

通过合并策略中的raw_info,代码不能与oauth一起使用。例如,linkedin auth hash返回标记为“firstName”的数据,其中oauth将其识别为first_name。如果你使用

first_name: auth.extra.raw_info.first_name,

在调用链接时,该属性将为nil。这对我来说已经很奇怪,因为LinkedIn提供的基本个人资料详细信息表明标签是名字。

无论如何,我修复的部分是删除上面一行中对'extra.raw'的引用并使用auth.info.first_name。这应解决战略标签之间的差异。

我仍在处理此设置中出现的其他问题。 sourcey教程中的一些问题是语法,其他问题则更为重要。如果我可以解决它,我会再次发布。

答案 1 :(得分:-1)

unknown attribute 'name' for User.

这意味着name表中没有users列。您需要创建此列或使用您拥有的其他列(例如first_nameusername)。像这样:

username: auth.extra.raw_info.name
  

但是如果Facebook或Twitter再次使用不同的字段名称,那么如何   教程是否解决了这个问题?

是的,本教程只提供了一个变体,但其他变体并不那么难以找到。你只需要知道,哪些字段返回这个或那个提供者(twitter,facebook或linkedin)并做这样的事情:

def self.find_for_oauth(auth, signed_in_resource = nil)
  ...
  # Create the user if needed
  if user.nil?
    case auth.provider
      when 'facebook'
        # Take fields that Facebook provides and use them when creating a new user
      when 'twitter'
        # Take fields that Twitter provides and use them when creating a new user
      when 'linkedin'
        # Take fields that Linkedin provides and use them when creating a new user
    end
  end
  ...
end

如果为每个提供程序实现单独的方法并在某些when中调用它们,那么代码组织会更好。

同时查看https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema以了解env['omniauth.auth']内的内容。