はじめに
RailsAdminをバージョンアップするときに、割とヒントが少なかったので備忘録を書いておく
RailsAdminをアップグレードしたい
今回は3.0.0から3.3.0へのアップグレードをしてみる
Railsの準備
7.2.3をインストールしておく
% rails --version
Rails 7.2.3
プロジェクトを作成
rails _7.2.2_ new myapp
生成されたGemfileへ以下を記載
gem "rails_admin", "3.0.0"
bundle install すると、以下のメッセージが表示される
Post-install message from rails_admin:
### Upgrading RailsAdmin from 2.x.x to 3.x.x ###
Due to introduction of Webpack/Webpacker support, some additional dependencies and configuration will be needed.
Running `bin/rails g rails_admin:install` will suggest required changes, based on the current setup of your app.
メッセージに従って bin/rails g rails_admin:installを実行する
すると gem "sassc-rails" が追記されるので、念の為再度 bundle install
3.3.0へアップグレードする
Gemfileへ記載したバージョンを書き換える
gem "rails_admin", "3.3.0"
bundle installを実行する
問題なくgemがインストールされる
必要なファイルを生成するために bin/rails g rails_admin:install を実行すると以下のエラーが発生する
myapp % bin/rails g rails_admin:install
- Skipped route addition, since it's already there
insert config/initializers/rails_admin.rb
- Using [importmap] for asset delivery method
run yarn add rails_admin@3.3.0 from "."
create app/javascript/rails_admin.js
/Users/name/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/importmap-rails-2.2.2/lib/importmap/packager.rb:133:in `rescue in post_json': Unexpected transport error (OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 peeraddr=216.239.32.21:443 state=error: certificate verify failed (unable to get certificate CRL)) (Importmap::Packager::HTTPError)
これはRubyがうまくSSL認証をできていないことによるエラー
Gemfileに以下を追加する
gem "openssl"
そして bundle install して bin/rails g rails_admin:install する
すると次のエラーに進む
myapp % bin/rails g rails_admin:install
- Skipped route addition, since it's already there
unchanged config/initializers/rails_admin.rb
- Using [importmap] for asset delivery method
run yarn add rails_admin@3.3.0 from "."
identical app/javascript/rails_admin.js
/Users/name/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/rails_admin-3.3.0/lib/generators/rails_admin/importmap_formatter.rb:17:in `format': undefined method `gsub!' for nil (NoMethodError)
imports['@popperjs/core'].gsub!('lib/index.js', 'dist/esm/popper.js')
^^^^^^
from /Users/name/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/rails_admin-3.3.0/lib/generators/rails_admin/install_generator.rb:100:in `configure_for_importmap'
from /Users/name/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/rails_admin-3.3.0/lib/generators/rails_admin/install_generator.rb:33:in `install'
これは、 importmap_formatter.rbのformatで、
imports['@popperjs/core'].gsub!('lib/index.js', 'dist/esm/popper.js')
という行があるのだが、この importsは以下のようなハッシュになっている
{:imports=>
{"rails_admin"=>"https://ga.jspm.io/npm:rails_admin@3.3.0/src/rails_admin/base.js",
"@hotwired/turbo"=>"https://ga.jspm.io/npm:@hotwired/turbo@7.3.0/dist/turbo.es2017-esm.js",
"@hotwired/turbo-rails"=>"https://ga.jspm.io/npm:@hotwired/turbo-rails@7.3.0/app/javascript/turbo/index.js",
"@popperjs/core"=>"https://ga.jspm.io/npm:@popperjs/core@2.11.8/lib/index.js",
"@rails/actioncable/src"=>"https://ga.jspm.io/npm:@rails/actioncable@7.2.300/src/index.js",
"@rails/ujs"=>"https://ga.jspm.io/npm:@rails/ujs@6.1.710/lib/assets/compiled/rails-ujs.js",
"bootstrap"=>"https://ga.jspm.io/npm:bootstrap@5.3.8/dist/js/bootstrap.esm.js",
"flatpickr"=>"https://ga.jspm.io/npm:flatpickr@4.6.13/dist/esm/index.js",
"jquery"=>"https://ga.jspm.io/npm:jquery@3.7.1/dist/jquery.js",
"jquery-ui/ui/"=>"https://ga.jspm.io/npm:jquery-ui@1.13.3/ui/"}}
imports[:imports]["@popperjs/core"]が正しいところを、一つ上の階層で参照しようとしてエラーになってしまっている。
上記のコミットで修正されているが、まだリリースまでに至っていない
(詳しく調査していないけど、Importmap::Packager v2で破壊的変更が入った影響かなと推測している)
そのため、自前でモンキーパッチを当ててあげる必要がある
そして、これまたややこしいのが、def formatの呼び出しもとの install_generator.rbでは、 require_relative 'importmap_formatter'している
つまり、importmap_formatter.rbへモンキーパッチを当てようとしても、常にGem本体のimportmap_formatter.rbを参照してしまう(かなり泣)
config/initializers下に以下の2つのファイルを作成する
require 'generators/rails_admin/install_generator'
module RailsAdmin
module InstallGeneratorMonkeyPatch
def configure_for_importmap
puts "=============== configure_for_importmap_monkey_patch"
run "yarn add rails_admin@#{RailsAdmin::Version.js}"
template 'rails_admin.js', 'app/javascript/rails_admin.js'
require_relative 'rails_admin_importmap_formatter_monkey_patch'
add_file 'config/importmap.rails_admin.rb', ImportmapFormatter.new.format
setup_css
end
end
end
RailsAdmin::InstallGenerator.prepend RailsAdmin::InstallGeneratorMonkeyPatch
# frozen_string_literal: true
require 'importmap/packager'
module RailsAdmin
class ImportmapFormatter
attr_reader :packager
def initialize(path = 'config/importmap.rails_admin.rb')
@packager = Importmap::Packager.new(path)
end
def format
imports = packager.import("rails_admin@#{RailsAdmin::Version.js}", from: 'jspm.io')
imports = imports[:imports] if imports.key?(:imports)
# Use ESM compatible version to work around https://github.com/cljsjs/packages/issues/1579
imports['@popperjs/core'].gsub!('lib/index.js', 'dist/esm/popper.js')
# Tidy up jQuery UI dependencies
jquery_uis = imports.keys.filter { |key, _| key =~ /jquery-ui/ }
imports['jquery-ui/'] = imports[jquery_uis.first].gsub(%r{(@[^/@]+)/[^@]+$}, '\1/')
imports.reject! { |key, _| jquery_uis.include? key }
pins = ['pin "rails_admin", preload: true', packager.pin_for('rails_admin/src/rails_admin/base', imports.delete('rails_admin'))]
(pins + imports.map { |package, url| packager.pin_for(package, url) }).join("\n")
end
end
end
そして再度 bin/rails g rails_admin:installするとエラーが解決する。
終わりに
RailsAdmin周りのアップグレードはかなり腰が折れるので、なるべくこまめにアップグレードしよう。。。