ruby-on-railsruby-on-rails-5hotwire-railsturbo-frames

Finding the current URL or "main" controller from within a Turbo Frame in Rails


I have a Turbo Frame on my page which uses the src attribute to load in /chats/. Within this frame I want to be able to know whether the main page is using the show action of the groups controller, i.e. the URL of the page is at /groups/group_name.

Using current_page?(controller: 'groups', action: 'show') returns false as it sees itself as in the chats controller. How do I work around this?


Solution

  • Here are the options I've found:

    1. request.referrer

    There doesn't appear to be a built-in way of getting to the controller class / action in the way that you're describing, but you can access the URL of the page which initiated the Turbo request (groups_controller#show) through request.referrer. This will be the fully-qualified URL for the page, such as http://localhost:3000/groups/1/show.

    1. use query parameters

    This requires changes to view code (you must add query params to all links where you need this functionality), but it allows you to pass controller/action names and any other arbitrary data you'd like.

    Example:

    in application_controller.rb:

    # define a method to capture the information you wish to access during your Turbo stream request
    def current_route_info
      {
        path: current_path,
        controller: params[:controller],
        action: params[:action]
      }
    end
    

    No need to touch the groups controller in this example.

    in show.html.erb (the page which submits the Turbo request)

    <%= form_with url: turbo_view_path(info: current_route_info) do %>
    ...
    <% end %>
    OR
    <%= link_to turbo_view_path(info: current_route_info) do %>
    ...
    <% end %>
    OR
    <!-- you could also manually build the URL & encode the query params if you need to avoid URL helpers-->
    <turbo-frame id="" src=chats_partial_path(info: current_route_info)>
    ...
    <turbo-frame>
    

    chats partial controller (which handles the Turbo request)

    def turbo_view_method
      params[:info]
      # => info as defined in current_route_info
    end
    
    1. use flash

    I've just learned the many ways you can use flash for this type of functionality that extends across requests. This is less work than using query parameters, mainly because you don't need to adjust your view code.

    Example:

    groups controller (which renders the show view, which submits the Turbo requests)

    def show
      # stick the current controller and action params into flash
      # again, you can add any other arbitrary (primitive) data you'd like
      flash[:referrer] = params.slice(:controller, :action)
      ...
      ...
    end
    

    chats partial controller (which handles the Turbo requests)

    def chats_turbo_method
      flash[:referrer]
      # => { controller: "some_controller", action: "show" }
      # NOTE: flash will retain this :referrer key for exactly 1 further request.
      # If you require this info for multiple Turbo requests,
      # you must add:
      flash.keep(:referrer)
      # and you will have access to flash[:referrer] for as many Turbo requests as you want to make from group#show
    end