Tech Racho エンジニアの「?」を「!」に。
  • 開発

Rails: form_withで名前空間が異なるコントローラを簡潔に指定する方法

TL;DR

以下のようにurlを直接指定しなくても

<%= form_with model: @user, url: admin_users_path, local: true do |f| %>

こうやって簡潔に書けるよ

<%= form_with model: [:admin, @user], local: true do |f| %>

前提

環境

  • Rubyのバージョン: 2.5.1
  • Railsのバージョン: 5.2.0

フォルダ構成

  • app/
    • controllers/
      • admin/
        • users_controller.rb
    • models/
      • user.rb
    • views/
      • admin/
        • users/
          • new.html.erb

各ファイル概要

# users_controller.rb

class Admin::UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    @user.save!
  end

  private

  def user_params
    params.require(:user).permit(:name, :age)
  end
end
<!-- new.html.erb -->

<%= form_with model: [:admin, @user], local: true do |f| %>
  <%= f.text_field :name %>
  <%= f.text_field :age %>
  <%= f.submit %>
<% end %>

ポイント

form_withの引数に[:admin, @user]を渡すことです。
こうすることで,/admin/usersというurlをRailsが生成してくれます。

これまで私はこの方法を知らず,urlオプションにヘルパーを直接指定していました。

<!-- new.html.erb -->

<%= form_with model: @user, url: admin_users_path, local: true do |f| %>
  <%= f.text_field :name %>
  <%= f.text_field :age %>
  <%= f.submit %>
<% end %>

冗長ですね。何度かこの方法で実装した後に,もう少しスマートにかけるのでは?と思いform_withのコードを読んだところ,しっかりコメントしてありました。

# For namespaced routes, like +admin_post_url+:
#
#   <%= form_with(model: [ :admin, @post ]) do |form| %>
#     ...
#   <% end %>

冗長だなーって思ったときは,きっとより良い書き方をRailsが用意してくれているはずなので,コードを見にいったり,公式ドキュメントを読んだりするのは大切ですね。

まとめ

  • コントローラの名前空間をわけたときは,form_withのキーワード引数(model:)に配列を指定すると,いい感じにurlを解決してくれます
  • コードを書いていて違和感を覚えたら,もっといい書き方がないか調べてみると良いかもしれません
    • (これはまとめというか自戒です)

関連記事

Rails 5.1〜: ‘form_with’ APIドキュメント完全翻訳


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。