#6 リソースマスタ画面を作る(1)

投稿者: | 2021年3月9日

前回まででDBのセットアップと最初の静的ページを作るところまで行きました。今回はマスタ画面を作ります。

Handsontableのライブラリ導入

ライブラリの導入は過去のHandsontableの記事にも書きました。Gitからソースをダウンロードして、vendor/assetsの下に配置し、application.jsやapplication.cssにパスを通します。

Visual Studio Codeであれば、上記にドラッグするだけで追加できます。

まずはファイルを作って表示するまで

RailsTutorialと違って1件ずつエンティティをCreateするわけではないので自分でルーティングを定義します。

まずはコントローラを作ります。

rails g controller w_resource

最初はコントローラやビューなどのファイルを作ってしまいましょう。

routes.rb
get 'w_resource', to: 'w_resource#new', as: 'w_resource'

application_controller.rbに1つメソッドを追加しておきます。これはテスト用のメソッドで、呼び出し箇所でデータを標準出力するためのものです。byebugなどのツールでしてステップ実行をしてもよいですが、手軽にできるのでこの方法もありです。

application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  def test( str )
    puts "----------------------------"
    puts caller[0]
    puts str
    puts "----------------------------"
  end
end
w_resource_controller.rb
class WResourceController < ApplicationController
    def new
        test request
    end
end
new.html.erb
<%= provide(:title, "リソースマスタ") %>
<div class="row jumbotron">
    <h3>リソースマスタ</h3>
    <div class="form-group inline">
        <row>
        </row>
    </div>
</div>
<script type="text/javascript">
$(document).ready(function(){
});
</script>

実行すると下記のようにコンソールに出力がでます。動かない時はどこまでが実行されているのか?を見るためにもこのような手を打つとよいです。

いわゆる「printf デバッグ」と言われている方法ですね。

----------------------------
/home/devuser/waiting_app/app/controllers/w_resource_controller.rb:3:in `new'
#<ActionDispatch::Request:0x0000000005d71428>
----------------------------

画面モックを作る

さて今回はこの形まで作りこんでいきます。演習問題も1問だけつけてみました。最後に気楽にやってみてください。

作りとしては下記のようになります。追加ボタンを押下すると、リソース名と尾行を登録処理(Create)にPOSTして登録を実行します。一覧部分にはすべてのリソースが表示されており、削除ボタンを押下すると画面上に削除の印をつけます。(この時点ではまだ削除しません)

そして、反映ボタンをクリックすると一覧のデータをPOSTして削除したり更新したりします。

ではルーティングファイルを書き換えます。このプロジェクトでは基本構成はこんな感じで行きます。

  • newは画面の初期表示用
  • createはエンティティを1件作成する
  • searchは検索条件によって検索結果を返す
  • editsは更新内容を受け取りデータベースに反映する
routes.rb
get  'w_resource', to: 'w_resource#new',    as: 'w_resource'
post 'w_resource', to: 'w_resource#create', as: 'create_resource'
post 'w_resource/search', to: 'w_resource#search', as: 'search_w_resource'
post 'w_resource/edits',  to: 'w_resource#edits',  as: 'edits_w_resource'

Railに従うのであれば、エンティティ1件のeditやdestroyなどがありますが、今回は省略します。一括での更新や削除があるため、大は小を兼ねるで作っていきます。indexも省略です。えてして検索条件を指定して受け取りたいということがあるので、ただ無条件で取得するindexはそちらで賄うことにします。

w_resource_controller.rb
 class WResourceController < ApplicationController
     def new
         test request
         @form = WaitingResource.new
     end
+    def create
+        test request
+    end
+    def search
+        test request
+    end
+    def edits
+        test request
+    end
 end

ルーティングファイルに沿えってコントローラ側もインターフェイスの定義だけは済ませます。

さて、次は肝心の画面です。これは少し長くなります。

<%= provide(:title, "リソースマスタ") %>
<div class="row jumbotron">
    <h3>リソースマスタ</h3>
    <%= form_for(@form, url: w_resource_path, method: 'post' ) do |f| %>
        <row>
            <div class="form-group inline">
                <%= f.label :name, "リソース名", class:"col-md-1" %>
                <div class="col-md-11">
                    <%= f.text_field :name, class: 'form-control' %>
                </div>
            </div>
        </row>
        <row>
            <div class="form-group inline">
                <%= f.label :ref, "備考", class:"col-md-1" %>
                <div class="col-md-11">
                    <%= f.text_field :ref, class: 'form-control' %>
                </div>
            </div>
        </row>
        <row>
            <div class="form-group inline col-md-12 text-right">
                <%= f.submit "追加", class: 'btn btn-primary' %>
            </div>
        </row>        
    <% end %>

    <div class="form-group inline grid_area">
        <div class="row">
            <div id="resources_grid"></div>
        </div>
        <div class="row ">
            <div>
                <button type="button" class="btn btn-labeled btn-danger btn-custom" id="removeBtn">
                    行削除
                </button>
                <%= link_to '反映', edits_w_resource_path, method: "POST",
                    class: "btn btn-labeled btn-success btn-custom", id: "commitBtn" %>
            </div>
        </div>
    </div>    

</div>
<script type="text/javascript">
$(document).ready(function(){
    let hot = null;
    let resources = function(){
        let grid = document.getElementById('resources_grid');
        hot = new Handsontable(grid, {});
        let data = [];
        hot.updateSettings({
            data: data,
            colHeaders: ['', '' ,'', '削除', 'リソース名', '備考'],
            columns: [
                { data: "id"       , type: 'numeric',
                    readOnly: true},
                { data: '_status'  , type: 'text'   ,
                    readOnly: true },
                { data: 'status'   , type: 'text'   ,
                    readOnly: true },
                { data: "select"   , type: 'checkbox' },
                { data: "name" , type: 'text' },
                { data: "ref"  , type: 'text' }
            ],
            width: 650,
            height: 150,
            colWidths: [0.1, 0.1, 30, 50, 200,300],
            enterMoves: { row: 1, col: 0 },
            wordWrap: false,
            outsideClickDeselects: true,
            manualColumnResize: true,
            manualRowResize: true,
            rowHeaders: true,
            manualColumnMove: false,
            rowHeights: 30,
            columnSorting: true
        });
    };

    resources();
});
</script>

演習

上記のソースでは一覧部分に何も表示されません。試しに数件程度データを表示してみてください。(idやstatusについては今回は意識しなくてよいです。今はなくて問題ありません。)

handsontableの仕様が絡むので少し補足しますと、data:dataとなっている部分がありますが、ここで表示データを指定します。現在は空の配列です。

また、データの定義はcolumnsに定義しています。dataが[ {c1: 1, c2:2} ]なのであれば、c1,c2を定義します。

解答例は末尾に記載しておきます。

次回

次回は登録処理を完成させましょう。そして、画面初期表示時にデータが表示されるようにすることを目指します。なお、大量のデータがある場合にはページネーションが必要ですから、この辺りも仕組みを整備しましょう。

回答例

 let data = [];
+for(var i = 0; i < 10; i++){ data.push( { name: 'dummy_name' + i , ref: 'dummy_name' + i } ); }
 hot.updateSettings({
     data: data,
: