はじめに
現在RUNTEQにてプログラミングを学んでいる初心者が書いた記事になります。Ruby on Rails使用し、バックエンドやDBを使用したアプリを初めて作成しました。そのアプリの開発記録になります。
なぜこのアプリを作成したのか
私自身が、季節や時間ごとによって表情が変わる空をみることが大好きでよく空の写真を撮影するのですが、その空の写真と合わせてその時感じた気持ちや状況などを同時に記録できたらいいなと思っていからです。また、Xで共有してタイムラインに素敵な空の画像が流れることで見ている人に癒されて欲しいと思いました。
アプリの概要
「SkyPhotos」
何気なく見上げた空が心に響く瞬間ありませんか? 「SkyPhotos」は、ふと心に響いた空の写真を投稿して、みんなと共有できるアプリです。
GitHub
主な機能
- ユーザー登録(google outh対応)
- ユーザー未登録で写真一覧および写真詳細が見られる機能
- 写真投稿機能
- 写真プレビュー機能
- コメント機能
- ブックマーク機能
- 何回でも押すことが可能な「エモい」ボタン機能
- 管理画面機能
- マイページ編集機能
- パスワードリセット機能
使用技術
| カテゴリ | 技術・ツール |
|---|---|
| バックエンド | Ruby on Rails 7.2.2.2 |
| フロントエンド | Ruby on Rails / JavaScript / Stimulus / Turbo |
| UI/CSS | Tailwind CSS |
| データベース | PostgreSQL(Neon) |
| 認証 | Sorcery / OmniAuth (Google OAuth2) |
| 画像ストレージ | Cloudinary |
| 環境構築 | Docker |
| CI/CD | GitHub Actions |
| インフラ | Render |
| その他 | Kaminari (ページネーション) / ActiveStorage (写真投稿) / Meta-tags (OGP) / rails_admin(管理画面) |
技術選定の理由
Ruby on Railsを使用した理由はRUNTEQで学んでいるフレームワークだからです。カリキュラムのなかで、sorceryを使用したログインログアウト機能を実装した経験をもとに採用しました。DBのNeonと画像ストレージのCloudinaryという外部サービスを使用した理由は、無料枠内で個人開発程度の利用であれば十分な容量を借りることが可能なためです。
技術的な工夫ポイント
プレビュー機能実装
コードについては以下の記事にまとめましたのでご覧いただけますと幸いです。
このアプリ自体、写真投稿がメイン機能となっているためこの機能はマストで取り入れると決めていました。プレビュー表示は、ユーザーが間違った写真を投稿することを防ぐという点だけでなく、プレビューを見ることでその時感じた気持ちや思い出を思い出しながらタイトルや本文を書くことができます。
写真投稿一覧ページ「空を見上げる」
一覧表示ではあえて写真以外の情報は載せず、カードを並べていろんな空の画像を先入観無く眺められるように設計しました。気になる画像があればカーソルをかざすことでカードの下部からタイトルや投稿者などの情報がスッとスライドで出てくるようにしました。
カーソルをかざしても写真が覆われない程度にすることで写真も見ながら情報も得られるように設計しました。また、アプリ利用のハードルが下がるように未ログインの方でも一覧を見ることができるようにしました。
投稿者に感動を伝える「エモい」ボタン

SNSのいいね機能のように、空の写真を見た後簡単に投稿者に感動を伝えることができるよう「エモい」ボタンを設置しました。エモいとは「心が揺さぶられてなんとも言えない気持ち」を指し、「感情的」「哀愁漂う」「趣がある」「グッとくる」など複雑でいろんな感情を含む便利な言葉です。(引用:https://fujifilmsquare.jp/column/23.html)
いいねの一言では伝えられない気持ちをこの「エモい」ボタンで表現しました。また、普段SNSを利用しているとなぜ一回しかいいねが押せないのかと感じることがあったため、何度でも押せる仕様にしました。
フィードバックから気づいたこと
- お気に入り登録マーク
当初、登録済みの場合黒い星マークに×マークが付いているアイコンにしていたのですが、黒い星マークの方がわかりやすいというフィードバックを受け、アイコンを黒い星マークに変更しました。ここは開発時どのアイコンがわかりやすいか迷っていた部分でもあったので意見を頂けて大変助かりました。
- 写真の投稿時間や季節の項目
空の写真がいつ、どの時間帯で撮影されたかを知れると良いというフィードバックを受けました。開発当初導入する予定でいましたが、投稿者自身が投稿本文に記載してもらう方向にしたため実装しませんでした。しかし、リリースして自分自身も投稿してみると簡単に選択できた方が楽であると気づきました。フィードバックでも同じ意見を貰ったのでユーザー目線でもそのようにした方が使いやすいと感じました。
まだこの機能は実装できていませんが今後アップデートで実装していきたいと思います。
苦労したこと、学び
外部サービスNeonやCloudinary、GoogleOuthなどカリキュラムでは使用しなかった技術を取り入れた点です。開発当初、カリキュラムに準えた簡単な投稿サイトを作成する予定でいましたが、実際に本番環境で運用するにはどこにDBを置くか、画像のストレージや加工はどうするか、本番環境の設定などアプリを動かすための必要な設定を調べることにとても苦労しました。公式ドキュメントを読んだり、記事を見たり、先輩方に聞いたりしてひとつずつ手順の意味を確認しながら実装しました。途中、エラーが何度も出ましたが、AIに聞きながらではありますが、ここを少し変更したらどうなるか?ここの変数には何が入っているのか?一つずつ検証していきました。
そのおかげで、今までぼんやりとしていた、どのファイルにどういう設定を書くべきかや、環境変数や各サービスの理解が深まりました。
また、アプリMVPリリースする直前にrenderのメモリをみたところ、starterコースの512MBギリギリまで使用しており、警告が何度も出ている状態でした。アプリのログを確認してみるとN+1問題が起きていることに気づき修正しました。それだけでもメモリ使用率は下がらなかったため、サーバーへのリクエストのスレッド数を減らしたり、画像処理をrailsデフォルトからgem ruby-vipsに変更したりと色々と試行錯誤しました。最終的には、場合によっては100%近くまであがることもありますが、80%程度の使用率まで抑えることができました。
この経験のおかげでメモリ使用効率まで考えて設計する大切さを知ることができました。
今後のアップデート予定
- (上記のフィードバックで挙げた)写真の投稿時間や季節の項目追加
- プライバシーポリシーの実装
最後に
当初二週間ぐらいでできればいいなと適当で大雑把な見積もりをしていたのですが、開発が進めば進むほど知らないことがたくさん出てきて、途中諦めようかと思うほどでした。しかし、SNSで繋がった同じRUNTEQ生の方に励ましの言葉をもらったり、先輩方に相談したりしてMVPリリースまで持っていくことができました。
このアプリを開発する上で関わってくださった皆様及びアプリを使用してくださった皆様、この記事を最後まで読んでいいただいた方に心より感謝申し上げます。
