Turbo-frame with Devise, after a successful update user, on page reload the turboframe does not render the appropriate html

Hi everyone,

I have a strange problem with Devise that I was not able to figure out after several hours so I decided to bring it up to you to have a little help on the mater.

I have a tab panel which uses a turbo_frame_tag to render different tabs that have forms inside them. On form submission if they are errors it works perfectly, the turbo frame is rerendered with the form and its errors associated. However, on a successful form submission for the Devise form (here editing the user), it reloads the page but it does not render the content of the turbo frame whereas my rails server says it is rendering the appropriate html :sweat_smile:

I am giving you some code details below to help you understand:

– Where I display my tab content –
GET /settings (users#settings, users/settings.html.slim)

section { ... }
  = render "shared/tab/navigation",
  = turbo_frame_tag "tab_content", src: edit_user_registration_path

I put src: edit_user_registration_path because that it my first tab, it does not work with or without it.

I have a user edit form on my first tab, the issue is only for the Devise tab, for the other controllers/actions it works fine. Here for my user registration#edit (I curated the html for better understanding):

– The view I want to display in my turbo frame –
GET /settings/notifications (hairdressers#notifications_settings, hairdressers/notifications_settings.html.slim)

= turbo_frame_tag "tab_content"
  section
    = form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class:  "..." }) do |f|
      # some inputs
      = button_tag type: "submit",
             class: "...",
             data: { disable_with: "Submitting..." }

– The controller responsible for handling the request and displaying the view –
My Devise user#registrations controller:

class Users::RegistrationsController < Devise::RegistrationsController
  # before_action :configure_sign_up_params, only: [:create]
  # before_action :configure_account_update_params, only: [:update]

  layout "sign_in_up", except: %i[edit update]

  # GET /resource/sign_up
  # def new
  #   super
  # end

  # POST /resource
  # def create
  #   super
  # end

  # GET /resource/edit
  # def edit
  #   super
  # end

  # PUT /resource
  # def update
  #   super
  # end

  # DELETE /resource
  # def destroy
  #   super
  # end

  # GET /resource/cancel
  # Forces the session data which is usually expired after sign
  # in to be expired now. This is useful if the user wants to
  # cancel oauth signing in/up in the middle of the process,
  # removing all OAuth session data.
  # def cancel
  #   super
  # end

  protected

  # If you have extra params to permit, append them to the sanitizer.
  # def configure_sign_up_params
  #   devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
  # end

  # If you have extra params to permit, append them to the sanitizer.
  # def configure_account_update_params
  #   devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
  # end

  # The path used after sign up.
  # def after_sign_up_path_for(resource)
  #   super(resource)
  # end

  # The path used after sign up for inactive accounts (ie not activated yet accounts)
  # That's our 'after_sign_up_path_for' because we ask users to activate their
  # account on sign up
  def after_inactive_sign_up_path_for(resource)
    users_welcome_path(resource_id: resource.id)
  end

  # CUSTOM: The path used after successful update.
  def after_update_path_for(resource)
    users_settings_path
  end
end

So, when I successfully update my informations as a user with this form form, it redirects me properly to the /settings routes, however it does not display the content of my turbo_frame_tag (here registrations#edit) BUT my rails server says so …

Started PUT "/users" for ::1 at 2022-08-24 19:30:45 +0200
Processing by Users::RegistrationsController#update as TURBO_STREAM
  Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"first_name"=>"Ulysse35", "last_name"=>"Benard1", "email"=>"mathieu@madeinvote.com", "phone_number"=>"06 59 86 98 64", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "current_password"=>"[FILTERED]"}}
  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  TRANSACTION (0.2ms)  BEGIN
  User Update (7.9ms)  UPDATE "users" SET "updated_at" = $1, "first_name" = $2 WHERE "users"."id" = $3  [["updated_at", "2022-08-24 17:30:45.644398"], ["first_name", "Ulysse35"], ["id", 1]]
  TRANSACTION (6.7ms)  COMMIT
Redirected to http://localhost:3000/settings
Completed 302 Found in 397ms (ActiveRecord: 15.7ms | Allocations: 7481)


