Лучшая практика создания общего метода между разработкой SessionsController и RegistrationsController - PullRequest
0 голосов
/ 01 августа 2020

Есть 3 способа войти в мои приложения с токеном приглашения:

  • Вы уже вошли в систему
  • У вас есть учетная запись, но вы не вошли в нее
  • Вам необходимо зарегистрировать

Теперь меня интересует, как обрабатывать последние 2 ситуации в сочетании с Devise, не повторяя одни и те же функции.

Контроллер отменяет обрабатываются из routes.rb:

devise_for :users, controllers: {
      sessions: 'users/sessions',
      registrations: 'users/registrations'
  }

Переопределение after_sign_in/up_path для сеансов и регистраций:

class Users::SessionsController < Devise::SessionsController
  protected
  def after_sign_in_path(resource)
    handle_invite
    super(resource)
  end
end
class Users::RegistrationsController < Devise::RegistrationsController
  protected
  def after_sign_up_path_for(resource)
    handle_invite
    super(resource)
  end
end

Где я должен разместить handle_invite метод?

Я ищу решение, которое я могу поместить в свой UsersController, потому что это кажется правильным местом для его размещения.:

class UsersController < ApplicationController
  private
  def handle_invite
    # Some code getting the token and adding the user to a group
  end
end

Я думал, что это должно сработать, потому что кажется, что Devise наследует этот контроллер:

class Users::SessionsController < Devise::SessionsController; end
class Devise::SessionsController < DeviseController; end
class DeviseController < Devise.parent_controller.constantize; end

Итак, я ожидал, что Devise.parent_controller.constantize будет представлять UsersController, но по какой-то причине handle_invite нельзя назвать от дочерних контроллеров.

1 Ответ

1 голос
/ 02 августа 2020

Если вы хотите использовать классическое наследование, вам придется фактически поместить этот класс в цепочку наследования, настроив Devise.parent_controller, не нарушая при этом остальную часть цепочки.

Ruby не имеет множественного наследования . Класс может наследовать только от одного родительского класса.

# config/initializers/devise.rb
config.parent_controller = 'UsersController'
class UsersController < DeviseController
  private
  def handle_invite
    # Some code getting the token and adding the user to a group
  end
end

Но это не лучший способ решить эту проблему, поскольку Ruby имеет горизонтальное наследование через модули:

# app/controllers/concerns/invitable.rb
module Invitable
  private

  def handle_invite
    # Some code getting the token and adding the user to a group
  end

  def after_sign_in_path(resource)
    handle_invite
    super(resource)
  end
end
# Do not use the scope resolution operator (::) for namespace definition!
# See https://github.com/rubocop-hq/ruby-style-guide#namespace-definition
module Users
  class SessionsController < ::Devise::SessionsController
    include Invitable
  end 
end
module Users
  class RegistrationsController < ::Devise::SessionsController
    include Invitable
  end 
end

Это известно как миксин модулей. На других языках, таких как Java или PHP, это будет называться чертой . Модуль инкапсулирует набор методов, которые могут быть включены в любой класс, а также вы можете смешивать модули с другими модулями. что каталоги app/controllers/concerns и app/models/concerns добавлены в корни автозагрузки. Это означает, что рельсы будут искать там константы в пространстве имен верхнего уровня.

Это также слабо связано с ActiveSupport :: Concern , который является синтаксисом c сахаром для обычных ruby идиомы . Но нет необходимости использовать его, если вы на самом деле не используете его функции.

...