5

I'm having trouble setting up a Devise sign-up form using Turbo Frames. I'd like to have the Devise sign up form set up as a "gradual engagement" form that only requires email to register the new user from the homepage.

Here's how I've set this up so far:

  • First, I used this workaround to get the default Devise views working with Hotwire.
  • Then, I used this approach to get the devise signup form working on my homepage
  • Finally, I used this method to set up email-only signup with Devise.

That is all working as expected, but when the user complete's sign up it redirects and shows a flash page. Instead, I'd like to use Turbo Frames to just replace the form with a message like "Thank you for signing up" without reloading any page or doing a redirect.

Also, if there are any errors in the form (such as the email being blank) it redirects to the default devise sign up view and displays the errors there. I'd prefer this happens within the homepage frame so that there's no page reload when there's an error to display.

So, how would I do this with Devise and Turbo Frames?

Here's the form that's working on the homepage:

<%= form_for resource, :as => resource_name, :url => registration_path(resource_name), html: { class: "sm:flex" } do |form| %>
  <%= form.label :email, class: "sr-only" %>
  <%= form.email_field :email %>
  <div class="mt-3 rounded-md shadow sm:mt-0 sm:ml-3 sm:flex-shrink-0">
    <%= form.submit "Subscribe" %>
  </div>
<% end %>

And, to get that working I created a confirmations_controller.rb that overrides the default Devise::ConfirmationsController like this:

class ConfirmationsController < Devise::ConfirmationsController
  private
  def after_confirmation_path_for(resource_name, resource)
    sign_in(resource) # In case you want to sign in the user
    root_path
  end
end

Do I need to create a UsersController that overrides some parts of Devise to use turbo frames? How would I do this?

Lee McAlilly
  • 9,084
  • 12
  • 60
  • 94

1 Answers1

1

You're not going to be able to use after_X_path_for to accomplish this with Turbo. By the time you hit after_confirmation_path_for, my understanding is that Devise has already initiated a redirect, so it's too late to change to a Turbo response. These steps should get you closer:

  1. You need to enable Turbo on your form by adding the option data: { turbo: true }, or wrapping it in a turbo-frame element. You are seeing the full page reload and the flash message because this is missing.

  2. Your form (or a parent turbo-frame) need an ID for the Turbo response to target (i.e. the controller action needs to know which element to update).

  3. It appears that your form submission is handled by RegistrationsController. You will need to adjust the controller action (probably #create?) to have a block that actually renders a Turbo response, something like the following:

respond_to do |fmt|
  fmt.turbo_stream do
    render turbo_stream: turbo_stream.replace(
      form_element_id,
      partial: 'your_html_partial/here',
      locals: {
        current_user: your_user,
        other: "data"
      }
    )
  end
end

Lastly, this doesn't answer your question, but it will be much simpler to implement this without Devise, mainly because you're doing so much customization. Devise is best for limited customization (because, like Rails, it comes with very strong conventions). Implementing this flow should only involve a couple of controller actions (render the sign-in/sign-up form, handle form submission with Turbo stream).

aidan
  • 1,627
  • 17
  • 27