自分にやさしく学ぶプログラミング

プログラミング学習記録、備忘録

VScode で Gem::LoadError がいっぱい出て困った

わけあってしばらく放置していたrubyのコードを開いて、VScodeで編集しようとしたら、拡張機能ruby-rubocopからこんなかんじで怒られた。 Gem::LoadError: You have already activated forwardable 1.3.1, but your Gemfile requires forwardable 1.2.0. Prependingbundle execto your command may solve this.

Gemfileみたら、こんな風に書いてある。 gem 'forwardable', '~> 1.2.0'

恥ずかしながら、この表記みて
「バージョン1.2.0より新しけりゃいいんでしょ?あってんじゃん!!#」
なんて思ってしまった。

~>って、そういえば
「最後の桁が現在よりも大きくなることは許可するが、次の桁の原稿は許可しない」
でしたね・・・。 やっべ。

今回の例でいけば、確か1.2.9までしか許可されてなくて、1.3.1でエラーが出るのはそりゃそうだってかんじですね。 とりあえず今回いじってたのは学習用のフォルダで、正直Gemのバージョンとか気にしないので、エラーが出たとこを一つずつバージョン指定無くしていったところ、怒られなくなりました。 しばらく触ってないとこういうことも起きるんだな。
rubocopも頻繁にバージョンアップするから、copのrenameも定期的に対応しないといけないっぽいし。
長く使うコードは時々見直さないといけないんだと再認識した。

「駆け出しエンジニアのための、初めてのLT会」に参加してきた

同じフィヨルドブートキャンプ生の@NMP3000さん主催の勉強会に参加してきた。

connpass.com

その名の通り、駆け出しのエンジニアが集まって気軽にLTしようというもの。 なんと私にも発表の時間をいただくことができ、こんな感じの発表をしてきた。

speakerdeck.com

初めての発表で緊張したけど、@NMP3000さんの声掛けもあり、聞き手の反応が良くて話しやすく、楽しく発表できた。

計6名が発表し、どれも興味深い内容だったが、特に面白いなぁと感じたのが、@hasehiro25さんのこの発表。

speakerdeck.com

Railsでテーブルにデータ100万件追加するというベンチマークプログラムを作って回してみたところ、createメソッドで追加しようとすると30分以上の時間がかかったのに対し、Bulk insertで追加すると数十秒で完了したとのこと。
こういう数字の出る発表っていいなぁと思う。
あと、Bulk insertはRails6から標準になったそうで、そういう新しい機能をすぐさま使ってみるっていうのも素敵。
自分も見習って、手元で色々試す習慣をつけたい。

Ruby on Rails : railsのフォルダ、ファイルの意味について自分なりにまとめる

概要

Railsのフォルダ構成の意味がよくわかっていないので、とりあえず今の時点での理解を文章化してみる。 正直あまり自信ないので、もしも間違いがあればコメント等いただけるとありがたい。

Railsの各フォルダ、ファイルの意味

自明なものなど一部省略

