ruby-on-railshotwire-rails

Trying to render partial but The response (500) did not contain the expected <turbo-frame id="">


Trying to learn this a bit, but keep running into new issues.

Currently, I have an 'explore' button that is supposed to run some controller code, and pop out a new _partial where it counts down and shows a new button. After the countdown, the 'complete' button is active and you press it, and it reupdates the #exploration contents and updates the user-info-land.

When I press the button, it doesn't work: see below.

Heres my controller:

class ExplorationController < ApplicationController
  before_action :authenticate_user!

  def status
    render partial: 'exploration_widget', locals: { user: current_user }
  end

  def explore
    timenow = Time.current
    if current_user.is_exploring
      redirect_to root_path, notice: "You are already exploring"
    else
      @explore_time = exploration_time
      if current_user.update(explore_start: timenow, explore_end: timenow + @explore_time, is_exploring: true)
        current_user.user_notifications.create(notification_id: 2, date1: timenow, date2: timenow + @explore_time)
        respond_to do |format|
          format.html { redirect_to root_path }
          format.turbo_stream { render partial: 'exploration_widget', locals: { user: current_user } }
        end
      else
        render plain: "Failed to update user", status: :internal_server_error
      end
    end
  end

  def complete
    if current_user.explore_end <= Time.current
      current_user.increment!(:land)
      current_user.update(is_exploring: false)
      respond_to do |format|
        format.html { redirect_to root_path, notice: 'Exploration complete! You gained 1 land.' }
        format.turbo_stream { render partial: 'exploration_widget', locals: { user: current_user } }
      end
    else
      render plain: 'Exploration not yet complete.', status: :bad_request
    end
  end

  private

  def exploration_time
    10.seconds
  end
end

And my view/exploration/

complete.turbo_stream.erb

<turbo-stream action="replace" target="exploration">
  <template>
    <%= render 'exploration_widget', user: current_user %>
  </template>
</turbo-stream>

<turbo-stream action="update" target="user-info-land">
  <template>
    <%= current_user.land %>
  </template>
</turbo-stream>

explore.turbo_stream.erb

<turbo-stream action="replace" target="exploration">
  <template>
    <%= render 'exploration_widget', user: current_user %>
  </template>
</turbo-stream>

views/shared/_exploration_widget.html.haml

%turbo-frame#exploration
  - if user.is_exploring?
    %div{"data-controller" => "exploration", "data-exploration-end-time-value" => "#{user.explore_end.iso8601}"}
      = form_with url: complete_exploration_path, method: :post, local: true, data: { turbo_frame: "exploration" } do
        %button.btn.btn-secondary{"data-exploration-target" => "completeButton", :disabled => "disabled"} Complete
      #exploration-timer
        Time remaining:
        %span#time-remaining{"data-end-time" => "#{user.explore_end.iso8601}", "data-exploration-target" => "timeRemaining"}= time_remaining(user.explore_end)
  - else
    = form_with url: start_exploration_path, method: :post, local: true, data: { turbo_frame: "exploration" } do
      = submit_tag 'Explore', class: 'btn btn-primary'

And my routes:

Rails.application.routes.draw do
  get 'test/index'
  root 'home#index'
  get 'structures', to: 'structures#index'
  post 'start_exploration', to: 'exploration#explore'
  post 'complete_exploration', to: 'exploration#complete'
  get 'exploration/status', to: 'exploration#status'
  resources :armies do
    post 'recruit', on: :collection
  end
  devise_for :users, controllers: {
    omniauth_callbacks: 'users/omniauth_callbacks'
  }
end

Heres the error in dev console

And the error in rails server:

ActionView::MissingTemplate - Missing partial exploration/_exploration_widget, application/_exploration_widget with {:locale=>[:en], :formats=>[:turbo_stream], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :haml, :jbuilder]}.

It seems like it should be working. I'm at a loss. If anyone can take a look and spot what is wrong here, thank you!


Solution

  • local: true is a Rails UJS attribute and is not used by Turbo.

    %turbo-frame#exploration also not needed, because your responses are turbo streams and you don't seem to actually use this frame anywhere else, you can replace it with a div.

    format.turbo_stream has to render a turbo stream, make sure you point to the correct partial:

    # note that `partial: 'exploration_widget'` will use you current controller name
    # to find the partial: `exploration/_exploration_widget`
    # if you have it in a different directory you need to specify it
    # `partial: 'shared/exploration_widget'`
    
    respond_to do |format|
      format.html { redirect_to root_path }
      format.turbo_stream do
        render turbo_stream: turbo_stream.replace(
          'exploration',
          partial: 'shared/exploration_widget',
          locals: {user: current_user}
        )
      end
    end
    

    or leave it as format.turbo_stream (without a block) to render a corresponding {action_name}.turbo_stream.erb view:

    respond_to do |format|
      format.html { redirect_to root_path }
      format.turbo_stream
    end