管理画面のCRUD作成
CRUD作成
以下のような、管理画面に掲示板とユーザーのCRUD(Create(生成)、Read(読み取り)、Update(更新)、Delete(削除))機能を作成する。
ルーティング
namespace :admin do root to: 'dashboards#index' resources :users, only: %i[index show edit update destroy] resources :boards, only: %i[index show edit update destroy] get 'login', to: 'user_sessions#new' post 'login', to: 'user_sessions#create' delete 'logout', to: 'user_sessions#destroy' end
掲示板のCRUD作成
掲示板一覧では、ID、タイトル、作成者、作成日の項目を表示させる。
それぞれに対して「詳細」「編集」「削除」ボタンの項目を表示させ、削除時には確認アラートを表示させる。
controller
boards_controllerの作成
$rails g controller admin::boards
継承元をbase_controler
にする。
ransack
で検索機能をつける。→参考
class Admin::BoardsController < Admin::BaseController before_action :set_board, only: %i[edit show update destroy] def index @q = Board.ransack(params[:q]) @boards = @q.result(distinct: true).includes(:user).order(created_at: :desc).page(params[:page]) end def edit; end def show @board = Board.find(params[:id]) @comment = Comment.new @comments = @board.comments.includes(:user).order(created_at: :desc) end def update if @board.update(board_update_params) redirect_to admin_board_path(@board), success: '掲示板を更新しました' else flash.now['danger'] = '編集に失敗しました' end end def destroy @board.destroy! redirect_to admin_boards_path, success: '掲示板を削除しました' end private def board_update_params params.require(:board).permit(:title, :body, :user_id, :board_image, :board_image_cache) end def set_board @board = Board.find(params[:id]) end end
掲示板一覧のviewを作成
パーシャルを使い一覧画面を表示させる。
<%= content_for(:title, t('.title')) %> <div class="container mb-5 pt-2"> <h1>掲示板一覧</h1> <div class="row"> <div class="col-md-12 mb-3"> <%= render 'search_form' %> </div> </div> <div class="row"> <div class="col-sm-12"> <table class="table table-striped"> <thead> <tr> <th>ID</th> <th>タイトル</th> <th>作成者</th> <th>作成日時</th> <th></th> </tr> </thead> <tbody> <%= render @boards %> </tbody> </table> </div> </div> <div class="row"> <div class="col-sm-12"> <!-- ページネーション --> <%= paginate @boards %> </div> </div> </div>
検索機能のパーシャル
<%= search_form_for @q, url: boards_path do |f| %> <div class="row"> <div class="form-inline align-items-center mx-auto"> <div class="col-auto"> <%= f.search_field :title_or_body_cont, placeholder:'検索ワード', class:'form-control' %> </div> <div class="col-auto"> <%= f.date_field :created_at_gteq, include_blank: true, class:'form-control' %> 〜 <%= f.date_field :created_at_lteq_end_of_day, include_blank: true, class:'form-control' %> </div> <div class="col-auto"> <%= f.submit '検索', class:'btn btn-primary' %> </div> </div> </div> <% end %>
リンクなどのパーシャル
<tr> <td> <%= board.id %> </td> <td> <%= link_to board.title, admin_board_path(board) %> </td> <td> <%= board.user.decorate.full_name %> </td> <td> <%= l board.created_at, format: :long %> </td> <td> <%= link_to '詳細', admin_board_path(board), class:"btn btn-info" %> <%= link_to '編集', edit_admin_board_path(board), class:"btn btn-success" %> <%= link_to '削除', admin_board_path(board), method: :delete, data: { confirm: '本当に削除しますか?' }, class:"btn btn-danger" %> </td> </tr>
編集画面のview
form_withの書き方
<%= form_with model: @board, url: admin_boards_path, local: true do |f| %>
とURLを指定しなくても、簡潔に書ける。
<%= form_with model: [:admin, @board], local: true do |f| %>
form_withの引数に[:admin, @board]を渡すことで、
/admin/boardsというurlをRailsが生成してくれる。
<% content_for(:title, @board.title) %> <div class="container"> <div class="row"> <div class="col-md-10 offset-md-1 col-lg-8 offset-lg-2"> <h1><%= t('.title') %></h1> <%= form_with model: [:admin, @board], local: true do |f| %> <%= render 'shared/error_messages', object: f.object %> <div class="form-group"> <%= f.label :title, Board.human_attribute_name(:title) %> <%= f.text_field :title, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :body, Board.human_attribute_name(:body) %> <%= f.text_area :body, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :board_image %> <%= f.file_field :board_image, onchange: 'previewImage()', class: 'form-control mb-3', accept: 'image/*' %> <%= f.hidden_field :board_image_cache %> </div> <div class='mt-3 mb-3'> <%= image_tag @board.board_image.url, id: 'preview', size: '300x200' %> </div> <%= f.submit class: 'btn btn-primary' %> <% end %> </div> </div> </div>
詳細画面のview
<%= @board.user.decorate.full_name %>
user_decorator.rb
のfull_name
メソッドを呼び出し、ユーザー名を表示する。
<%= l @board.created_at, format: :long %>
l
メソッドはi18nにおいて日付や時刻を表す際に使用する。
config/locales/ja.ymlに書かれた内容を読み込む。
formatオプションを使うことで複数の書式を使い分けることができる。
<% content_for(:title, @board.title) %> <div class="container"> <div class="row"> <div class="col-md-10 offset-md-1 col-lg-8 offset-lg-2"> <h1><%= t('.title') %></h1> <div class="text-right mb-3"> <%= link_to '編集', edit_admin_board_path(@board), class:"btn btn-success" %> <%= link_to '削除', admin_board_path(@board), method: :delete, data: { confirm: '本当に削除しますか?' }, class:"btn btn-danger" %> </div> <table class="table table-bordered bg-white"> <tbody><tr> <th scope="row">ID</th> <td><%= @board.id %></td> </tr> <tr> <th scope="row">タイトル</th> <td><%= @board.title %></td> </tr> <tr> <th scope="row">作成者</th> <td><%= @board.user.decorate.full_name %></td> </tr> <tr> <th scope="row">本文</th> <td><%= @board.body %></td> </tr> <tr> <th scope="row">作成日時</th> <td><%= l @board.created_at, format: :long %></td> </tr> </tbody></table> </div> </div> </div>
ユーザー一覧画面のviewを作成
一覧画面と同じくパーシャルを使用する。
<% content_for(:title, t('.title')) %> <div class="container mb-5 pt-2"> <h1>ユーザー一覧</h1> <div class="row"> <div class="col-md-12 mb-3"> <%= render 'search_form' %> </div> </div> <div class="row"> <div class="col-md-12"> <table class="table table-striped"> <thead> <tr> <th>ID</th> <th>氏名</th> <th>権限</th> <th>日時</th> <th></th> </tr> </thead> <tbody> <%= render @users %> </tbody> </table> </div> </div> <div class="row"> <div class="col-md-12"> <!-- ページネーション --> <%= paginate @users %> </div> </div> </div>
検索機能のパーシャル
<%= search_form_for @q, url: admin_users_path do |f| %> <div class="row"> <div class="form-inline align-items-center mx-auto"> <div class="col-auto"> <%= f.search_field :first_name_or_last_name_cont, placeholder:'検索ワード', class:'form-control' %> </div> <div class="col-auto"> <%= f.select :role_eq, User.roles_i18n.invert.map { |key, value| [key, User.roles[value]]}, include_blank:'指定なし', class:'form-control mr-1' %> </div> <div class="col-auto"> <%= f.submit '検索', class:'btn btn-primary' %> </div> </div> </div> <% end %>
リンクなどのパーシャル
<tr> <td> <%= user.id %> </td> <td> <%= link_to user.decorate.full_name, admin_user_path(user) %> </td> <td> <%= user.role_i18n %> </td> <td> <%= l user.created_at, format: :long %> </td> <td> <%= link_to '詳細', admin_user_path(user), class:"btn btn-info" %> <%= link_to '編集', edit_admin_user_path(user), class:"btn btn-success" %> <%= link_to '削除', admin_user_path(user), method: :delete, data: { confirm: '本当に削除しますか?' }, class:"btn btn-danger" %> </td> </tr>
編集画面のview
<% content_for(:title, t('.title')) %> <div class="container"> <div class="row"> <div class="col-md-10 offset-md-1 col-lg-8 offset-lg-2"> <h1><%= t('.title') %></h1> <%= form_with model: [:admin, @user], local: true do |f| %> <%= render 'shared/error_messages', object: f.object %> <div class="form-group"> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :last_name %> <%= f.text_field :last_name, class: 'form-control'%> </div> <div class="form-group"> <%= f.label :first_name %> <%= f.text_field :first_name, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :avatar %> <%= f.file_field :avatar, onchange: 'previewImage()', class: 'form-control mb-3', accept: 'image/*' %> <%= f.hidden_field :avatar_cache %> </div> <div class='mt-3 mb-3'> <%= image_tag @user.avatar.url, class: 'rounded-circle', id: 'preview', size: '100x100' %> </div> <div class="form-group"> <%= f.label :role %> <%= f.select :role, User.roles_i18n.invert, {}, class: 'form-control' %> </div> <%= f.submit class: 'btn btn-primary' %> <% end %> </div> </div> </div>
詳細画面のview
<% content_for(:title, t('.title')) %> <div class="container"> <div class="row"> <div class="col-md-10 offset-md-1 col-lg-8 offset-lg-2"> <h1><%= t('.title') %></h1> <div class="text-right mb-3"> <%= link_to '編集', edit_admin_user_path(@user), class:"btn btn-success" %> <%= link_to '削除', admin_user_path(@user), method: :delete, data: { confirm: '本当に削除しますか?' }, class:"btn btn-danger" %> </div> <table class="table table-bordered bg-white"> <tbody> <tr> <th scope="row">ID</th> <td><%= @user.id %></td> </tr> <tr> <th scope="row">権限</th> <td> <%= @user.role_i18n %> </td> </tr> <tr> <th scope="row">氏名</th> <td><%= @user.decorate.full_name %></td> </tr> <tr> <th scope="row">アバター</th> <td><img src="/assets/sample-08ca6735af47bfefce4c43e3de2182768289121aa057f141b7f4704a89670827.jpg"></td> </tr> <tr> <th scope="row">作成日時</th> <td><%= l @user.created_at, format: :long %></td> </tr> </tbody> </table> </div> </div> </div>
i18nの設定
admin: users: index: title: 'ユーザー一覧' new: title: 'ユーザー登録' show: title: 'ユーザー詳細' edit: title: 'ユーザー編集' boards: index: title: '掲示板一覧' show: title: '掲示板詳細' edit: title: '掲示板編集' dashboards: index: title: 'ダッシュボード'