|- app/ アプリケーションの具体的な機能がフォルダにまとめられている。
|   |- assets/ HTMLに付随するCSSJavaScriptや画像など。
|  |   |- config/ 多分JavaScript関連の設定。マニフェストファイルが入っている。
|  |  |- images/ 画像置き場。
|  |  |- stylesheets/ スタイルシート置き場。
|  |- channels/ Action Cableのチャネルの記述。各ファイルの中身はControllerと同じような感じ。
|  |- controllers/ データや入力を元に計算しつつ、modelとviewを接続する。
|  |  |- concern/ 複数のモデルで使いたいモジュールなどを置いておく。
|  |- helpers/ 複数のviewで共通して使われるようなちょっとしたモジュール。
|  |- javascript/ JavaScript置き場のようだが、Action CableとWebpackrが絡んでいるっぽい。
|  |- jobs/ Active Jobによるジョブの定義(例えばアカウント生成したら確認メールを送るなど)。
|  |- mailers/ メールを生成する際のコントローラにあたるもの。
|  |- models/ モデルの定義。
|  |- uploaders/ CarrierWaveによるアップロード機能の定義。
|  |- views/ 画面上に表示するもの。
|- bin/  アプリケーションの起動、アップデート、デプロイのためのスクリプト
|- config/  各種設定ファイル。
|- config.ru Rackの設定ファイル。
|- db/ DBの定義。
|- lib/ アプリ固有のライブラリ。
|- log/ アプリ実行時のログ。
|- node_modules/ Node.jsのパッケージ。npmによる。
|- public/ 静的ファイル置き場。インターネットからそのまま参照できる領域。
|- storage/ Diskサービスで用いるActive Storageファイル。
|- test/ 自動テストのためのファイル。
|- tmp/ アプリ実行時に一時的に保存するデータ。
|- vendor/ 外部からのGem (色々gem入れてるはずなのに空なのはなぜ・・・?)。
|- babel.config.js JavaScriptコンパイラであるBabelの設定ファイル。
|- package.json npmの依存関係を記述する。
|- postcss.config.js PostCSS(CSSツールのフレームワーク)の設定ファイル。
|- yarn.lock パッケージマネージャであるyarnの依存関係を記述したファイル。

最後に

WebpackとかAction Cableとか、色々読んではみたけど大分チンプンなので、今後も実際使いながら学んでいきたい。

Ruby on Rails : deviseでユーザー認証追加してi18nしてユーザープロフィールページも追加するための手順の解説

概要

先日上げたエントリ(Ruby on Rails : deviseでユーザー認証追加してi18nしてユーザープロフィールページも追加するための手順(手順だけ))の解説。自明な部分は置いといて、自分がよくわからないと感じた部分だけまとめる。

参考資料

手順全体の意味をざっくりまとめる

  • 手順1〜5 deviseを入れてRailsアプリ立ち上げ
  • 手順6〜9 deviseのための設定
  • 手順10~11 deviseによるuserモデル追加(この段階でユーザー認証機能が備わる)
  • 手順12~13 カスタマイズ用のファイル生成
  • 手順14~18 ユーザー情報に項目を追加し、ログインユーザー以外のアクセスを禁止
  • 手順19~20 言語切り替えリンクの追加
  • 手順21~26 ユーザープロフィールページを追加

自分がよくわからなかったところ

手順6~9:deviseのための設定

deviseで指定されている設定。何も考えずにとりあえず書いとけば動く。

各設定の意味についてちょっと詳しく 手順6:
action_mailerの設定。action_mailerとはRailsアプリでメールを送受信するための仕組み。controllerと似ている。controllerがページを表示するviewと繋がっているのに対して、mailerはメールのviewと繋がっている。
そして上記設定はmailerにhost名とポート番号を設定するためのもの。mailerはWebサーバーのコンテキストと無関係であるため、明示的に設定する必要がある。

