Rails 4 - разработка гостевых пользователей приводит к остановке цепочки фильтров
Я только начал работать над приложением Rails 4 (4.2.3), где я использую Devise
для аутентификации пользователя. Я хочу, чтобы пользователи могли поиграть с приложением, прежде чем подписывать upp, создав тестовый проект, и войти в него как гость. Когда пользователь регистрируется (или в), я хочу назначить тестовый проект новому текущему пользователю.
Я следовал этому руководству от Platformatec: https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user
Создание гостевого пользователя работает, но при регистрации или в сеансе активного гостевого пользователя я получаю следующую ошибку:
Filter chain halted as :require_no_authentication rendered or redirected
Если я очищаю свою сессию, это работает. Метод, который управляет моим гостевым пользователем, выглядит так:
def current_or_guest_user
if current_user
if session[:guest_user_id] && session[:guest_user_id] != current_user.id
logging_in
guest_user(with_retry = false).try(:destroy)
session[:guest_user_id] = nil
end
current_user
else
guest_user
end
end
Как уже упоминалось, создание гостевых пользователей, кажется, работает просто отлично. Но такой логики никогда не бывает:
# should delete the guest user and clear the session.
if current_user
if session[:guest_user_id] && session[:guest_user_id] != current_user.id
logging_in
guest_user(with_retry = false).try(:destroy)
session[:guest_user_id] = nil
end
current_user
Я почти уверен, что мой сеанс гостевого пользователя конфликтует с моим новым пользователем и вызывает эту ошибку Devise (так как гостевой пользователь никогда не удаляется при регистрации):
Filter chain halted as :require_no_authentication rendered or redirected
Остальная часть моей гостевой пользовательской логики выглядит более или менее точно так же, как это связанное руководство: https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user. Я также добавил код из параграфа / примера аутентификации: https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user.
Любые идеи о том, что мне не хватает, и как я могу получить свой current_or_guest_user
удалить гостевого пользователя при регистрации и подписи при использовании Devise?
Обновить
Вот так выглядят мои маршруты:
devise_for :users, controllers: { sessions: "users/sessions", registrations: "users/registrations" }
root :to => 'public#index'
resources :apps
get 'users/show', to: "users#show"
get 'users', to: "users#index"
post 'guests/receive_guest', to: "guests#receive_guest"
Обновление 2
В руководстве есть следующее утверждение:
Когда (и если) пользователь регистрируется или входит в систему, мы удаляем гостя и очищаем переменную сеанса.
Это не объясняет, как и где это сделать. Я думаю, мне нужно позвонить current_or_guest_user
где-то снова Но я не уверен, где, так как я не очень знаком с Devise.
Обновление 3
Чтобы было немного понятнее. Это шаги, которые я хочу достичь.
- Пользователь создает тестовый проект.
- При создании тестового проекта создается гостевой пользователь и сеанс. Гостевой пользователь должен быть удален после окончания сеанса или #3.
- Если гостевой пользователь регистрируется, он / она должен войти в систему, и тестовый проект должен быть назначен новому реальному пользователю.
- Гостевой пользователь должен быть удален.
3 ответа
Спасибо за ваши ответы skahlert и SsouLlesS. Пропуск стратегии надзирателя помог, а определение обратных вызовов кажется чистым подходом. Помимо этого у меня были некоторые другие проблемы.
Одним из них было то, что мои пользовательские контроллеры Devise никогда не вызывались. Для этого создан еще один вопрос: Rails 4 - devise_for, не использующий пользовательские контроллеры. Решение состояло в том, что я использовал неправильный URL в моей модальной форме регистрации. Моя форма теперь выглядит так:
= form_for(resource, as: resource_name, url: user_registration_path do |f|
Затем я сделал так, как предложил skahlert, и удалил стратегию надзирателя из моего приложения.
Однажды мой обычай придумать Users::RegistrationsController < Devise::RegistrationsController
позвонил контроллер, я решил переопределить действие создания. Он не полностью протестирован, но выглядит так:
# POST /resource
def create
# Delete guest user and reset session.
new_user_from_guest = guest_user
guest_user(with_retry = false).try(:destroy)
session[:guest_user_id] = nil
build_resource(sign_up_params)
resource.save
yield resource if block_given?
if resource.persisted?
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
# Assign the guest users app to the new current user.
new_user_from_guest.apps.each do |app|
app.user_id = current_user.id
app.save!
end
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
# Reset test user if signup fails, I have not tested this part yet.
guest_user
guest_user.apps << new_user_from_guest.apps
guest_user.save!
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
end
Кажется, все работает сейчас. Можно было бы провести некоторый рефакторинг и, возможно, попробовать метод обратного вызова, который SsouLlesS предложил в своем ответе.
Я думаю, что проблема вызвана стратегией надзирателя guest_user, упомянутой в руководстве. Так как Devise проверяет действительный сеанс надзирателя перед входом в систему, он вызывает перенаправление и флэш-сообщение:
if authenticated && resource = warden.user(resource_name)
flash[:alert] = I18n.t("devise.failure.already_authenticated")
redirect_to after_sign_in_path_for(resource)
end
Так что если вам строго не нужно это аутентифицировать! Метод для работы с гостевым пользователем, вы можете просто отключить эту стратегию, и она должна работать.
Приведенный выше ответ не имеет объяснения, loggin_in
метод не вызывается, потому что вы не определили свой обратный вызов
В вашем ApplicationController вам нужно определить и затем установить обратный вызов следующим образом:
define_callbacks :logging_in_user
set_callback :logging_in_user, :before, :transfer_guest_user_actions_to_current_user
def transfer_guest_user_actions_to_current_user
# todo
end
Вы пытались использовать драгоценный камень devise- guest? он реализует из коробки эту функциональность, а не делает это с нуля...
Проверьте этот пример контроллера, который реализует гостевой вход в систему. Надеюсь, поможет.