CircleCI Checkoutができない
Circle CI上でテストが動かなくなったので備忘録として。
エラーメッセージ
Directory (/home/circleci/project) you are trying to checkout to is not empty and not a git repository
原因
原因に関しては、CircleCIのissueを読んでみたのですがいまいちわからず...
対応策
issueでも記載されてある通り、- checkout
の位置をcircleci/browser-tools@1.4.0
より上にもってくるかorbのバージョンを1.4.1にあげたらよいみたいでした。
circleci/browser-toolsのバージョンを上げる
config.yml
version: 2.1 orbs: ruby: circleci/ruby@2.0.0 node: circleci/node@5.0.3 - browser-tools: circleci/browser-tools@1.4.0 + browser-tools: circleci/browser-tools@1.4.1 jobs: ・・・省略
checkoutの位置を変更する
config.yml
version: 2.1 orbs: ruby: circleci/ruby@2.0.0 node: circleci/node@5.0.3 browser-tools: circleci/browser-tools@1.4.0 ・・・省略 test: ・・・省略 steps: + - checkout - browser-tools/install-chrome - browser-tools/install-chromedriver - - checkout - ruby/install-deps
仕事をしながら、フィヨルドブートキャンプに参加して思ったこと
この記事はフィヨルドブートキャンプ Part 2 Advent Calendar 2022の9日目の記事になります。
※part1もありますので、興味のある方は是非😄
昨日は、@rosh_1228の「Railwayの紹介」という記事でした。
この記事に関して
仕事をしながらスクールに通うメリット、デメリットに関しての内容になります。
仕事をしながらスクールに通えるのか?と不安に思っている人たちの参考になればと思います。
メリット
1. スクールで学んだことを実際の仕事に生かすことができる
フィヨルドブートキャンプでは、Linuxの基礎からWebアプリの仕組み、Rails、JavaScript etc...と非常に幅広く学ぶことができます。その中でも実際に自分が実際の仕事で生かすことができたことを何点か紹介してみます。
良いコードを仕事で書けるようになった
デイリースクラム(仮)を仕事に導入し、チーム開発を円滑に進めることができた
自分の考えていることを言語化できるようになった
考察し、自分の考えを持てるようになった
2. 読書する習慣が付いた
FBCでは各プラクティス毎に必読本があります。
世の中にはたくさんの技術書があり、どれを読めばいいかわからない中これは絶対に読むべき!と具体的に教えてくれるのは大変ありがたかったです。
自分はよく通勤時間に必読本を読んでいたこともあり、今では通勤時間は読書をするルーティンができあがったのは非常に良かったと思います。
最近読んだ中で断トツで面白かったのは、FBCビブリオバトルで@goruchan32が紹介していました情熱プログラマーでした。
3. 自走力が付いた
他のスクールはわかりませんが、FBCでは良くも悪くも一から教えてはもらえません。
もちろんどうしても分からない場合などはメンターや、Q&A掲示板で質問することができますが決して答えは教えてれないので自分自身で考えて考えて考え抜く必要がでてくるため、自然と自走力が付いたな~と思います。
デメリット
1. 各種イベント(輪読会etc)に参加しずらい
輪読会などのイベントが平日の9:00~17:00くらいの時間帯に集まっていたため、なかなか参加することができませんでした。
じゃ、土日に輪読会開催しちゃえばいいじゃん!と思いながらもなかなか実行に移すことができなかった事を後悔しています...
2. 自分の時間が取れなくなる
起床 → FBC→ 仕事 → 帰宅 → 家族との時間 → FBC → 就寝というサイクルだったので、なかなか息抜きの時間を作るのは難しかったな~と思います。
自分は上手に息抜きすることができなかったので、プラクティスの途中で何度も力尽きたことがありました。
(その度日報の更新がとまったり...)
何事にも全力で取り組むことは大切ですが、息抜きしないと絶対にどこかで力尽きてしまうと思うのでみなさんは息抜きもしっかりしていきましょう(戒め)
おわりに
個人的に感じたメリット、デメリットを書きましたが自分は仕事をしながらフィヨルドブートキャンプに参加して良かったと思います。
技術的なことを学べたことはもちろんですが、原因追求の方法や考え方を学べたことが一番大きかったように思います。
この記事が仕事に通いながらスクールに通えるかな?と不安に思っている人の助けに少しでもなれればと思います。
明日はnicole 2525さんが記事を書いてくださいます。
Fly.ioでProcfile的なことをする方法
自作サービスで、Railsとは別にDiscord Botを常時起動させておく必要があったが、Fly.ioにはProcfile
なんてものは存在しなかった😢
いろいろ調べてみたところ、Fly.ioではfly.toml
なるものを使用すればいいということが分かったので備忘として。
The Fly platform uses fly.toml to configure applications for deployment. Configuration of builds, environment variables, internet-exposed services, disk mounts and release commands go here. TOML is a simple configuration file format. Here's a useful introduction on its syntax. You don't need to create a fly.toml file by hand. Running flyctl launch will create a fly.toml file for you. You can also generate one from an existing app by running flyctl config save. VSCode users: Install the Even Better TOML extension for automatic fly.toml validation and hints drawn from this documentation. App Configuration (fly.toml)
公式ドキュメントを確認したところ、どうやらfly.toml
はデプロイする際のアプリケーション設定を記述することができるらしい。
Questions / Helpも確認したところ、自分の探していることのスレッドを発見した。
どうやら、 [processes]
セッションに記述すればよいみたい。
修正前のfly.toml
・・・省略・・・ [[services]] http_checks = [] internal_port = 8080 processes = ["app"] protocol = "tcp" script_checks = []
修正後のfly.toml
[[services]] http_checks = [] internal_port = 8080 processes = ["web"] protocol = "tcp" script_checks = [] [processes] web = "bundle exec rails server -b [::] -p 8080" bot = "rake discord_bot:start"
[processes]
セクション内にRailsを起動するコマンド、rakeタスクを実行するコマンドを記述し、processes = ["app"]
をprocesses = ["web"]
に置き換える。
相手と自分の認識をすり合わせる
やっと...スクラム開発に到達することができました🤗 スクラム開発では誰かが起票したissueに取り組んでいくことになるのですが、一番大切だなと思う事を実体験を元に書こうと思います。
タイトルにも書いていますが、自分が一番大切なことは相手(issueの起票者)と自分の認識をすり合わせることだと思います。 読解力の高い人だと、相手の言いたい事、実装したいことを理解できるのかもしれませんが自分はあまり読解力が高くないので...😅
good first issueの実体験
スクラム開発のはじめにgood frist issueという比較的簡単なissueを割り振って頂きました。
下記がissueのコードになるのですが、1行目の- title @practice.title
を- title "#{@practice.title}の提出物"
に書き換えると
それに引きずられ、4行目のtitle(h1タグ)も変更されてしまいます。
今回のissueはtitleタグの変更なので4行目は変更しなくてよさそうだな〜と思いましたがもしかするとh1タグも変更してくれという暗黙的なお願いがあるかもしれないのでissue起票者に確認をしました。
確認したところ、やはりtitleタグの変更だけでよい!ということでした。
1 - title @practice.title 2 - category = @practice.category(current_user.course) 3 4 = render '/practices/page_header', title: title, category: category 5 = render 'page_tabs', resource: @practice
もし、暗黙的なお願いが含まれていたとすると出戻り作業が発生していました。 今回のissueは簡単だったので、出戻り作業が発生してもあまりタイムロスにはなりませんがこれが難しいissue(作業に1~2日かかる)だと出戻り作業で発生するタイムロスは深刻なものになってしまいます! 一番初めに読解力の高い人は...と書きましたが、相手の思考を完全に理解できる人なんてまずこの世にいないと思います。 もし、何かの仕事を依頼されたとき相手と認識を合わせずに着手する人がいれば、まず一旦相手と自分の認識のすり合わせを絶対にするべきだと思います。
余談ですが、その後のissueで調子にのった自分は相手と自分の認識をすり合わせず着手したので、あとあと出戻り作業が発生しました(小声) ちゃんと相手と自分の認識のすり合わせをしてから作業をしましょう!(戒め)
npmをリリースしました
フィヨルドブートキャンプで自作npmを作成する課題があり、先日リリースしました。
初めて0から1を作成し、どんなnpmを作成するかなどすごく悩みました...
npmを作成した経緯
漠然とAPIを使ってみたいな〜と思い無料で使用できるAPIを探したところ、
さけのわというところが日本酒に関するAPIを提供しているとの事だったため、日本酒に関するnpmを作成することにしました。
ターゲット層
居酒屋にMacbookを持っていって、今日どんな日本酒を飲もうかな〜と言いながらnpmを叩く変人向けです。
上記は冗談ですが、居酒屋などに行った際日本酒の銘柄などたくさんありどんな日本酒が人気なのか分からない人をターゲットにしました。
ゆくゆくはLINEBotなどと紐づけて、居酒屋などで気軽に利用できるようにしたいと思います。
npmの紹介
使用方法
npmのインストール
npm install jpn-sake
npx jpn-sake
で実行
今後
まだまだソースコードのリファクタリングなどが残っているので、メンターから指摘された点を改善していくと同時に、
上記でも挙げたように、npmのままではイマイチ使い勝手がよくないのでLINEBotと紐づけてもっと気軽に日本酒を探せるようにしたいと思います。
今まで自分でアプリなどを作成したこともなかったため、今回自分で作成し、リリースまでできた事がうれしいです。
少しは成長できたかな?
【Ruby on Rails】N+1問題
N+1問題が発生したので、原因と対応策を備忘としてまとめた。
N+1問題とは🤔
ループ処理の中で都度SQLを発行してしまった結果、大量のSQLが発行されパフォーマンスが低下してしまう問題
ソースコード
# app/controllers/users_controller.rb # frozen_string_literal: true class UsersController < ApplicationController def index @users = User.order(:id).page(params[:page]) end def show @user = User.find(params[:id]) end end
# app/views/users/index.html.erb <h1><%= User.model_name.human %></h1> <table> <thead> <tr> <th><%= User.human_attribute_name(:avatar) %></th> <th><%= User.human_attribute_name(:email) %></th> <th><%= User.human_attribute_name(:name) %></th> <th><%= User.human_attribute_name(:postal_code) %></th> <th><%= User.human_attribute_name(:address) %></th> <th></th> </tr> </thead> <tbody> <% @users.each do |user| %> <tr> <td><%= image_tag user.avatar.variant(resize:'50x50').processed if user.avatar.attached? %></td> <td><%= user.email %></td> <td><%= user.name %></td> <td><%= user.postal_code %></td> <td><%= user.address %></td> <td><%= link_to t('views.common.show'), user %></td> </tr> <% end %> </tbody> </table> <%= paginate @users %>
N+1発生箇所
今回、ユーザー一覧(アイコンも表示)を表示するページでN+1問題が発生した。
# app/controllers/users_controller.rb
def index
@users = User.order(:id).page(params[:page])
end
# app/views/users/index.html.erb
<% @users.each do |user| %>
<tr>
<td><%= image_tag user.avatar.variant(resize:'50x50').processed if user.avatar.attached? %></td>
<td><%= user.email %></td>
<td><%= user.name %></td>
<td><%= user.postal_code %></td>
<td><%= user.address %></td>
<td><%= link_to t('views.common.show'), user %></td>
</tr>
<% end %>
# rails.log
Started GET "/users" for ::1 at 2022-05-19 12:53:28 +0900
Processing by UsersController#index as HTML
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 51], ["LIMIT", 1]]
Rendering layout layouts/application.html.erb
Rendering users/index.html.erb within layouts/application
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ? [["LIMIT", 25], ["OFFSET", 0]]
↳ app/views/users/index.html.erb:16
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 1], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 2], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 3], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 4], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 5], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 6], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 7], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 8], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 9], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 10], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 11], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 12], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 13], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 14], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 15], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 16], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 17], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 18], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 19], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.2ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 20], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 21], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 22], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 23], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 24], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 25], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/users/index.html.erb:18
(0.1ms) SELECT COUNT(*) FROM "users"
↳ app/views/users/index.html.erb:29
Rendered users/index.html.erb within layouts/application (Duration: 74.7ms | Allocations: 30676)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered layout layouts/application.html.erb (Duration: 86.1ms | Allocations: 34506)
Completed 200 OK in 92ms (Views: 83.2ms | ActiveRecord: 3.8ms | Allocations: 36494)
上記のログを見るとSQLを下記のタイミングで発行していることがわかる。
1. controller側でのUser.order(:id).page(params[:page])
で呼び出し1回
1. view側でのuser毎の呼び出しN回
計26件のSQLが発行されていることが分かる。
解決方法
includesを使用する
事前にデータを全件取得しておけば、<% @users.each do |user| %>
の中で都度SQLを発行しなくて済む。# app/controllers/users_controller.rb def index @users= User.all.includes(:avatar_blob).order(:id).page(params[:page]) end
# rails.log Started GET "/users" for ::1 at 2022-05-19 12:54:50 +0900 (1.0ms) SELECT sqlite_version(*) (0.6ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC Processing by UsersController#index as HTML User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 51], ["LIMIT", 1]] Rendering layout layouts/application.html.erb Rendering users/index.html.erb within layouts/application User Load (1.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ? [["LIMIT", 25], ["OFFSET", 0]] ↳ app/views/users/index.html.erb:16 ActiveStorage::Attachment Load (0.7ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? AND "active_storage_attachments"."record_id" IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["record_type", "User"], ["name", "avatar"], ["record_id", 1], ["record_id", 2], ["record_id", 3], ["record_id", 4], ["record_id", 5], ["record_id", 6], ["record_id", 7], ["record_id", 8], ["record_id", 9], ["record_id", 10], ["record_id", 11], ["record_id", 12], ["record_id", 13], ["record_id", 14], ["record_id", 15], ["record_id", 16], ["record_id", 17], ["record_id", 18], ["record_id", 19], ["record_id", 20], ["record_id", 21], ["record_id", 22], ["record_id", 23], ["record_id", 24], ["record_id", 25]] ↳ app/views/users/index.html.erb:16 (0.5ms) SELECT COUNT(*) FROM "users" ↳ app/views/users/index.html.erb:29 Rendered users/index.html.erb within layouts/application (Duration: 443.2ms | Allocations: 304422) [Webpacker] Everything's up-to-date. Nothing to do Rendered layout layouts/application.html.erb (Duration: 473.5ms | Allocations: 312669) Completed 200 OK in 532ms (Views: 477.1ms | ActiveRecord: 5.3ms | Allocations: 325554)
with_attached_avatarを使用する
ActiveStorageでN+1問題を解決する際は、上記のメソッドを使用すればOKscope :“with_attached#{name}”, -> { includes(“#{name}attachments”: :blob) }
メソッド内でも同じようにincludesされているみたい。
参考サイト
【Ruby on Rails】deviseでつまづいたところ
deviseを用いてユーザー認証を実装する際に躓いたポイントを素人目線でまとめてみた。
deviseとは🤔
deviseとはRuby on Railsで作成したアプリケーションに簡単にユーザー認証機能を実装することができるgemである。 github.com
前提
rails generate devise MODEL
はrails generate devise users
で実行
deviseのインストールとセットアップ
READMEにインストール手順が記載されているので、基本的にその指示通りにインストールすればOK
Gemfileに
gem 'devise'
を追加し、bundle install
を実行
※READMEに記載のあるように、Rails 4.1
以上からしか使用できないので注意が必要Devise 4.0 works with Rails 4.1 onwards. Add the following line to your Gemfile:
rails generate devise:install
を実行config/environments/development.rb
に下記の行を追加
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
user
モデルを作成するため下記コマンドを実行rails g devise users rails db:migrate
サーバーを起動した後、http://localhost:3000/users/sign_inにアクセスして、ユーザーが作成できるか確認してみる
deviseのViewとController
現在の各種ファイルを確認したところsign_inやsign_upで表示された画面に対応するViewファイルが見当たらない...
上記のセットアップの中でViewやControllerが一緒に作成されると思い込んでいたが、作成されなかったので作成する。
# Viewファイルの作成 rails g devise:views users
# Controllerファイルの作成 rails g devise:controllers users
ただし、このままでは作成されたViewやControllerをごにょごにょしても実際には反映されない。
config/routes.rbを変更する前だと、各種viewなどはgem自体のviewファイルなどを参照していることがログからわかる。
Rendering /Users/choco/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/devise-4.8.1/app/views/devise/registrations/new.html.erb within layouts/application Rendered /Users/choco/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/devise-4.8.1/app/views/devise/shared/_error_messages.html.erb (Duration: 1.2ms | Allocations: 295) Rendered /Users/choco/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/devise-4.8.1/app/views/devise/shared/_links.html.erb (Duration: 1.5ms | Allocations: 617) Rendered /Users/choco/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/devise-4.8.1/app/views/devise/registrations/new.html.erb within layouts/application (Duration: 411.3ms | Allocations: 2799
config/routes.rbに記載されているdevise_for :users
を下記に置き換えることにより、app/views/users配下にある各種Viewを参照するようになる。
※ 下記の場合だとregistrations
とsessions
のみusers配下を参照するようになる
(パスワード再設定ページなどはusers配下を参照しない)
devise_for :users, controllers: { registrations: 'users/registrations', sessions: "users/sessions", }
Rendering users/registrations/new.html.erb within layouts/application Rendered users/shared/_error_messages.html.erb (Duration: 1.4ms | Allocations: 289) Rendered users/shared/_links.html.erb (Duration: 2.0ms | Allocations: 611) Rendered users/registrations/new.html.erb within layouts/application (Duration: 327.1ms | Allocations: 279730)
全view、controllerをuser配下のものを参照させたいときは、config/initialize/devise.rbに記載されているconfig.scoped_views = false
をconfig.scoped_views = ture
に置き換えてあげるとよい。