手順7:
root(今回なら http://localhost:3000/ )のルーティング。

手順8,9:
ログイン成功のメッセージを表示するためのもの。

手順12~13:カスタマイズ用のファイル生成

deviseはcontrollerもviewも用意してくれているので、特に必要なければそのまま使えばいいが、もし編集したい場合はrails gで生成したファイルを編集する。
手順12のコマンドでviewを生成すると、viewファイルはapp/views/devise/下に生成される。deviseというディレクトリ名をusersなどに変えてしまうと、scoped_viewと見なされるようで、viewを編集するために設定変更が必要となったり、i18nのlazy lookupが使えなくなったりするので注意。

手順16:ログインユーザー以外のアクセス禁止とStrong Parametersへの変数追加

1行目は文字通りのことをしてくれる。 その下は、Usersテーブルに追加したnameとprofileに値を渡せるようにするためのもの。RailsのStrong Parametersという仕組み(受け取れる値を制限する)により、この設定をしないと値をデーターベースに書き込めない。書き方としてはdevise_parameter_sanitizer.permit(許可するタイミング, 許可する項目)みたいな感じ。

手順19~20:言語切り替えリンクの追加

唐突だけど、これはユーザーがアプリ上で英語と日本語を切り替えられるようにするためのリンクを追加するもの。いらなければ飛ばしていい。

手順21~23:ユーザープロフィールページの追加

プロフィールページなど、自分でページを追加したいときは、改めてcontrollerとルーティングを記述する必要がある。Users::RegistrationsControllerとかに追記してもうまくいかない。

手順25~26:ユーザー情報を編集したらプロフィールページへ飛ぶようにする

デフォルトだと編集後はアプリのrootに飛ぶ。それだと編集結果が確認できないので、プロフィールページに飛ぶようにする。そのためには、Users::RegistrationsController内でafter_update_path_for(resource)をオーバーライドする。 controllerを変更したら、変更後のcontrollerを編参照するようにルーティングも修正する必要がある。deviseのルーティングはdevise_forメソッドを使って編集する。中括弧の中に適宜書き足していけば、任意のcontrollerについてルーティングを変更できる。

ルーティングを変更した場合のviewファイルについて
Copy the views from devise/sessions to users/sessions. Since the controller was changed, it won't use the default views located in devise/sessions.
deviseのREADMEより
とあるけど、私の環境では、viewファイルについてはdeviseフォルダにおいたままでも変更が反映されていた。

最後に

deviseはとりあえず認証機能をつかするだけならすぐだけど、少し変えようとするだけでも色々やることがあって難しかった。特にルーティングはrailsresourcesしたときとはちょっと雰囲気が違うので、よく確認したほうがいいなと思った。

Ruby on Rails : deviseでユーザー認証追加してi18nしてユーザープロフィールページも追加するための手順(手順だけ)

概要

まっさらな空のディレクトリから、

  1. Railsのアプリを立ち上げて
  2. deviseでユーザー認証機能を導入し
  3. ユーザー情報の項目を追加し
  4. ユーザープロフィール表示ページを追加する

までの手順をまとめる(手順だけ)。 サンプルとして、rails scaffoldでシンプルなブログアプリ(devise_app)をつくる。 (2019/10/19 追記) なお、追加したリンク等の翻訳については手順に含まれていないので、適宜翻訳ファイルの修正が必要。

参考資料

本記事は下記のページを元にして手順を捕捉したものである。
devise導入からユーザーのプロフィール画面を作成するまで

実施環境

上記は私が確認した際のバージョンであり、下記手順で実行するとdeviseおよびdevise-18nは最新バージョンがインストールされる。

手順

  1. rails new devise_appする
  2. Gemfileにgem 'devise', gem 'devise-i18n'を追記し、bundleする
  3. rails g scaffold blog title:string content:textする
  4. rails db:migrateする
  5. rails g devise:installする
  6. config/environments/development.rbconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 }を追記
  7. config/routes.rbroot to: "blogs#index"を追記
  8. app/views/layouts/application.html.erb

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>
    

      を追記

  9. app/views/blogs/index.html.erb<p id="notice"><%= notice %></p>を消す
  10. rails g devise userする
  11. rails db:migrateする
  12. rails g devise:i18n:viewsする
  13. rails g devise:controllers usersする
  14. rails g migration AddColumnToUsers name:string profile:textする
  15. rails db:migrateする
  16. app/controllers/application_controller.rb

      before_action :authenticate_user!
      before_action :configure_permitted_parameters, if: :devise_controller?
    
      protected
      def configure_permitted_parameters
        devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
        devise_parameter_sanitizer.permit(:account_update, keys: [:name, :profile])
      end
    

    を追記

  17. app/views/devise/registrations/new.html.erb

      <div class="field">
        <%= f.label :name %><br />
        <%= f.text_field :name, autofocus: true %>
      </div>
    

    を追記

  18. app/views/devise/registrations/edit.html.erb

      <div class="field">
        <%= f.label :name %><br />
        <%= f.text_field :name, autofocus: true %>
      </div>
    
      <div class="field">
        <%= f.label :profile %><br />
        <%= f.text_area :profile, autofocus: true %>
      </div>
    

    を追記

  19. app/controllers/application_controller.rb

      before_action :set_locale
    
      def set_locale
        I18n.locale = extract_locale_from_tld || I18n.default_locale
      end
    
      def extract_locale_from_tld
        parsed_locale = request.host.split(".").first
        I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
      end
    

    を追記

  20. app/views/layouts/application.html.erb

      <%= link_to_if request.host.split('.').first != 'ja', '日本語',   "http://ja.localhost:3000#{request.path}"%> |
      <%= link_to_if request.host.split('.').first != 'en', 'English', "http://en.localhost:3000#{request.path}" %>
    

    を追記

  21. config/routes.rbの最後に

      resources :users, only: [:show]
    

    を追記

  22. app/controllers/users_controller.rbを新たに作成し

      class UsersController < ApplicationController
        def show
          @user = User.find(params[:id]) #追記
        end
      end
    

    を記述

  23. app/views/users/show.html.erbを新たに作成し

      <h1>Users#show</h1>
      <p>名前 : <%= @user.name %></p>
      <p>メールアドレス : <%= @user.email %></p>
      <p>プロフィール : <%= @user.profile %></p>
      <%= link_to t(".edit_profile"), edit_user_registration_path %>
    

    を記述

  24. app/views/layouts/application.html.erb

      <p class="navbar-text pull-right">
        <% if user_signed_in? %>
          <%= t(".login_user", username: current_user.email) %>
          <br>
          <%= link_to t(".top"), blogs_path, class: 'navbar-link' %> |
          <%= link_to t(".profile"), user_path(current_user.id), class: 'navbar-link' %> |
          <%= link_to t(".sign_out"), destroy_user_session_path, method: :delete, class: 'navbar-link' %>
        <% else %>
          <%= link_to t(".top"), blogs_path, class: 'navbar-link' %> |
          <%= link_to t(".sign_up"), new_user_registration_path, class: 'navbar-link'  %> |
          <%= link_to t(".sign_in"), new_user_session_path, class: 'navbar-link'  %>
        <% end %>
      </p>
    

    を追記

  25. app/controllers/users/registrations_controller.rb

      protected
      # アカウント編集後、プロフィール画面に移動する
        def after_update_path_for(resource)
          user_path(id: current_user.id)
        end
    

    を追記

  26. config/routes.rbresources :users, only: [:show]より上に

      devise_for :users, controllers: {
        registrations: "users/registrations"
      }
    

    を追記

