Подтвердить что ты не робот

Devise - перенаправление страницы после подтверждения

Скажите, что пользователь нажимает ссылку на защищенную страницу. Затем они перенаправляются на экран знака, на котором они могут войти. Если они это сделают, они успешно перенаправляются на эту страницу. Но если у них нет учетной записи, они должны зарегистрироваться. Здесь все становится сложно, потому что я делаю подтверждение по электронной почте.

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

<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token, :redirect_to => stored_location_for(@resource)) %>

Но я не могу понять, как получить доступ к stored_location_for (или если это даже правильное место для получения). Он определен в Devise::Controllers::Helpers, но это метод экземпляра, поэтому я не могу сделать Devise::Controllers::Helpers.stored_location_for(…).

Мой вопрос в том, как получить доступ к stored_location_for ИЛИ каков наилучший способ сделать это?

Моя цель - это сделать, а затем в моем настраиваемом ConfirmationsController определите:

def show
  if params[:redirect_to]
    session["user_return_to"] = params[:redirect_to]
  end
  super

end

Это должно работать правильно?

4b9b3361

Ответ 1

Хорошо, я, наконец, понял это. Я не уверен, что это вообще изменилось с обновлением, которое Devise сделал вчера, когда Devise:: Mailer поместил большую часть своих функций в модуль (см. Код здесь и билет здесь).

В основном это сводится к невозможности доступа к session внутри представления почтовой программы. Поэтому вам нужно передать перенаправление в качестве переменной. Devise использует метод after_create на вашем ресурсе (User в моем случае), который затем отправляет письмо с подтверждением. Это означало, что я не мог просто передать переменную сеанса непосредственно почтовой программе. Таким образом, я чувствую, что это довольно неприятная работа, чтобы получить эту функциональность. Но вот код.

Итак, чтобы получить переменную redirect_to в почтовой программе, вам нужно добавить переменную пользователю. Таким образом:

class User < ActiveRecord::Base
  …
  attr_accessor :return_to
  …
end

Затем вы должны установить эту переменную при создании пользователя в первый раз. У меня уже была настраиваемая настройка контроллера для регистрации (см. Создание Readme о том, как это установить, или см. Ответ @ramc для направления). Но было довольно легко сделать эту часть, я просто добавил ее к параметрам, и пусть остальные позаботятся о себе.

class RegistrationsController < Devise::RegistrationsController
  def create
    params[:user][:return_to] = session[:user_return_to] if session[:user_return_to]
    …
    super
  end
end

Теперь пользователь имеет переменную return_to, которая установлена. Нам просто нужно получить доступ к этому в электронном письме confirm_instructions. Я уже переписал часть confirm_instructions.html.erb, поэтому внутри там я добавил:

<% if @resource.return_to %>
  <%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token, :redirect_to => @resource.return_to) %>
<% else %>
  <%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>
<% end %>

(для тех, кто не знаком с этим, @resource - это переменная, которую Devise использует для определения вашего пользователя).

Теперь, когда пользователь нажимает на эту ссылку, мы должны перенаправить их. @ramc до того, как фильтр хорошо работает для этого.

class ConfirmationsController < Devise::ConfirmationsController
  before_filter :set_redirect_location, :only => :show

  def set_redirect_location
    session[:user_return_to] = params[:redirect_to] if params[:redirect_to]
  end
end

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

Теперь нам просто нужно позаботиться о случае, когда пользователь делает это, но вместо того, чтобы нажимать на ссылку, они пытаются вернуться на защищенную страницу. В этом случае их просят зарегистрироваться/войти в систему. Они регистрируются, а затем просят подтвердить их электронную почту и им предоставляется возможность повторно отправить письмо с подтверждением. Они добавили свой адрес электронной почты, и теперь мы должны поместить переменную redirect_to в это новое электронное письмо с подтверждением.

Для этого нам нужно изменить ConfirmationController, аналогично тому, как мы сделали RegistrationController. На этот раз нам нужно изменить метод создания. Способ, которым это работает, состоит в вызове метода класса для пользователя с именем send_confirmation_instructions. Мы хотим переписать этот метод, чтобы мы могли передать в него переменную return_to.

class ConfirmationsController < Devise::ConfirmationsController
  def create
    self.resource = resource_class.send_confirmation_instructions(params[resource_name],session[:user_return_to])

    if resource.errors.empty?
      set_flash_message(:notice, :send_instructions) if is_navigational_format?
      respond_with resource, :location => after_resending_confirmation_instructions_path_for(resource_name)
    else
      respond_with_navigational(resource){ render_with_scope :new }
    end
  end
end

Единственное, что отличается от того, что приходит с разработкой, это первая строка создания. Мы передаем две переменные в. Теперь нам нужно переписать этот метод.

class User < ActiveRecord::Base
  def self.send_confirmation_instructions(attributes={},redirect=nil)
    confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
    confirmable.return_to = redirect if confirmable.persisted?
    confirmable.resend_confirmation_token if confirmable.persisted?
    confirmable
  end
end

confirmable становится экземпляром пользователя (текущий пользователь на основе электронной почты). Поэтому нам просто нужно установить return_to.

Что это.

Ответ 2

Взгляд на то, как файл stored_location_for был реализован в lib/devise/controllerlers/helpers.rb

def stored_location_for(resource_or_scope)
   scope = Devise::Mapping.find_scope!(resource_or_scope)
   session.delete("#{scope}_return_to")
end

В противном случае можно получить доступ к нему, используя session ['user_return_to']. В вашем случае вы потеряете этот объект сеанса, потому что, когда пользователь нажимает на ссылку из почты подтверждения, это может быть новый сеанс, который генерируется.

Вы можете реализовать все, что вы предложили, в качестве фильтра before:

class Users::ConfirmationsController < Devise::ConfirmationsController 
     before_filter :set_redirect_location, :only => :show

     def set_redirect_location
         session["user_return_to"] = params[:redirect_to] if params[:redirect_to]
     end
end

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

devise_for :users,
           :controllers => { :confirmations => 'users/confirmations'}

Надеюсь, что это поможет:)

Примечание. Фрагменты кода не являются полными и содержат только релевантные сведения.

Ответ 3

Из того, что я вижу из комментариев в исходном коде разработки, все, что вам нужно сделать, это реализовать в вашем registrations_controller.rb следующее:

def after_inactive_sign_up_path_for(resource_or_scope)
  session["user_return_to"]
end