アラサーOLだっしゅつけいかく

30代でOLを辞めて未経験からエンジニアになろうと一念発起した人の活動記録です

オリジナルアプリ開発#5 ヘッダーメニューをアイコン化したりページネーション作ったり

Lesson#12-1

開発記録溜め過ぎてすみません…色々やってます!

こんにちは、はくたむです。
ちょっと体調崩してレッスン先延ばしになったりなんだりしていましたが、元気にアプリ制作に励んでおります。

進捗記録をどんな感じで公開して行こうかまだ手探りで、開発進めるのが楽しくて気づいたらめっちゃ溜まってました。
15,000文字くらい…。笑

何回かに分けて投稿しますので、よろしければお付き合いください。

プルリクエストの単位について

レッスン時に先生と確認したのですが、プルリクエストの単位はなるべく小さくするとレビューしてもらう時に抜け漏れが少なくなるかつレスポンスが早くなる、高速でmasterにマージできるよう進めて行きましょう、とのことでした。
と言うわけでなるべく小さく作ることを心がけて作業を進めることとします!

ヘッダーメニューをアイコンにする

前回ログイン前後でヘッダーメニューを切り替えるようにましたが、さらに追加してログイン後の画面で新規投稿ページへのリンクとユーザー編集ページへのリンクをアイコンにして追加してみようと思います。

作業ブランチadd_header_menuiconを作成

今度は間違えないように!笑
masterからブランチを作成します。

railsにFontAwesomeを導入する

簡単みたいです!
下記を参考に導入します。

logist3.com

Gemfileに下記を記述してbundle installします。

$ gem 'font-awesome-rails'

app/assets/stylesheets/application.cssに下記を記述して読み込ませます。
前回の指摘を活かして *= require_tree .より上に記述するよ。

*= require font-awesome

これで使う準備はOK!
記述したあとはサーバーを再起動させないとエラーになりましたので注意。

あとはFontAwesomeのページから使いたいアイコンを選ぶだけ。

headerのドロップダウン部分はこんな感じになりました。

<div class="dropdown">
  <!-- 切替ボタンの設定 -->
  <div class="nav-link" id="dropdownMenuButton button_group" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    <%= fa_icon 'cog 2x' %>
  </div>
  <!-- ドロップメニューの設定 -->
  <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
    <%= link_to 'マイページ', '#', class: 'nav-link dropdown-item' %>
    <%= link_to 'アカウント設定', edit_user_registration_path, class: 'nav-link dropdown-item' %>
  <div class="dropdown-divider"></div>
  <%= link_to 'ログアウト', destroy_user_session_path, method: :delete, class: 'nav-link dropdown-item' %>
  </div><!-- /.dropdown-menu -->
 </div><!-- /.dropdown -->

ヘッダーメニュアイコン化

実はここでレスポンシブ対応が邪魔になっているのを感じてるのですが(わざわざしなくてもアイコンだけなので問題なさそう)この辺りはデザインをやるときに考えることとして先に進みます。

高速でマスターにマージを意識して、一旦ここまででプルリクを出します。

アカウント設定ページの編集

さて、レビューを待っている間にアカウント設定(ユーザー情報変更ページ)の編集をしようと思います。
masterブランチからedit_userinfomation_pageブランチを作成します。

特筆すべきこともなく、ログインや新規登録フォームを流用しながらapp/views/devise/registrations/new.html.erbを修正して終わりです。
このフォーム周りってリファクタリングできるのかなぁ…なんてことを思い始めました。

アカウント設定ページ

あとはユーザー名変更のためapp/controllers/application_controller.rbのStrong Parametersも変更して許可しておきましょう。

devise_parameter_sanitizer.permit(:account_update, keys: [:name] )

プルリクエスト作成&LGTM

今回は両方変更点も少なく一発OKだったのでそれぞれmasterにマージしてローカルとも同期させます。

Wordsテーブル作成

そろそろメインコンテンツの作り込みを始めよう〜!ということでまずは土台となるモデルとコントローラを作成します。
masterブランチからadd_words_tableというブランチを作成しました。

$ rails g model Word user_id:integer word:string kana:string content:text content_replace:text

事前に考えておいたテーブルの内容をざざっと書き込みモデルを作成、db:migrateしてDBに反映させます。

次にコントローラーを作成。
とりあえずindexだけにしたけどよく考えたら全部のアクション使うのでもう少し作っておいても良かったかも。

$ rails g controller words index

ちゃんとwords/indexが表示されたので、後ほどこのページをログイン後の画面にしたいと思います。

ルーティングの設定

その前にconfig/routes.rbを編集してルーティングの設定をしておきます。
このコントローラーは全てのアクションを使用するので、リソースベースでルーティングを作成します。

resources :words

リソースベースで作成するとpathが作成されるので便利ですね!
pathがわからなくなったらいつでもターミナルでrails routesすれば確認できます。よく使ってます。笑

ログイン後の画面を変更する

先ほど作ったwords/indexをログイン後表示させるページに指定したいです。
とはいえdeviseのコントローラーはいじれないし…とりあえず下記を参考にしてdeviseのGitHubを眺めてみました。

31webcreation.hatenablog.com

app/controllers/application_controller.rbにオーバーライドさせるメソッドを作成すればいいみたいなので書き足していきます。
このとき↑で作成したpathが役に立ちます。

def after_sign_in_path_for(resource)
  words_path #ログイン後のページ
end

ヘッダーにリンク作成し忘れていたアカウント設定ページのリンクを追記して、一旦ここまでをプッシュしてプルリクエストを出しました。

メイン画面のデザイン作っていくことにしました

さて作業を続けますが、今回はmasterから切るとモデルやコントローラーがなくなってしまうのでadd_words_tableから新しくedit_words_indexを作成して作っていきます。

インデックスページ

とりあえずここまで編集したのですが、ページネーションを作るためにダミーデータを作って表示やらなんやらさせてみようと思いました。 rails cで下記のコマンドを実行して100個ダミーデータを作成します。

100.times do |i|
  Word.create(user_id: 1, word: "test#{i}") 
end 

ダミーデータをindexに表示させてみる

先ほど作ったデザインの登録語を表示させる部分にダミーデータを反映させてみます。
app/controllers/words_controller.rbでログインユーザーを取得。

class WordsController < ApplicationController
  def index
    @user = current_user
  end
end

表示エリアをで繰り返し表示。
カラム落ちの原因を探るのにめっちゃ時間がかかってしまいました。
col-md-4で指定したdivはみっちり3つ並んでしまうので、もう一個divで囲んでその内側にpaddingで余白をつけてあげたらうまくいきました!

<div class="container mt-5">
  <div class="row justify-content-around">
  <!-- 登録内容繰り返し表示 -->
    <% @user.words.each do |word| %>
      <div class="p-2 col-lg-4">
        <div class="word_box">
          <%= word.word %>
        </div>
      </div>
    <% end %>
   </div>
 </div>

kaminariでページネーションの表示

登録語一覧をindexページにうまく表示できたのでページネーションをつけてみます。
下記を参考に24件ずつ表示するようにしてみました。

blog.otsukasatoshi.com

まずapp/controllers/words_controller.rbでログインユーザーの登録語を取得する記述を追加。

class WordsController < ApplicationController
  def index
    @user = current_user
    @words = @user.words.page(params[:page]).per(24)
  end
end

ページネーションを表示させるところに

<%= paginate @words %>

と書くだけ!
簡単でした…。

と思ったらうまくページネーションできてなくて、何事かと思ったんですが単に繰り返し表示のところで使った変数を@user.words@wordsに変えればOKでした。

見た目の変更がBootstrapでできるとの情報を事前に得ていたのですが、調べてみたらこちらも超簡単。
下記のコマンドを入れるだけでした。

$ rails g kaminari:views bootstrap4

indexページが出来上がりました!

インデックスページ完成

ここまででプルリクエストを作成しました。

単語新規登録フォームの作成

まだレビューが返ってこないので同じブランチからcreate_words_newpageというブランチを切って作業を進めます。 単語を新規登録するためのページを作っていきます。
フォームから投稿してデータベースに反映されたらOKを目標にします。

app/views/words/new.html.erbという新規ファイルを作成し、フォームを作っていきます。

<%= form_for(@words) do |f| %>

  <div class="form-group">
    <%= f.label :登録語 %><br />
    <%= f.text_field :word, autofocus: true, class: 'form-control', placeholder: '登録語' %>
  </div>
    
  <div class="form-group">
    <%= f.label :よみがな %><br />
    <%= f.text_field :kana, autofocus: true, class: 'form-control', placeholder: 'よみがな' %>
  </div>

  <div class="form-group">
    <%= f.label :メモ %><br />
    <%= f.text_area :content, autofocus: true, class: 'form-control', placeholder: 'メモ', rows: 8 %>
  </div>

  <div class="actions">
    <%= f.submit '新規登録', class: 'btn btn-primary badge-pill pr-4 pl-4' %>
  </div>

<% end %>

このページを表示させるためのnewアクションと投稿を保存するためのcreateアクションを作りました。
作ってて気づいたのが、

やたら @user = current_user が出てくる

ということ。
Railsの考え方の一つDRYの法則に則って何回も書かずにするにはどうしたら?と色々調べていたら下記の記事を発見しました。

Railsのmodelクラスのselfが曖昧だったので

これで@user = current_userをメソッド化してself.メソッド名で呼び出してあげればいいみたいです。
というわけでコントローラは下記のようになりました。  

class WordsController < ApplicationController
  def user
    @user = current_user
  end

  def index
    @words = self.user.words.page(params[:page]).per(24)
  end

  def new
    @words = self.user.words.new
  end

  def create
    @words = self.user.words.new(words_params)
    if @words.save
      redirect_to words_path, notice: '単語を登録しました!'
    else
      render 'new'
    end
  end

  private

  def words_params
      params.require(:word).permit(:word, :kana, :content)
  end
end

あとはモデルapp/models/word.rbにバリデーションを追加しました。

  validates :word, presence: true
  validates :kana, presence: true
  validates :content, presence: true

新規登録もちゃんとできたので、ここで作業を終わりにします。
プルリクエスト作成〜!

ちなみに、一覧表示が登録古い順になってしまっていたのであとで直そうと思いました。

プルリクエストがおかしい?

ここまで連続して(masterにマージする前に)作業ブランチからブランチを切って作業を進めていたのですが、なぜかプルリクエストを作成するたびに前のプルリクエストが重複して登録されてたんですね。
原因は調べたけどよくわかりません…。
とりあえず修正点はCSSファイルの行末に空行がなかっただけ(ここでファイルが終わるよ、という目印のためファイルの最後に空行を挿入するのだそう)なので一旦全てmasterにマージして作業を進めてくださいとのことだったので進めます。
この件については次回のレッスン時に詳しく聞こうと思います。