Rails: 覚書: 別画面からモデルの一部の項目だけを編集する

外観

目的
別画面からモデルの一部の項目だけを編集したい。

下記の要領でサンプルアプリを作成する。
管理者はモデルの全ての項目を編集できる。
会員は一部の項目だけを編集できる。

同じモデルを編集するのでフォームオブジェクトは不必要。
会員当人(Owner)をサブリソースとして、Rails: 覚書: DHH流のルーティングで実装する。また、ルーティングの命名と管理者権限が必要かどうかについては別の関心事として扱いadminを付けるようなことはしていない。

2021/03/05 追記
ルーティングを別ファイルに分ける場合は別のルーティングが良い気がしました。

環境
Ruby 2.7.2
Rails 6.1.3

画面

画像3

足場の準備

メーラーなどを使用しない設定でアプリを準備する。

rails new try_another_view -MCJT
cd try_another_view && tmux
bin/rails g scaffold Member \
name agreed:boolean \
admin_note:text admin_confirmed:boolean
bin/rails db:migrate

バリデーションを追加する。

app/models/member.rb
class Member < ApplicationRecord
   validates :name, presence: true, length: { maximum: 100 }
end

会員による編集

会員は赤枠の項目だけを更新できる。

画像1

ルーティングを加筆修正する。

config/routes.rb
Rails.application.routes.draw do
  resources :members do
    resource :owners, only: %i[edit update], module: 'members'
  end
end
#bin/rails routes -c Members::OwnersController
bin/rails routes -c owners
           Prefix Verb  URI Pattern                               Controller#Action
edit_member_owners GET   /members/:member_id/owners/edit(.:format) members/owners#edit
    member_owners PATCH /members/:member_id/owners(.:format)      members/owners#update
                  PUT   /members/:member_id/owners(.:format)      members/owners#update

一覧に会員編集用のリンクを追加する。

画像2

app/views/members/index.html.erb
      <th colspan="4"></th>
...
        <td><%= link_to 'Edit2', edit_member_owners_path(member) %></td>

コントローラーを生成する。

bin/rails g controller 'members/owners' \
edit \
--skip-routes --no-helper --no-assets

MembersControllerを参考に実装する。

app/controllers/members/owners_controller.rb
class Members::OwnersController < ApplicationController
  before_action :set_member, only: %i[edit update]

  def edit
  end

  def update
    if @member.update(member_params)
      redirect_to @member, notice: 'Member was successfully updated.'
    else
      render :edit, status: :unprocessable_entity
    end
  end

  private
    def set_member
      @member = Member.find(params[:member_id])
    end

    def member_params
      params.require(:member).permit(:name, :agreed)
    end
end

Membersのedit/_formビューを参考に実装する。
editのみで使用するので部分テンプレートは使用しない。
ローカル変数memberをインスタンス変数@memberに置き換える。
editビューのBackリンクを流用する。

app/views/members/owners/edit.html.erb
<h1>Editing Member</h1>

<%= form_with(model: @member, url: member_owners_url) do |form| %>
  <% if @member.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@member.errors.count, "error") %> prohibited this @member from being saved:</h2>

      <ul>
        <% @member.errors.each do |error| %>
          <li><%= error.full_message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.label :agreed %>
    <%= form.check_box :agreed %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

<%= link_to 'Back', members_path %>

以上です。



この記事が気に入ったらサポートをしてみませんか?