Madogiwa Blog

主に技術系の学習メモに使っていきます。

`vscode-standard-ruby`でプリインストールのrubyが利用されてしまうのを直した時のメモ📝

vscode-standard-rubyでプリインストールのrubyで実行されてしまいパッケージマネージャーで関しているバージョンで実行されずLSPが落ちてしまいハマったので対応したことをメモ📝

github.com

事象

以下のようにターミナルで確認するとパッケージマネージャで管理している最新のRubyが利用されているが、

$ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin22]

vscode-standard-rubyのLSPの起動時に以下の通り謎にプリインストールのrubyが利用されてしまっており失敗していた。

[client] stderr:
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems.rb:283:in `find_spec_for_exe': Could not find 'bundler' (2.4.10) required by your /Users/morita.jun/Documents/repo/dogfeeds/Gemfile.lock. (Gem::GemNotFoundException)

解決方法

以下の設定が入っていたので削除し、ターミナルで利用しているもの(zsh)が利用されるようにした。

- "terminal.integrated.defaultProfile.osx": "bash"

そしてVSCodeを単純に再起動するのではなく、ターミナルからcodeコマンドでVSCodeを再起動するとパッケージマネージャで管理しているRubyが利用されLSPの起動に成功した🤔

[server] Standard Ruby v1.32.0 LSP server initialized, pid 81066

"terminal.integrated.defaultProfile.osx": "bash"の設定によりbashで最初起動してしまったので、zshのターミナルで再起動するまではパッケージマネージャーの設定が無いbashが利用されてしまいプリインストールのRubyが使われてしまっていたっぽい?(VSCodeは起動時のShellの設定を引き継ぐ?)

参考

qiita.com

rbenv+nodebrewからasdfに移行したので作業メモ📝

rbenv+nodebrewからasdfに移行してみたのでやったことをメモしておきます📝

github.com

asdfインストール

公式はgit cloneの方法のようだが、homebrewからinstallできるようなのでinstall

https://asdf-vm.com/guide/getting-started.html#_2-download-asdf

$ brew install asdf

以下に従ってbrew + zshのinstallコマンドを実行 https://asdf-vm.com/guide/getting-started.html#_3-install-asdf

$ echo -e "\n. $(brew --prefix asdf)/libexec/asdf.sh" >> ${ZDOTDIR:-~}/.zshrc

出来た🆗

$ asdf --version
v0.13.1

asdfrubyを管理

asdfruby pluginを追加

$ asdf plugin add ruby 

install可能なrubyのバージョンを確認

$ asdf list-all ruby

任意のバージョンのrubyのinstall

$ asdf install ruby 3.2.2

任意のバージョンのrubyのグローバル利用

$ asdf global ruby 3.2.2

出来た🆗

$ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin22]

rbenv uninstall

rbenvは不要なので削除しておく

$ brew uninstall rbenv
$ rm -rf ~/.rbenv 

.zshrcから以下も削除

# for rbenv
eval "$(rbenv init - zsh)"

asdfでnodeを管理

asdfのnodeプラグインを追加

$ asdf plugin add nodejs 

インストール可能なnodeの一覧を表示

$ asdf list-all nodejs

任意のバージョンのnodeをinstall

$ asdf install nodejs 18.18.2

任意のバージョンのnodeをグローバル利用

$ asdf global nodejs 18.18.2

出来た🆗

$ node -v
v18.18.2

nodebrew uninstall

$ brew uninstall nodebrew
$ rm -rf ~/.nodebrew 

.zshrcから以下も削除

# for nodebrew
export PATH=$HOME/.nodebrew/current/bin:$PATH

参考

scrapbox.io

https://asdf-vm.com/guide/getting-started.html#_4-install-a-plugin

Ruby on Rails: テスト用にrouteを動的に追加するメモ📝

テスト用にRoutingを動的にいじってテストしたいことがたまにあるのでやり方をメモ📝

まず以下のようなテスト用のhelperを用意します。 中でやっていることは動的にrouteを追加するdraw_test_routesとそれをリセットするreload_routes!を実装しています。

module RoutesHelper
  def draw_test_routes(&block)
    Rails.application.routes.disable_clear_and_finalize = true

    Rails.application.routes.draw do
      instance_exec(&block)
    end
  end

  def reload_routes!
    Rails.application.reload_routes!
  end
end

Rails.application.routes.disable_clear_and_finalize = trueをすることで以下のroutesのclearやfinalizeを無効化してroutesを固定化させず、動的に追加したものを初期化させないようにします。

https://github.com/rails/rails/blob/v7.1.2/actionpack/lib/action_dispatch/routing/route_set.rb#L428-L433

またRails.application.reload_routes!を実行することで、clear!し再読み込みされfinalize!することで動的に追加したroutesを削除するとともにRails.application.routes.disable_clear_and_finalizeがfalseに再設定されるので、元に戻ります。

https://github.com/rails/rails/blob/v7.1.2/railties/lib/rails/application/routes_reloader.rb#L22-L29

以下の通り、任意のcontrollerを使って動的にrouteを追加することができました🎉

require "spec_helper"
require_relative "../../test/support/routes_helper"

class TestsController < ActionController::Base
  def index
    head :ok
  end
end

describe "GET /test", type: :request do
  include RoutesHelper

  before(:example) do
    draw_test_routes do
      get "/tests", to: "tests#index"
    end
  end

  after(:example) do
    reload_routes!
  end

  it "success" do
    get "/tests"
    expect(response).to have_http_status :ok
  end
end

参考

techracho.bpsinc.jp

Ruby on Rails: メーラー関連のファイルを`app/mailers`に集約するメモ📝

Ruby on RailsメーラーのViewはデフォルトでapp/views配下に置かれてしまい数が多くなってくるとControllerからrenderされるものとMailerからrenderされるものが混在してしまい見通しが悪くなるケースがあります。

メーラーのビューは app/views/name_of_mailer_class ディレクトリに置かれます。
Action Mailer の基礎 - Railsガイド

そういうわけでメーラー関連のファイルはapp/mailers配下に集約する方法をメモ📝

やり方

目指す姿は以下のような感じで、mailer配下にviewsを持ち、そこにlayoutや各mailerのviewを配置することを目指します。

app/mailers
├── application_mailer.rb
├── sample_mailer.rb
└── views
    ├── layouts
    │   ├── application_mailer.html.erb
    │   └── application_mailer.text.erb
    └── sample_mailer
        ├── sample_mail.html.erb
        └── sample_mail.text.erb

やり方は、そこまで難しくなくて以下のようなApplicationMailerを用意してあげるだけで大丈夫でした!

class ApplicationMailer < ActionMailer::Base
  default from: "from@example.com"
  layout Rails.root.join("app/mailers/views/layouts/application_mailer")
  prepend_view_path "app/mailers/views"
end

layout Rails.root.join("app/mailers/views/layouts/application_mailer")app/mailers内のlayout用のファイルを参照するようにし、

別のレイアウトファイルを明示的に指定したい場合は、メーラーでlayoutを呼び出します。
Action Mailer の基礎 - Railsガイド

prepend_view_path "app/mailers/views"でviewの参照パスにapp/mailers/viewsを追加しています。

prepend_view_pathメソッドやappend_view_pathメソッドを用いることで、パスの解決時に優先して検索される別のディレクトリを追加できます。
Action View の概要 - Railsガイド

参考

techracho.bpsinc.jp

VSCodeの`rebornix.ruby`から`shopify.ruby-lsp`に乗り換えるメモ

今までVSCodeRubyを使うときにはrebornix.rubyを使うことが多かったと思うのですが、

marketplace.visualstudio.com

現状は非推奨となっており、

Shopify's ruby-lsp and associated vscode-ruby-lsp are recommended alternatives to this extension. It is substantially easier to produce a high-quality LSP implementation using Ruby itself vs relying on another language such as TypeScript. GitHub - rubyide/vscode-ruby: Provides Ruby language and debugging support for Visual Studio Code

推奨されているshopify.ruby-lspに乗り換えてみたのでメモ📝

marketplace.visualstudio.com

乗り換えは簡単でVSCode拡張機能からinstallした後にGemfileにruby-lspを追加してbundle installすれば大丈夫でした🙆‍♂️

group :development do
  gem "ruby-lsp"

Gemfileに入れないとエラーになったのでGemfileに入れましたが、公式のReadme的には起動時に.ruby-lsp配下にGemfileが追加されてよしなに利用されるため不要なようです。(自分はなぜか動かなかった・・・)

NOTE: starting with v0.7.0, it is no longer recommended to add the ruby-lsp to the bundle. The gem will generate a custom bundle in .ruby-lsp/Gemfile which is used to identify the versions of dependencies that should be used for the application (e.g.: the correct RuboCop version).
GitHub - Shopify/ruby-lsp: An opinionated language server for Ruby

あとは私はrubocopじゃなくてstarndardrbを利用しているのですが、Ruby LSPが出すrubocopの警告は不要のためdiagnosticsfalseにしました。

  "rubyLsp.enabledFeatures": {
    "diagnostics": false,

これでいい感じにコードジャンプ等が動くようになりました💎

あとrails用のもあるらしい。

github.com

ShopfyこういったRubyの基盤的な技術もOSSで提供してくれていてありがたい🙏

参考)

code.visualstudio.com

Ruby on Rails: 個人のサービスをRails v7.1にアップデートしたのでやったこととかメモ📝

2023/10/05にRuby on Rails v7.1がリリースされました🎉

rubyonrails.org

個人のwebサービスなので以下のように規模はかなり小さめですがやったこととかをメモ📝

+----------------------+--------+--------+---------+---------+-----+-------+
| Name                 |  Lines |    LOC | Classes | Methods | M/C | LOC/M |
+----------------------+--------+--------+---------+---------+-----+-------+
| Controllers          |    572 |    425 |      21 |      71 |   3 |     3 |
| Helpers              |     51 |     37 |       0 |       8 |   0 |     2 |
| Jobs                 |     31 |     23 |       3 |       2 |   0 |     9 |
| Models               |   1100 |    712 |      32 |     102 |   3 |     4 |
| Mailers              |      6 |      4 |       1 |       0 |   0 |     0 |
| Views                |    393 |    371 |       0 |       0 |   0 |     0 |
| JavaScript           |   3033 |   2195 |       0 |       2 |   0 |  1095 |
| Libraries            |    262 |    214 |       5 |      18 |   3 |     9 |
+----------------------+--------+--------+---------+---------+-----+-------+
| Total                |   5448 |   3981 |      62 |     203 |   3 |    17 |
+----------------------+--------+--------+---------+---------+-----+-------+

やったこと

installするRailsのバージョンを更新

dependabotのPRが作成されていたので、それを利用しました🤖

bundle update --conservativeを使って最低限のgemだけあげた方が安全。

--conservative Use bundle install conservative update behavior and do not allow indirect dependencies to be updated. https://bundler.io/v2.4/man/bundle-update.1.html

設定周りをRails v7.1に合わせて更新

config.load_defaults 7.1に更新してRails 7.1の設定を反映するようにしたのと、 Rails v7.1時のRails newのdiffを確認し以下の変更を追加した。

https://railsdiff.org/7.0.8/7.1.0

config.autoload_libのignoreオプションを利用するように修正

config.autoload_lib(ignore:)という新しい設定メソッドが導入されました。 このメソッドは、デフォルトでは自動読み込みパスに含まれていないlibディレクトリをアプリケーションの自動読み込みパスに追加するために利用されます。 また、新しいアプリケーションではconfig.autoload_lib(ignore: %w(assets tasks))が生成されます。 https://railsguides.jp/v7.1/7_1_release_notes.html

config.cache_classesconfig.enable_reloadingに変更

3.2.13 config.cache_classes 後方互換性のためにサポートされている古い設定であり、!config.enable_reloadingと同等です。 https://railsguides.jp/configuring.html

config.action_controller.raise_on_missing_callback_actionsをtrueに設定

onlyやunlessで既存のメソッドに存在しないシンボルを指定した場合にコールバックでエラーを発生するようになった。 https://techracho.bpsinc.jp/hachi8833/2023_09_27/135156

config.active_job.verbose_enqueue_logsをtrueに設定

3.15.8 config.active_job.verbose_enqueue_logs バックグラウンドジョブをエンキューするメソッドのソースコードの場所を、 関連するエンキューログ行の下にログ出力するかどうかを指定します。 デフォルトは、development環境ではtrue、それ以外の環境ではfalseです。 https://railsguides.jp/configuring.html

config.action_dispatch.show_exceptions:rescuableに設定

Deprecate true and false values for config.action_dispatch.show_exceptions in favor of :all, :rescuable, or :none. https://edgeguides.rubyonrails.org/7_1_release_notes.html#action-pack-deprecations

警告が出ている部分のFIX

アプリケーション起動時に以下のような警告が出ていましたが、どちらもDevise起因ぽかったので一旦無視しました。

DEPRECATION WARNING: DeprecatedConstantAccessor.deprecate_constant without a deprecator is deprecated (called from <top (required)> at /app/config/application.rb:16)
DEPRECATION WARNING: `Rails.application.secrets` is deprecated in favor of `Rails.application.credentials` and will be removed in Rails 7.2. (called from <top (required)> at /app/config/environment.rb:7)

DeprecatedConstantAccessor.deprecate_constant側はissueが上がっている模様。

github.com

DEPRECATION WARNINGの調査はconfig.active_support.deprecation = :raise にするとスタックトレースが出るので発生箇所が調査しやすい。

おわりに

Rails v7.1はasync queriesや複数主キーのサポートなどいい感じの機能が楽しみですね✨

参考

techracho.bpsinc.jp

inside.pixiv.blog

Ruby on Rails: Content Security Policyを使ってみたのでMEMO

Ruby on Rails 5.2からContent Security Policyヘッダーを設定するDSLが提供されました。

2.5 Content Security Policy
Rails 5.2 ships with a new DSL that allows you to configure a Content Security Policy for your application. You can configure a global default policy and then override it on a per-resource basis and even use lambdas to inject per-request values into the header such as account subdomains in a multi-tenant application. You can read more about this in the Securing Rails Applications guide.
Ruby on Rails 5.2 Release Notes — Ruby on Rails Guides

今更ながら個人のサービスに適用してみたので使い方とかをメモ📝

Content Security Policyとは?

HTTP の Content-Security-Policy レスポンスヘッダーは、ウェブサイト管理者が、あるページにユーザーエージェントが読み込みを許可されたリソースを管理できるようにします。いくつかの例外を除いて、大半のポリシーにはサーバーオリジンとスクリプトエンドポイントの指定を含んでいます。これはクロスサイトスクリプティング攻撃 (クロスサイトスクリプティング) を防ぐのに役立ちます。 Content-Security-Policy - HTTP | MDN

上述の通りレンスポンスヘッダーでクライアントがロードするリソースの許可条件を設定できる機能ようです。

CSP を有効にするには、ウェブサーバーから Content-Security-Policy HTTP ヘッダーを返すように設定する必要があります 他にも、 要素を用いてポリシーを指定することも可能です。例を挙げます。 コンテンツセキュリティポリシー (CSP) - HTTP | MDN

設定するにはHTTPヘッダーまたはmetaタグでポリシーに記述することで行えます。

# HTTPヘッダーでContent-Security-Policyを返すようにする
Content-Security-Policy: default-src 'self'
# or metaタグを設定する
<meta http-equiv="Content-Security-Policy" content="default-src 'self' />

Ruby on RailsでContent Security Policyを設定する

Ruby on RailsではDSLを使ってContent-Security-Policy HTTP ヘッダーの内容及びCSP関連の振る舞いを指定することができます。

Rails.application.configure do
  config.content_security_policy do |policy|
    policy.default_src :self, :https # 同一オリジン OR httpsで取得するリソースのみ許可
    policy.script_src :strict_dynamic # nonceにより検証が成功したリソースのみを許可
  end

  # Generate session nonces for permitted importmap and inline scripts
  config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } # session_idをnonceの取得元として使用する
  config.content_security_policy_nonce_directives = %w[script-src] # JavaScriptはnonceによる検証の対象にする

  # Report CSP violations to a specified URI. See:
  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
  config.content_security_policy_report_only = true # CSP違反があってもエラーとしない
end

cssstrict_dynamicにしたい場合にはpolicy.style_src :strict_dynamicにし、content_security_policy_nonce_directives = %w[script-src style-src]を指定するようにすれば良い。 ※ Viteを利用している場合には制約上、script_src: unsafe-eval, style_src: unsafe-inlineを許可する必要がある(?)ようです Link

nonceの付与はjavascript_include_tag等であればnonce: trueを指定すれば自動的に付与できますが、 scriptタグを直接記載しているときにはcontent_security_policy_noncenonceを取得することもできるので直接指定することもできます。

<script nonce="<%= content_security_policy_nonce %>">

おわりに

Ruby on Rails、こういうのを簡単に指定できて非常に便利ですね 🚃

参考

zenn.dev

railsguides.jp