Search code examples
ruby-on-rails-7import-mapsturbo-railsrails-sprocketsjsbundling-rails

Upgrade Rails 6.1 > 7.0, add turbo-rails and importmap, gems do not install


I'm trying to upgrade a working legacy app to Rails 7, from Rails 6.1. I want to use Hotwire, so I added gem turbo-rails.

  • Ruby 3.1.2
  • zeitwerk
  • no webpacker
  • sprockets-rails
  • no modern JS yet
  • app passes tests
  • server boots locally

Added gem "turbo-rails", it bundles ok, and I booted the app. Cannot run rails turbo:install. Error is Don't know how to build task 'turbo:install'. That rake install task is not that important, but if i try to add <%= turbo_include_tags %> manually, i get undefined method. In rails console, the class Turbo is undefined.

Turbo needs something like importmap-rails if not using jsbundling or any other JS build tool, as suggested in the edge guides docs for version 7.1. (The guides for version 7.0 do not mention importmap, they are outdated — they talk about turbolinks, which is not even in Rails 7.)

Added importmap-rails, bundles OK, and I tried to run rails importmap:install. The first time, the task did execute. It adds <%= javascript_importmap_tags %> to the head, but when i boot the app, i get method undefined for that helper.

Then i remove and re-add the importmap-rails gem, it bundles OK, but the importmap:install task is not even available. In rails console, the class Importmap is undefined. Are these gems not getting installed properly? There are no error messages from bundle, and bundle doctor says No issues found. bundle info shows them installed.

How can I debug a gem that bundles, but its methods are unavailable?

My gemfile is like this, because we don't want to load ActiveStorage and a couple other gems in core Rails.

# gem("rails", "~> 7.0")

group :rails do
  gem("actioncable")
  # gem("actionmailbox")
  gem("actionmailer")
  gem("actionpack")
  # gem("actiontext")
  gem("actionview")
  gem("activejob")
  gem("activemodel")
  gem("activerecord")
  # gem("activestorage")
  gem("activesupport")
  gem("bundler")
  gem("importmap-rails")
  gem("railties")
  gem("sprockets-rails")
  gem("turbo-rails")
end

I assume I need to add gem turbo-rails here because i'm not just using gem rails, and it is not a listed dependency of any of the core component gems.


Solution

  • When you bundle install all gems listed in your Gemfile are installed - aka downloaded. To use them you have to require files you need.

    # config/application.rb
    
    require_relative "boot"
    
    # NOTE: this takes care of rails gems
    #       but you probably have individual requires here
    require "rails/all"
    
    # NOTE: nothing else in `group :rails` is required
    #       Rails.groups #=> [:default, Rails.env]
    Bundler.require(*Rails.groups)
    

    Move gems outside of the group:

    group :rails do
      gem("actioncable")
      # gem("actionmailbox")
      gem("actionmailer")
      gem("actionpack")
      # gem("actiontext")
      gem("actionview")
      gem("activejob")
      gem("activemodel")
      gem("activerecord")
      # gem("activestorage")
      gem("activesupport")
      gem("bundler")
      gem("railties")
    end
    
    # now you have your gems installed and required
    gem("sprockets-rails")
    gem("importmap-rails")
    gem("turbo-rails")
    

    https://bundler.io/guides/groups.html