Rails 4 с Devise, Omniauth и несколькими поставщиками услуг

Я отчаянно пытаюсь найти способ заставить устройство работать в моем приложении 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 или твиттер снова используют разные имена полей, как этот урок решит это?

Кроме того, в моей пользовательской таблице у меня есть атрибуты с именами 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 лет заставить работать устройство.

Мои недавние вопросы, связанные с учебником:

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

Devise Omniauth - настройка и определение стратегий

Rails, Devise & Omniauth - проблемы с настройкой

Есть несколько других, но я не пойму это своими собственными усилиями. У меня было несколько сеансов на 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 НАЗЫВАЛСЯ: УПРАВЛЕНИЕ НЕСКОЛЬКИМИ ПОСТАВЩИКАМИ

Кажется, в этом документе могут быть опечатки, которые опытные программисты могут прочитать в прошлом.

В настоящее время генерируется сообщение об ошибке:

/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

В том же методе есть дисперсия.

Я также не понимаю, почему контроллер сессий не наследуется от контроллера devise. В каждом другом уроке, в котором я использовал контроллер сессий, он унаследовал от devise.

Есть много других запутанных аспектов этого руководства (например, почему у него нет контроллера регистрации, почему нет других путей для разработки, почему у контроллера приложения есть методы create и destroy)?

Отчаянно ищет помощи.

2 ответа

Это не полный ответ, но я решил часть своей проблемы.

Суть жемчужины oauth состоит в том, чтобы взять атрибуты каждой стратегии социальных сетей и объединить их в общую форму выражения.

Включая raw_info из стратегии, код не работает с oauth. Например, хэш-код auth возвращает данные, помеченные как firstName, где oauth распознает их как first_name. Если вы используете

first_name: auth.extra.raw_info.first_name,

атрибут будет равен нулю, когда вызывается ссылка. Это уже странно для меня, поскольку LinkedIn предоставляет базовые данные профиля, которые предполагают, что ярлык является именем.

В любом случае, часть, которую я исправил, состоит в удалении ссылки на 'extra.raw' в приведенной выше строке и использовании auth.info.first_name. Это должно устранить различия между метками стратегии.

Я все еще работаю над остальными проблемами, возникающими в этой установке. Некоторые из проблем в учебнике по исходному тексту - синтаксис, другие более существенны. Я отправлю еще раз, если смогу разобраться.

unknown attribute 'name' for User.

Это означает, что нет name колонка в users Таблица. Вам нужно создать этот столбец или использовать другой имеющийся у вас столбец (например, first_name или же username). Вот так:

username: auth.extra.raw_info.name

Но тогда, если 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'],

Другие вопросы по тегам