Started GET "/settings" for ::1 at 2022-08-24 19:30:45 +0200
Processing by UsersController#settings as TURBO_STREAM
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/users_controller.rb:10:in `settings'
  Rendering layout layouts/application.html.slim
  Rendering users/settings.html.slim within layouts/application
  Rendered shared/tab/_link_item.html.slim (Duration: 23.6ms | Allocations: 786)
  Rendered shared/tab/_link_item.html.slim (Duration: 1.4ms | Allocations: 781)
  Rendered shared/tab/_link_item.html.slim (Duration: 3.8ms | Allocations: 781)
  Rendered shared/tab/_navigation.html.slim (Duration: 62.9ms | Allocations: 2577)
  Rendered users/settings.html.slim within layouts/application (Duration: 66.0ms | Allocations: 2870)
  Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 1.1ms | Allocations: 773)
  Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 1.1ms | Allocations: 773)
  Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 1.0ms | Allocations: 773)
  Rendered shared/buttons/_primary_compact_with_icon.html.slim (Duration: 2.4ms | Allocations: 772)
  Rendered shared/buttons/_primary_large_with_icon.html.slim (Duration: 0.5ms | Allocations: 773)
  Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
  Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
  Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
  Rendered shared/dropdown/_menu.html.slim (Duration: 0.3ms | Allocations: 363)
  Rendered shared/_navbar.html.slim (Duration: 8.7ms | Allocations: 5647)
  Rendered shared/_footer.html.slim (Duration: 1.1ms | Allocations: 21)
  Rendered layout layouts/application.html.slim (Duration: 77.9ms | Allocations: 9322)
Completed 200 OK in 85ms (Views: 78.4ms | ActiveRecord: 0.2ms | Allocations: 10645)


Started GET "/users/edit" for ::1 at 2022-08-24 19:30:45 +0200
Processing by Users::RegistrationsController#edit as HTML
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Rendering layout layouts/application.html.slim
  Rendering devise/registrations/edit.html.slim within layouts/application
  Rendered devise/shared/_password_field.html.slim (Duration: 1.0ms | Allocations: 896)
  Rendered devise/shared/_password_field.html.slim (Duration: 1.0ms | Allocations: 897)
  Rendered devise/shared/_password_field.html.slim (Duration: 0.5ms | Allocations: 895)
  Rendered shared/buttons/_submit_primary_large.html.slim (Duration: 1.7ms | Allocations: 779)
  Rendered devise/registrations/edit.html.slim within layouts/application (Duration: 7.2ms | Allocations: 5268)
  Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 0.6ms | Allocations: 773)
  Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 2.0ms | Allocations: 773)
  Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 0.5ms | Allocations: 773)
  Rendered shared/buttons/_primary_compact_with_icon.html.slim (Duration: 0.4ms | Allocations: 772)
  Rendered shared/buttons/_primary_large_with_icon.html.slim (Duration: 2.0ms | Allocations: 773)
  Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
  Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
  Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
  Rendered shared/dropdown/_menu.html.slim (Duration: 0.2ms | Allocations: 363)
  Rendered shared/_navbar.html.slim (Duration: 6.5ms | Allocations: 5647)
  Rendered shared/_footer.html.slim (Duration: 0.0ms | Allocations: 21)
  Rendered layout layouts/application.html.slim (Duration: 14.2ms | Allocations: 11710)
Completed 200 OK in 17ms (Views: 14.6ms | ActiveRecord: 0.2ms | Allocations: 13505)

and it seems that I receive well the turbo_frame response, just that it is not inserted properly, but probably I am missing something here

Any suggestion to solve this issue would be appreciated, do not hesitate to ask for further information …

If anyone gets the same problem someday, here is a clean solution I found to make it work :wink:

Just edit your registrations#edit and registrations#update actions with something like:

      def edit
        render turbo_stream: turbo_stream.replace("tab_content", partial: "devise/registrations/edit", locals: { resource: resource } )
      end

Do not forget to transform your devise/views/registration/edit view into a _edit partial, anyway it is what it was in my case.

By making your edit action responding with a turbo_stream you will be assured that it gets replaced accordingly.