最後に

解説は後日!!!

Webアプリ:ネタ検討のため困っていることを列挙

現在参加中のFJORD BOOT CAMPは、最終課題で自作アプリを作ることになっている。 自作アプリをつくるに当たって、自分の個人的な困りごとを解決するものをつくるのがいいと聞いたので、今の時点で思いつく困りごとについて列挙してみたい。 (まだ自分は他のカリキュラムの作成途中であり、これはモチベーション維持のための息抜きみたいなものである)

困りごとs

困りごとその1:計画が立てられない

私は長期的な計画を立てるのがめっっっちゃくちゃ苦手だ。
「やれるだけやる」で生きてきたので、自分のペースを作ってコンスタントにやっていくというのが本当に本当に苦手。というかできない。
これは切実に解決したい課題だと思っている。

具体的に困っている点

  • やったことのない物事に対して、どのくらいの時間がかかるかなんて見積もれない
  • 先のことを考えると不安になる
  • ので、計画を立て終わる前に我慢できす手を動かし始めてしまう
  • なんとか我慢して計画を立てようとするとそれに時間がかかって手を動かしはじめるのが遅くなり、その時点で計画がくずれる
  • やってるうちに他にも必要なこと(やりたいこと)が色々出てきて計画が無意味化していく
  • そもそも何をどうすれば「計画を立てた」ことになるのかよくわからない
  • 自分一人で立て、実行している計画は張り合いがなくて維持できない

