railsで管理者画面のあれやこれ
メモと整理がてら記載します。
docker環境で実施していることを前提としています。
docker-compose exec web rails g controller admin/products index show new edit --no-helper
model
下記コマンドでモデルの作成を行う
docker-compose exec web rails g model Product name description:text price:integer
作成したファイルの中身はこんな感じ
create_table "products", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "name" t.text "description" t.integer "price" end
下記コマンドを実行して上記で確認したテーブルを作成する
rails db:migrate
routes
上記実施後config/routes.rb
にて下記を確認します。
※今回は下記画面のみの作成になります。
- 商品一覧
- 商品作成
- 商品編集
- 商品削除(一覧画面から削除できるように)
Rails.application.routes.draw do namespace :admin do # []内のアクション以外を使うという意味を表す resources :products, except: [:show] end
namespace :admin do ~~ end
まで囲まれている部分はadmin/
が付与されます
下記のようGETした際はadmin/products#xxxx
がルートして呼び出されるようになります。
docker-compose exec web rails routes | grep products admin_products GET /admin/products(.:format) admin/products#index POST /admin/products(.:format) admin/products#create new_admin_product GET /admin/products/new(.:format) admin/products#new edit_admin_product GET /admin/products/:id/edit(.:format) admin/products#edit admin_product PATCH /admin/products/:id(.:format) admin/products#update PUT /admin/products/:id(.:format) admin/products#update admin_product DELETE /admin/products/:id(.:format) admin/products#destroy
なぜnewとcreateの2つも必要なのか?と思ったが、
理由はnew
アクションでフォームを、そのフォームをcreate
でデータの保存等を行うとのことらしい。
他にもedit
も同様に、edit
でフォームを、update
でデータの更新等を行う。
controller
adimin/products_controller.rb
# frozen_string_literal: true module Admin class ProductsController < ApplicationController before_action :basic_auth before_action :set_product, only: %i[update edit destroy] def index @products = Product.all end def new @product = Product.new end def update if @product.update(product_params) redirect_to ({ action: :index }), notice: 'Product was successfully updated.' else render :edit, status: :unprocessable_entity end end def create @product = Product.new(product_params) if @product.save redirect_to ({ action: :index }), notice: 'Product was successfully create.' else render(:new) end end def edit; end def destroy @product.destroy redirect_to ({ action: :index }), notice: 'Product was successfully destroyed.' end private def set_product @product = Product.find(params[:id]) end def product_params params.require(:product).permit(:name, :description, :price, :image) end def basic_auth authenticate_or_request_with_http_basic do |username, password| username == 'admin' && password == 'pw' end end end end
XXXX_path
は各画面に遷移することを示す
routesファイルに記載のあるやつで、xxx_pathとつければその画面に飛ぶ
before_action :set_product, only: %i[update edit destroy]
を使って何度もコードを記載するのを防いでます。(DRY)
after_action
もあるので良ければ調べてみよう。
編集画面だけを紹介
<section class="py-5"> <%= form_with(model: @product, url: admin_product_path(@product), local: true) do |f| %> <div class="form-floating"> <%= f.text_area :name, class: 'form-control', id: 'floatingName', placeholder: 'Enter product name' %> <%= f.label :name, 'Name', for: 'floatingName' %> </div> <div class="form-floating"> <%= f.text_area :description, class: 'form-control', id: 'floatingDescription', placeholder: 'Enter product name' %> <%= f.label :description, 'Description', for: 'floatingDescription' %> </div> <div class="form-floating"> <%= f.number_field :price, class: 'form-control', id: 'floatingPrice', placeholder: 'Enter product price' %> <%= f.label :price, 'Price', for: 'floatingPrice' %> </div> <div class="form-floating"> <%= f.file_field :image, class: 'form-control', id: 'floatingImage' %> <%= f.label :image, 'Image', for: 'floatingImage' %> </div> <%= f.submit "更新", class: 'btn btn-primary' %> <% end %> </section>
<%= form_with(model: @product, url: admin_product_path(@product), local: true) do |f| %>
model:
にはフォームで作成または編集される具体的なインスタンスを指定(コントローラのアクション内で設定)
編集画面では、通常update
アクションが呼び出される(更新ボタン押下時)ので、url:
にはそのパス(admin_product_path(@product))を指定します。
流れ的にはこんな感じ
form_withで指定されたurl: のパス(このケースでは admin_product_path(@product)
)に対してHTTP POST(新規作成)
またはPATCH(更新)
リクエストを送信
↓
Railsのルーティングシステムは、そのリクエストを適切なコントローラとアクション(この場合は ProductsControllerのupdate
アクション)にルーティング
↓
update
アクション内で @product.update(product_params)
が呼び出される
これにより、フォームから送信されたデータを使用して @product オブジェクトが更新されます。
↓
update
メソッドが成功すれば(つまり、バリデーションにパスすれば)、 redirect_to(admin_products_path(@product))
が呼び出され、ユーザは @product のビューにリダイレクトされます。
update
メソッドが失敗した場合(つまり、バリデーションに失敗した場合)、 render(:edit) が呼び出され、ユーザは同じ edit ビューに留まり、エラーメッセージが表示されます。
以上、メモがてらのあれやこれでした。