困りごとその2:生活記録をつけたいが面倒

自分のメンタルとフィジカル維持のための生活記録をつけている。
これをためていって、あとから振り返ったり解析できるようにしたいが、めっちゃくちゃ面倒。
ちなみに生活記録には、1時間間隔程度の気分を数値化した値(気分が良ければ100、悪ければ30みたいな)、その間の行動や思考、一日の運動量や食事内容、睡眠時間を記録しておき、もっと言うとそこに気温気圧の推移、天候や日照時間、花粉飛散量、心拍数の推移を重ねて解析できるようにしたい。
行動や思考をカテゴライズして、どんな行動をとったらどの程度気分がよくなるとか、そう言うことをグラフ化して表現したい。

具体的に困っている点

  • 1時間ごとに記録取るアクションが面倒
  • 手書きメモやエクセルの表などで記録していたが、特定の行動にフォーカスした解析などは簡単にはできない
  • 気分の数値化はなかなか難しい
  • わざわざ気候データとか整理してまとめるの面倒

困りごとその3:釣りが好きだが思うように釣れない

いやそりゃそうなんだけども。
釣りというのは行くだけでそこそこ金のかかる趣味なので、釣りに行ったら絶対釣りたいのだ。
魚がいるかどうか疑わしい中で、釣り人だらけの防波堤で周りに遠慮しなが釣るとか、逆にストレスが溜まる。
せめて「ここに今魚がいる!!!」という確信を持って釣りたい。
そのためには自分の釣行を記録するとともに、ネット上の無数の釣行記録を収集して、それらを並べて解析できるようにしたい。

具体的に困っている点

  • 自分の記録にしたってつけるのが面倒
  • 多くの記録は書式が定まっておらず、データとして並べるのは困難
  • 「魚がいるかどうか」の判断に当たっては、魚種、天候、潮汐、海水温などのデータが必要だと思うが、そこまで詳しい記録は少ない。
  • 自分の記録についてはできれば釣りをしながらつけていきたいが、釣りの最中は手が汚れているのでスマホとかにはあまり触りたくない。

所感

多少意識してしまったが、こうして挙げてみると意外とWebアプリとして作れそうなものはあるかも・・・?
計画を公開してみんなで進捗共有して励ましあえるとか。
好きな画像と音楽とか登録しといて、ノルマ達成したら表示されるとか、メッセージカードみたいにして頑張った友達にプレゼントできるとか?
記録は完全にフリーハンドでできると嬉しいんだけど、音声認識でどうにかならないかな。。。
こうして考えてみるとなかなか楽しい。カリキュラム進めつつ、他にもネタがないか考えていきたい。

Ruby: eachとmapの返り値

概要

eachとmapの使い分けがようやく実感として掴めた気がした。 返り値が違う。

eachの返り値

eachは繰り返し処理を実行したオブジェクトを返す。

          ary = ["./hello/11", "./hello/22", "./hello/33"]
          test = []
          ary.each { |a| test << a.delete_prefix("./hello/") }
                # => ["./hello/11", "./hello/22", "./hello/33"]
          test
                # => ["11", "22", "33"]

mapの返り値

mapは繰り返し処理をした結果を返す。

          ary = ["./hello/11", "./hello/22", "./hello/33"]
          test = []
          ary.map { |a| test << a.delete_prefix("./hello/") }
                # => [["11", "22", "33"], ["11", "22", "33"], ["11", "22", "33"]]
          test
                # => ["11", "22", "33"]

結局何だ

上のように繰り返しの結果を得たいのであればこんな感じでmap使うのがいい。

      ary = ["./hello/11", "./hello/22", "./hello/33"]
      test = ary.map { |a| a.delete_prefix("./hello/") }
            # => ["11", "22", "33"]