20210612のRailsに関する記事は24件です。

Railsをガイドに沿って基礎から学ぶ①

はじめに この記事はスキルアップを目的とした記録です。 前回に意味の分からないログイン画面を作成する投稿をしたところ、基礎知識が足りていないと感じたのでガイドに沿って1から勉強をしなおすことにしました。 現時点(2021/06/12)の物です。 わからない部分に関しては今後更新していきます。 1.教材 今回はRailsガイドを参考にしました。 今回はHello Railsを表示するまでの手順を記述し、ガイドを見て理解ができなかったところを深堀してお伝えしたいと思います。 2.Railsとは ①RailsとはRuby言語のフレームワーク ②Webアプリケーション簡単に設計出来るようになっている ③同一コードを繰り返さない事を推奨している ④設定よりも規約が優先される 3.新規プロジェクトの作成 3.1Railsのインストール 環境構築手順については以前投稿しているので割愛します。 3-2.新規アプリケーション作成 環境構築が終了したら新しいアプリケーションを生成します。 今回もCドライブ直下にアプリケーションを置きます。 $cd C:\ $rails new blog 生成が完了したらアプリケーションの中身を見ていきます。 上から初心者でも必要そうなものを紹介 ①app/ アプリケーションの構成に重要になるフォルダ。 MVCモデルに沿って作られている。 MVCモデルを知らない人は先にそちらを調べたほうが学習しやすいかもしれません。 ②config/ アプリケーションの設定ファイルが置いている。 使用頻度が高く重要。 気になる方はこちらのガイドから学ぶとよいと思います。 ③db/ データベーススキーマ、データベースマイグレーションファイルが置かれる場所。 appで記述しているModelと強いかかわりがあります ④public/ 外部からも接続できる範囲で、直接参照できるフォルダ。 Hello,Rails 4.1Webサーバーの起動 おさらい的な感じ サーバーを起動します。 $rails s 4.2画面にHelloを表示する Railsを画面上で表示するには、最低限ControllerとViewが必要。 更にルーティングの設定も必要になります。 まずはURLと画面を紐づけるためにルーティングを設定します。 ~/blog/config/routes.rb Rails.application.routes.draw do get "/articles" , to: "articles#index" end get "対象URL名" , to: "コントローラー名#アクション名"を追加しています。 getはHTTPメソッドを指定しています。 to:は"コントローラー名#アクション名"でコントローラーとビューの紐づけを行います。 るーていんぐの設定が完了したら次はコントローラーを生成します。 $rails generate controller Articles ※コントローラー名は原則複数形で定義します。今回はArticleの複数形Articlesです。2.Railsとはで紹介した規約の一部になります 生成が完了したら中身生成したコントローラーを確認して、アクションメソッド(index)を定義してあげましょう。 ※アクションメソッドとはルーティングにより指定されるときの名前です blog/app/controller/articles_controller.rb class ArticlesController < ApplicationController def index end end 次に画面表示のビューファイルを作って、中身を記述します。 ~blog\app\views\articles\index.html.erb <h1>Hello, Rails</h1> ControllerとViewを設定した時点で、routes.rbで定義した ~/blog/config/routes.rb get "/articles", to: "articles#index" でURLとコントローラーのアクション名とビューのファイルが紐づきます。 実際にアクセスすると下のようになります。 4.3アプリケーションのHomeを設定する http://localhost:3000 で開いてもArticlesに遷移させる方法があります。 config/routes.rbを開き、rootを追加します。 ~/blog/config/routes.rb get "/articles", to: "articles#index" 設定後に http://localhost:3000 を開くと、元々表示されていた画面がArticlesに変更されています。 さいごに 最後まで閲覧ありがとうございました。 記録として投稿しているため、間違っている部分や嘘をついている部分があるかもしれません。 もしお気づきの点がございましたらコメント等で教えてください。 今後もガイドに沿って理解を深めていこうと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オリジナルアプリ【BIKKE!!】README

本記事について オリジナルアプリ【BIKKE!!】がようやくRails+Puma+Docker+AWS(ECR,ECS.EC2,RDS,S3,Route53,VPC)でデプロイが完了しました。 そこで私のアプリの全貌を記載したREADMEを公開させていただきます。 アプリ名 BIKKE!! 概要 「ライダーにしか分からないことがある。」がコンセプトです。 乗ったことのあるバイク、所有するバイクのレビューを共有することができます。 また、レビューを今後のバイク選びの参考とすることができます。 バイク探しをしたい人、自分のバイクを共有したい人、バイクメーカーで働く人などバイクに携わる全ての人に価値を提供します。 本番環境 URL 非公開 ログイン情報 ゲストログイン機能を設けています。 トップページのヘッダーより、ワンクリックでゲストユーザーとしてログインが可能です。 ゲストユーザーは、レビューの投稿、検索、コメント、お気に入り登録といった機能が実行できます。 ※アカウント情報の編集・削除機能は実行できません。 制作背景 私自身ライダーであり、バイクが大好きです。 バイクの乗り換え、新規バイクの購入を検討する際、インターネットで検索しても、結果はバイクのスペックなどあくまでもカタログ上の数値であったり、 メディアが共有する専門的なインプレッション記事などがほとんです。 私はそこに課題を感じました。 なぜなら、バイクの良さとは乗ってみないと分からないことが多々あると考えているからです。 「ライダーにしか分からないことがある。」バイクの良さも悪さも、全てがバイク探しの重要なリソースです。 そんなバイク探しの指南となるアプリケーションを作成したいと考えたことが、本アプリケーションの制作背景となります。 DEMO トップページ(検索機能・レビュー一覧表示・ログイン機能) ・トップの写真には、ロード時に文字が浮き上がるようなアニメーションを付与しました。 ・ログイン画面もありますが、トップページからもログインができるようフォームを設置しています。 ・トップ中央に検索機能のコンポーネントがあります。 ・トップ下部にレビュー一覧が、スクロールによりふわっと浮き上がるアニメーションで表示されます。 ・レビューの一覧表示はページネーション機能を用いてコンパクトにまとめました。 また、ページネーションはBootstrapを用いてより見やすく、かつAjax通信により素早くページ切り替えが可能です。 新規登録画面 ・トップページヘッダーより遷移します。 ・必要な情報は「メールアドレス」「パスワード」「ニックネーム」のみとシンプルに仕上げました。 ・エラーメッセージは日本語化しております。 ・パスワードには正規表現のバリデーションを設け、セキュアにエラーメッセージを返します。 ・登録が完了すると、フラッシュメッセージでユーザーに登録が完了したことをアナウンスします。 ・ヘッダーにニックネームが表示されるようになります。 ログイン画面/ログアウト ・トップページヘッダーの「Log out」ボタンよりワンクリックでログアウトが可能です。 また、フラッシュメッセージでユーザーにログアウトが完了したことをアナウンスします。 ・トップページヘッダーの「Sign in」ボタンよりログイン画面に遷移します。 ・ログインに必要な情報は「メールアドレス」と「パスワード」のみです。 ・エラーメッセージは日本語化しています。 ・ログインに成功すると、トップページにリダイレクトされ、フラッシュメッセージでユーザーにログインが成功したことをアナウンスします。 ・トップページのヘッダーにニックネームが追加されます。 ・トップページ写真部分にあるログインフォームからも、ログインが可能です。 マイページ画面(ユーザーページ画面)・アカウント情報編集機能 ・トップページヘッダーに表示された、ニックネームをクリックし遷移します。 ・マイページ画面には、そのユーザーが投稿したレビューやお気に入りしたレビューを一覧で閲覧することができます。 ・表示されるレビュー一覧は、アニメーションで表示されます。 ・マイページ画面に遷移したユーザーが本人である場合、アカウント情報編集ボタンが表示されます。 ・マイページに遷移したユーザーが本人である場合、アカウント情報の編集が可能です。 ・メールアドレスやパスワード、ニックネームの変更が可能です。 ・変更を行わない項目は空白にすることで、そのまま保存されます。 ※ゲストユーザーはアカウント情報の編集は不可能です。 レビュー投稿画面 ・トップページヘッダーにあります「Post」ボタンからワンクリックでレビュー投稿画面に遷移します。 ・レビューの入力項目は写真、車種名、年式、排気量、メーカー、車種タイプ、乗り心地、燃費、メンテナンス性、維持費、速度、見た目の満足度、総合評価、レビューテキスト、で構成されています。 ・写真は任意項目で、そのほかは入力必須項目となります。 ・写真は1枚のみ投稿可能で、プレビュー表示されます。 ・車種名、レビューテキストは自由入力、年式は半角4桁入力、排気量、メーカー、車種タイプはActiveHashによるカテゴリー選択、 燃費、メンテナンス性、維持費、速度、見た目の満足度、総合評価はjQueryによる星評価でレビューを投稿します。 ・「投稿する」ボタン押下により、トップページにリダイレクトされ、フラッシュメッセージの案内とともに投稿が完了したことをお知らせします。 ・レビュー一覧に追加で表示されます。 ・一覧表示時に表示される項目は、写真、車種名、総合評価のみです。 レビュー詳細画面(お気に入り機能・コメント機能) ・一覧表示されたレビューからワンクリックでレビュー詳細画面に遷移します。 ・これは「マイページ(ユーザーページ)に表示されるレビュー一覧」、「検索結果として表示されるレビュー一覧」からも同様に、気になるレビューをワンクリックすることで詳細画面に遷移します。 ・詳細画面では、レビュー投稿で入力した全ての項目が表示されます。 ・ユーザーはあらゆる側面から気になるバイクのレビューを確認することができます。 ・レビュー詳細画面が投稿した本人のレビューである場合、「編集」ボタンと「削除」ボタンが表示されます。 ・レビューが投稿した本人のレビューではない場合、「お気に入り」登録ボタンが表示されます。 ・Ajax通信により、ワンクリックで即お気に入りに登録されます。 ・お気に入りしたレビューはマイページから一覧で管理することができます。 ・また、お気に入りの解除もワンクリックで可能です。 ・詳細画面ではコメントを投稿することが可能です。 ・レビュー投稿者に追加で質問がある場合などに便利です。 ・コメント投稿後、フラッシュメッセージで投稿が完了したことをお知らせし、詳細画面にリダイレクトします。 ・コメントは、投稿者、コメント内容、投稿時間で構成され、コメント投稿したユーザー本人である場合、コメント削除ボタンが表示されます。 レビュー編集画面・レビュー削除機能 ・レビュー詳細画面から、「編集」ボタンを押下し、編集画面に遷移します。 ・編集画面は投稿したユーザー本人のみが遷移可能です。URLを直接打ち込んでも他のユーザーは遷移できません。 ・編集画面は投稿した内容を全て保持しています。 ・ActiveHashによるカテゴリーの再選択、jQueryによる星評価の再評価も簡単に行うことができます。 ・詳細画面より「削除」ボタンを押下することで、レビューの削除が可能です。 ・アラートメッセージにより、本当に削除するか確認します。 ・確認時に「OK」ボタンを押下することにより、フラッシュメッセージが削除完了をお知らせします。 検索結果画面 ・トップページに全ての検索機能を設けています。 ・キーワード検索では、該当する車種名に一部分でも文字が含まれている場合、結果を返します。 ・検索結果に表示されるレビューはアニメーションにより、ふわっと表示されます。 ・排気量、メーカー、車種タイプはカテゴリーに該当するものをワンクリックで一覧表示させます。 ・排気量、メーカー、車種タイプ3つの項目を元に絞り込み検索も可能です。 ・必要ない項目は「指定なし」の状態で検索から省くことが可能です。 工夫したポイント 常にユーザー視点に立ち、ユーザーが「使いやすい、楽しい」と思えるようなUI/UXを意識して制作しました。 具体的なポイントとして、 ・初めてこのアプリを見ても、直感的に使用方法が理解できる。 ・アニメーションを用いて、視覚的な楽しみを作る。 ・なるべく画面遷移を少なく、ワンクリックで目的地に辿り着けるルーティング作成 ・jQueryやAjax通信により素早いレスポンスを与え、ストレスレスな操作感 などが工夫したポイントです。 苦労したポイント とにかくデプロイの一言につきます。 本アプリはDockerで開発したコンテナを、ECRにプッシュし、ECS(EC2)+VPC+RDS+S3でデプロイしたものに、Freenom+Route53でドメインを設定し本番運用しています。 過去にDockerを用いていないRailsをEC2にてデプロイをしたことがありますが、Dockerをデプロイすることは私にとって非常にハイレベルなものでした。 ネットワーク周りのエラー、接続されてもローカルでは出なかったRailsエラーにも悩まされました。 まずはDockerを再度基本から学び直し、そしてAWSでどのようにデプロイしたものが外部アクセスできるのか、学習に励み、その結果デプロイすることができました。 この経験は私の中でも非常に自信につながるものであり、引き続き学習に努め、より自分のものへと吸収していきたいと考えています。 使用技術(開発環境) サーバーサイド:Ruby on Rails フロントサイド:HTML, CSS, JavaScript, jQuery, Bootstrap テスト:RSpec インフラ:Docker, AWS(ECR+ECS+EC2+S3+VPC+S3+Route53), Freenom エディタ:VScode 課題・今後実現したい機能 レスポンシブデザイン化 現時点ではブラウザでのみしか表示が適応しておらず、スマホやタブレットサイズでも快適にアプリが使用できるレスポンシブデザイン化は必須と考えます。 具体的にはCSSにメディアクエリを用いて実装予定です。 アカウント削除機能 退会する機能が未実装であります。退会するまでのフローチャートをシンプルにして実装予定です。ただし、この機能はワンクリックでアカウントが削除されないように注意すべき点であると考えます。 検索機能の充実化 現在検索機能はトップページに集約されています。今後は検索結果ページにも検索機能を追加実装する予定です。 理由は、ユーザーが一度検索を行い、欲しい情報が得られなかった場合、少し範囲を広げて検索する行動が予測され、都度トップページに戻るのは煩わしいと考えるからです。 CI/CDパイプライン作成、デプロイの自動化 現在は下記の流れで手動デプロイを行っております。 ①ECRにイメージをプッシュ ②ECS・EC2インスタンスにSSH接続し、コンテナを再起動 特に手間があるわけでもなく、またローカルで動作をしっかり吟味した上でデプロイを行いたいので、性に合ってはいるのですが、今後はエンジニアで働くことをイメージして、CI/CDパイプラインによりgitからの自動デプロイが出来たらと考えています。 DB設計 ER図 usersテーブル Column Type Options email string null: false, unique: true encrypted_password string null: false nickname string null: false Association has_many :reviews has_many :comments has_many :likes reviewsテーブル Column Type Options bike string null: false year integer null: false displacement_id integer null: false maker_id integer null: false type_id integer null: false recommend float null: false comfort float null: false fuel float null: false maintenance float null: false cost float null: false speed float null: false look float null: false content text null: false user references null: false, foreign_key: true Association belongs_to :user has_many :comments has_many :likes commentsテーブル Column Type Options text text null: false user references null: false, foreign_key: true review references null: false, foreign_key: true Association belongs_to :user belongs_to :review likesテーブル Column Type Options user references null: false, foreign_key: true review references null: false, foreign_key: true Association belongs_to :user belongs_to :review
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Docker】【Rails】MySQL8.0にしたらログが出力されなくなった話

以前自分はMySQL5.7のイメージを使ってdbコンテナを立ち上げて、開発してました。 その時は docker-compose up を実行したら rails sみたいな eb_1 | Started GET "/" for 172.20.0.1 at 2021-06-12 13:36:48 +0000 web_1 | Cannot render console from 172.20.0.1! Allowed networks: 127.0.0.0/127.255.255.255, ::1 web_1 | Processing by DrinksController#index as HTML web_1 | User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 7 LIMIT 1 web_1 | ↳ app/helpers/sessions_helper.rb:52:in `current_user' web_1 | (0.6ms) SELECT COUNT(*) FROM `drinks` WHERE `drinks`.`user_id` != 6 AND (user_id IN (SELECT followed_id FROM relationships WHERE follower_id = 7) OR user_id = 7) web_1 | ↳ app/controllers/drinks_controller.rb:14:in `index' web_1 | web_1 | From: /coffee_passport/app/controllers/drinks_controller.rb:25 DrinksController#index: こんな感じのログが出てくれました。 ある日、本番環境がMySQL8系なので、 開発環境もMySQL8.0に統一した方がバグもすくなるなると考えて docker-compose.yml version: '3' services: db: image: mysql:8.0.21 cap_add: - SYS_NICE # コンテナにLinux機能を追加するオプションのようです。SYS_NICEは、プロセスの優先度(nice値)をあげます。 environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_HOST: db ports: - '3306:3306' volumes: - mysql-data:/var/lib/mysql command: --default-authentication-plugin=mysql_native_password # 認証方式を8系以前のものにする  このように書き換えて再度ビルドし docker-compose up を実行すると rails sみたいなログが出力されなくなってしまいました。 これはかなり不便なので色々調べると googleの3ページ目に http://hotatekun.hatenablog.com/entry/2021/04/04/224001 こんな感じの記事がありました。 puma.rb # workers ENV.fetch("WEB_CONCURRENCY") { 2 } # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code # before forking the application. This takes advantage of Copy On Write # process behavior so workers use less memory. # # preload_app! # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart app_root = File.expand_path("../..", __FILE__) bind "unix://#{app_root}/tmp/sockets/puma.sock" stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true どうしてpuma.rbをこのように編集したか覚えてないのですが、 puma.rb # stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true unless ENV.fetch("RAILS_ENV", "development") == "development" stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true end # puma.rbで、標準出力が log/puma.stdout.log にリダイレクトされていたのが原因だった。 # 開発環境ではファイルにリダイレクトしない形にしたらコンソールが表示されるようになった。 と変更することで docker-compose up を実行したら ターミナルにrails sみたいなログが出力されるようになりました。 docker-compose up -d が主流?みたいですが皆様は普段どんな感じでログを見てるか気になるところです。 binding.pryで処理は止まって web_1 | 17: .includes(:user)) web_1 | 18: web_1 | 19: @title = 'Timeline' web_1 | 20: web_1 | 21: @selected = 'Selected' web_1 | 22: web_1 | 23: @random_drinks = Drink.order('RAND()').limit(5) web_1 | 24: web_1 | => 25: binding.pry web_1 | 26: web_1 | 27: end このように表示されますが、 こっから何を入力しても反応がないので これからまたどうやってbinding.pryをしようかちゃんと調べて記事にします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Docker】【Rails】MySQL8.0にしたらログが出力されなくなったので解決した話

以前自分はMySQL5.7のイメージを使ってdbコンテナを立ち上げて、開発してました。 その時は docker-compose up を実行したら rails sみたいな eb_1 | Started GET "/" for 172.20.0.1 at 2021-06-12 13:36:48 +0000 web_1 | Cannot render console from 172.20.0.1! Allowed networks: 127.0.0.0/127.255.255.255, ::1 web_1 | Processing by DrinksController#index as HTML web_1 | User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 7 LIMIT 1 web_1 | ↳ app/helpers/sessions_helper.rb:52:in `current_user' web_1 | (0.6ms) SELECT COUNT(*) FROM `drinks` WHERE `drinks`.`user_id` != 6 AND (user_id IN (SELECT followed_id FROM relationships WHERE follower_id = 7) OR user_id = 7) web_1 | ↳ app/controllers/drinks_controller.rb:14:in `index' web_1 | web_1 | From: /coffee_passport/app/controllers/drinks_controller.rb:25 DrinksController#index: こんな感じのログが出てくれました。 ある日、本番環境がMySQL8系なので、 開発環境もMySQL8.0に統一した方がバグもすくなるなると考えて docker-compose.yml version: '3' services: db: image: mysql:8.0.21 cap_add: - SYS_NICE # コンテナにLinux機能を追加するオプションのようです。SYS_NICEは、プロセスの優先度(nice値)をあげます。 environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_HOST: db ports: - '3306:3306' volumes: - mysql-data:/var/lib/mysql command: --default-authentication-plugin=mysql_native_password # 認証方式を8系以前のものにする  このように書き換えて再度ビルドし docker-compose up を実行すると rails sみたいなログが出力されなくなってしまいました。 これはかなり不便なので色々調べると googleの3ページ目に http://hotatekun.hatenablog.com/entry/2021/04/04/224001 こんな感じの記事がありました。 puma.rb # workers ENV.fetch("WEB_CONCURRENCY") { 2 } # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code # before forking the application. This takes advantage of Copy On Write # process behavior so workers use less memory. # # preload_app! # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart app_root = File.expand_path("../..", __FILE__) bind "unix://#{app_root}/tmp/sockets/puma.sock" stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true どうしてpuma.rbをこのように編集したか覚えてないのですが、 puma.rb # stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true unless ENV.fetch("RAILS_ENV", "development") == "development" stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true end # puma.rbで、標準出力が log/puma.stdout.log にリダイレクトされていたのが原因だった。 # 開発環境ではファイルにリダイレクトしない形にしたらコンソールが表示されるようになった。 と変更することで docker-compose up を実行したら ターミナルにrails sみたいなログが出力されるようになりました。 docker-compose up -d が主流?みたいですが皆様は普段どんな感じでログを見てるか気になるところです。 binding.pryで処理は止まって web_1 | 17: .includes(:user)) web_1 | 18: web_1 | 19: @title = 'Timeline' web_1 | 20: web_1 | 21: @selected = 'Selected' web_1 | 22: web_1 | 23: @random_drinks = Drink.order('RAND()').limit(5) web_1 | 24: web_1 | => 25: binding.pry web_1 | 26: web_1 | 27: end このように表示されますが、 こっから何を入力しても反応がないので これからまたどうやってbinding.pryをしようかちゃんと調べて記事にします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails APIモード + MYSQLをherokuにデプロイする流れ

RailsのAPIモードでデータベースをMySQLとして作ったアプリを初めてherokuにデプロイする過程でハマったところがあるので、結局何が正しかったのかを記録として書いておこうと思います。初心者なので至らぬ箇所もあるかとは思いますが悪しからず。 環境 ・Windows10 ・Ruby 2.6.6 ・Rails 6.1.3 ・MySQL2 0.5 ・heroku 前提 ・herokuアカウント登録済 ・heroku CLIインストール済(コマンドラインで$ heroku使うため  インストールはこちらからhttps://devcenter.heroku.com/ja/articles/heroku-cli) ・herokuクレジットカード登録済み(clearDB使うため。無料です) デプロイするソースをコミット #デプロイするアプリのディレクトリに移動し $ cd ~ #初期化 $ git init #ディレクトリ以下のファイルを選択し $ git add --all #コミットする $ git commit -m "first commit" herokuにログインし、新規app作成 下記コマンドでブラウザからログインします $ heroku login デプロイするアプリのディレクトリでapp作成します。 $ heroku app:create <appの名前> これによりアプリの公開URLがhttps://(appの名前).herokuapp.comとなります。 ちなみにアンダーバーが使えないようです。 リモートリポジトリの確認 $ git remote -v リモートリポジトリ heroku https://git.heroku.com/(appの名前).git が作成されていることを確認します。 先にgit initでローカルリポジトリを作成してからheroku createしたので、リモートリポジトリは自動で追加されるようです。 DBの設定 herokuのDBはデフォルトでPostgreSQLに設定されているようで、MySQLを使う場合手動で設定する必要があるようです。 下記コマンドで作成 $ heroku addons:create cleardb:ignite cleardb:igniteはignite(無料プラン)でherokuでMySQLが使えるcleardbを利用するという意味です。ただ、これを利用するためには無料ではあるけれど本人確認のためにクレジットカードをherokuに登録する必要があります。https://heroku.com/verifyから登録できます。英語で住所登録するのが慣れないため面倒でした。 ※このサービスが住所変換に便利でした。http://judress.tsukuenoue.com/ DBの環境設定 cleardbのURLを確認します。 $ heroku config 次のようなものが確認できます。 CLEARDB_DATABASE_URL: mysql://<ユーザー名>:<パスワード>@<ホスト名>/<データベース名>?reconnect=true このURLの情報を参考に各変数を設定します。 $ heroku config:add DB_NAME='<データベース名>' $ heroku config:add DB_USERNAME='<ユーザー名>' $ heroku config:add DB_PASSWORD='<パスワード>' $ heroku config:add DB_HOSTNAME='<ホスト名>' $ heroku config:add DB_PORT='3306' $ heroku config:add DATABASE_URL='mysql2://<ユーザー名>:<パスワード>@<ホスト名>/<データベース名>?reconnect=true' ここで、最後の行の部分でDATABASE_URL='mysql2://~'のようにmysql2となっていることに注意して下さい。MySQL2を使用しているのであれば2を入れるのを忘れずに。 次にapp/config/database.ymlを修正します。 database.yml production: <<: *default database: <データベース名> #変更 username: <ユーザー名> #変更 password: <%= ENV['APP_DATABASE_PASSWORD'] %> cleardbのURLで確認したやつですね。 変更をコミットしておきます。 $ git add -all $ git commit -m "update" herokuにデプロイ リポジトリをherokuにpushします。 $ git push heroku master マイグレーション $ heroku rake db:migrate 問題がなければ次のコマンドでhttps://(appの名前).herokuaopp.comにアクセスできます。 $ heroku open 補足 自分はDATABASE_URL=のところでmysql2ではなくmysqlになっていたので詰まってしまったのですが、デプロイできない原因を調べている中でapplication.rbやproduction.rbファイルでassets関連の修正を加えることで改善するという記事を多く見かけました。何も考えずにこの辺をいじってしまったことでさらにハマってしまうという結果となりました。 結果的には、RailsのAPIモードで作成したアプリであればassets周りは触らなくていいことが分かりました。データを返すAPIとしての機能だけならassetsは必要ないというのは納得できますね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】enumで対応ステータスを更新する

自作アプリを作成しているときに、管理者機能として、フォームからのお問い合わせの対応ステータスを更新する機能があったらいいなと思い、調べながら実装してみたので、メモしておきます! 実装画面はこんな感じです? 前提 構成(モデル等は生成済の前提で進めます) MODEL (FormInquiry) t.integer "user_id" t.text "content" t.integer "response_status", default: 0 t.datetime "created_at" t.datetime "updated_at" CONTROLLER (form_inquiries) 問い合わせ一覧(index action) 問い合わせ詳細(show action) 対応ステータス更新(update action) VIEWS 問い合わせ一覧(index.html) 問い合わせ詳細(show.html) ライブラリ - enum_help(enumをI18n化するgem) - devise(ユーザー/管理者認証) その他 - 会員(エンドユーザー)をUser、管理者をAdminとしてそれぞれテーブルを作成しています。 - 会員からフォームで問い合わせを受け付けると、管理者の問い合わせ一覧画面に表示されます。 - 管理者は問い合わせ詳細画面を開き、対応ステータス(未対応/対応中/対応済)の更新を行えます。更新すると、フラッシュメッセージが表示され、問い合わせ一覧のステータスも更新されます。 環境 ruby 2.6.3 rails 5.2.6 OS:Linux(CentOS) IDE:Cloud9 実装 enumとは? 「列挙型」という、整数が割り当てられた文字列を順に出力していく変数のことで、0を男性、1を女性のように、整数の値に何かしらの意味づけを行ってデータを管理することができます。「hashのkey部分の定数を保存すると、そのkeyに対応するvalueの整数が保存される仕組み」とのこと(【Rails】 enumチュートリアルより) 今回は、以下のような値で進めていくことにします。 { 0: outstanding(未対応), 1: in_progress(対応中), 2: closed(対応済)} STEP1. enumの定義 ? FormInquiryモデルのresponse_statusカラムに対して、enumを定義します app/models/form_inquiry.rb belongs_to :user enum response_status: { outstanding: 0, in_progress: 1, closed: 2 } 次に、enumを日本語化します。 ? Gemfileにenum_helpを追記して、保存したらbundle installします。 Gemfile gem 'enum_help' ? 英語名に対応する日本語の値を、ja.ymlに定義します。 config/locales/ja.yml ja: time: formats: default: "%Y/%m/%d %H:%M" enums: form_inquiry: response_status: outstanding: "未対応" in_progress: "対応中" closed: "対応済" ? もしアプリケーションのデフォルト言語が日本語になっていない場合は、設定しておきます config/application.rb module App class Application < Rails::Application # 略 config.i18n.default_locale = :ja end end STEP2. コントローラーに記述 対応ステータスの更新はupdateアクションで行います。 更新できたら、問い合わせ詳細画面にリダイレクトし、フラッシュメッセージを表示するようにしています。 app/controllers/form_inquiry_controller.rb class Admin::FormInquiriesController < ApplicationController before_action :authenticate_admin! before_action :set_form_inquiry, only: [:show, :update] def index @form_inquiries = FormInquiry.all.includes(:user).order(created_at: "DESC").page(params[:page]).per(10) end def show @user = User.find(@form_inquiry.user_id) end def update if @form_inquiry.update(form_inquiry_params) redirect_to admin_form_inquiry_path(@form_inquiry), notice: "対応ステータスを更新しました" else render :show, alert: "対応ステータスを更新できませんでした" end end private def form_inquiry_params params.require(:form_inquiry).permit(:response_status) end def set_form_inquiry @form_inquiry = FormInquiry.find(params[:id]) end end STEP3. ビューの記述 問い合わせ詳細(show) ? 対応ステータスの更新は、問い合わせ詳細画面で行うため、show.html.erbにセレクトボックスを実装します(※該当部分のみ抜粋しています) app/views/form_inquiries/show.html.erb <%= form_with model: [:admin, @form_inquiry], method: :patch, local: true do |f| %> <%= f.select :response_status, FormInquiry.response_statuses.keys.map {|k| [I18n.t("enums.form_inquiry.response_status.#{k}"), k]} %> <%= f.submit "変更" %> <% end %> ここでは、enumの値(未対応/対応中/対応済)のセレクトボックスを作成するため、mapメソッド(配列の要素の数だけブロック内で処理を繰り返して、新しい配列を返すメソッド)を使用します。 ここで何をしているか確認しておくと、 keysメソッドでハッシュオブジェクトからキーのみ配列の形で取り出している(outstanding/in_progress/closed) I18nのtranslateメソッド(I18n.t)でenumのキーの内容を翻訳している keysメソッドで取り出した値一つ一つに対しmapメソッドで処理し、二次元配列(配列の中に、配列が格納された形の配列のこと)を戻り値として返す 試しにrails cで返り値を見てみると、こうなっています? [3]はtranslateメソッドを使わなかった場合を一応出力してみた形です。 二次元配列の2つ目の要素(["対応中", "in_progress"])を選択して、検証ツールで見てみると、この二次元配列の1つ目の要素がoptionタグの表示部分に、2つ目の要素がvalueに入る仕組みであることがわかります。 これが他2つの二次元配列に対しても展開されて、セレクトボックスが生成されているようですね。 問い合わせ一覧(index) ? 7〜13行目で、一覧に表示する対応ステータスをif文を使って分岐させています。 日本語化した定数の値を表示したいので、カラム名の末尾に_i18nを追記します。 app/views/form_inquiries/index.html.erb <table> <% @form_inquiries.each do |form_inquiry| %> <tr> <td><%= l form_inquiry.created_at %></td> <td><%= link_to form_inquiry.user.name, admin_user_path(form_inquiry.user.id) %></td> <td> <% if form_inquiry.response_status == 'outstanding' %> <%= form_inquiry.response_status_i18n %> <% elsif form_inquiry.response_status == 'in_progress' %> <%= form_inquiry.response_status_i18n %> <% else %> <%= form_inquiry.response_status_i18n %> <% end %> </td> <td> <%= link_to "詳細", admin_form_inquiry_path(form_inquiry.id), class:'btn btn-sm py-0 btn-outline-secondary' %> </td> </tr> <% end %> </table> これで対応ステータスが更新できるようになりました! keysメソッドやmapメソッドの部分は、個人的にまだ理解が難しいのですが、言語化することで理解が少し深まったように思います。何かお気づきの点があれば、ぜひご教示ください。 参考資料 【Rails】enumをI18n対応させるenum_helpが便利すぎた 【Rails】 enumチュートリアル 【Ruby】 mapメソッドの基礎から応用をマスターして、効率的なコードを書けるようにしよう! Rubyでハッシュオブジェクトからキーや値を取り出す方法【初心者向け】 【初心者向け】i18nを利用して、enumのf.selectオプションを日本語化する[Rails]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsでScrollTriggerを導入する【自分用メモ】

ScrollTriggerとは 2020年5月にGSAP(GreenSock Animation Platform)から生まれたスクロールアニメのためのライブラリです。とても少ないコードで実装でき、簡単にアニメーションが出来上がります。ドキュメントに動画付きで方法が乗っているので見てみてください。 今回はそんなライブラリを導入する方法を自分のためのメモとして残しておきます。 YouTube 導入方法 1,GSAPのモジュールをインストールします % yarn add gsap 2,gsap、ScrollTriggerをそれぞれimportします ※Nuxt.jsの場合は別の記述が必要なので、ドキュメントを参照してください application.js require("greensocks") import { gsap } from "gsap"; import { ScrollTrigger } from 'gsap/ScrollTrigger' 参照 ドキュメント 【2021年最新】GSAPの「ScrollTrigger」を使って爆速でスクロールアニメを実装する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】マージしていないにも関わらずdevelopのマイグレーションが更新された話

1.背景 現在、オンラインスクールにて共同開発に参加しており、タスクをGitHubのissueで管理しながら アプリを制作しています。 担当箇所の実装が終わると、マージする前にメンバー間のプルリクをローカルで確認してからメンターさんに確認して頂くようにしています。 ブランチ管理は以下のように行っており、featureブランチで作業→developブランチでマージという流れです。 ブランチ名 目的 備考 develop 開発用 機能実装用のブランチはここから切る feature/*** 機能実装用 派生元はdevelop 今回、マージしていない実装分の一部がdevelopブランチで更新されており、追加するかstash(回避)しないとブランチの切り替えができない状態でした。それを解消したのでまとめました。 2.環境 mac.os バージョン10.15.6 Ruby 2.7.2 Rails 6.1.3.1 psql (PostgreSQL) 12.6 3.今回起きていたこと ①origin/developとdevelopで差分が生じていた 状況を把握するために、origin/develop(リモートのdevelop)とdevelop(ローカルのdevelop)のコミットログを確認しました。 origin/developブランチのログ #origin/developブランチを確認 team_project % git fetch commit コミット番号 (HEAD -> origin/develop, origin/HEAD) Merge: マージしたコミット番号 Author: 人 <アドレス> Date: 日付 Merge pull request #41 from プロジェクト名/feature/*** Aを実装(プルリクのタイトル) ... ローカルのdevelopブランチのログ #developブランチで確認 team_project % git log commit コミット番号 (HEAD -> develop) Author: 人 <アドレス> Date: 日付 Bを実装 commit コミット番号 Merge: マージしたコミット番号 Author: 人 <アドレス> Date: 日付 Merge pull request #41 from プロジェクト名/feature/*** Aを実装(プルリクのタイトル) ... ローカルのdevelopブランチ上でBを実装というコミットをしており、ローカルのdevelopブランチが1つ進んでいる状態なので(本来は自分の作業ブランチでコミットが進んでいる以外はorigin/developとdevelopのコミットログは同じでないといけない)、origin/developブランチに戻す(同じ状態にする)コマンドを実行しました。 # developブランチ上で実行 team_project % git reset --hard origin/develop developブランチの差分がなくなり、再度rails db:migrateするとschemaが更新され、マージしていないモデルの実装が追加されました。原因はこれではありませんでした ②featureブランチでマイグレーションの更新をした後にリセットすることを忘れていた プルリクの確認を行うため、ローカルのdevelopブランチにプルリク分を取り込みます。 team_project % git switch develop # プルリク番号とブランチ名を確認 team_project % git fetch origin pull/プルリク番号/head:ブランチ名 team_project % git switch feature/*** # 今回はrails gでモデルとマイグレーションファイルを作成しているのでmigrateする team_project % rails db:migrate # feature/***ブランチで確認 team_project % rails db:migrate:status database: team_project_development Status Migration ID Migration Name -------------------------------------------------- up 年月日時      Create A up 年月日時 Create B up 年月日時 Devise create users up 年月日時 Devise create admin users up 年月日時 Create C  ★今回実装して増えた分 statusを確認すると、5つマイグレーションファイルが確認できます。 動作確認を行った後、そのままdevelopブランチに切り替えました。 # developブランチで確認 team_project % rails db:migrate:status database: team_project_development Status Migration ID Migration Name -------------------------------------------------- up 年月日時      Create A up 年月日時 Create B up 年月日時 Devise create users up 年月日時 Devise create admin users up 年月日時 ********** NO FILE ********** ★今回実装して増えた分 developブランチではマイグレーションファイルは存在しないのでNO FILEと表示されますが、statusは引き継がれます。その結果、developブランチでrails db:migrateをした際にdb/schema.rbにCモデルの内訳が更新されてしまった...ということでした。 4.マイグレーションを修正する対処法 パターン1:データベースを空にして再度入れ直す 今回の共同開発のデータはcsvデータを使用しており、またテストコードを手入力している訳ではないので データを空にする→再度入れ直すことで最新のdevelopブランチの状態にしました。 # developブランチで行う team_project % rails db:migrate:reset team_project % rails db:seed team_project % git status # 差分が出てこなくなった On branch develop Your branch is up to date with 'origin/develop'. nothing to commit, working tree clean パターン2:rollbackを使う featureブランチで行います。 developブランチ上で変更分を取り込むもしくはstash(回避)をしないとブランチの切り替えができないため、git checkout .コマンドで回避します。 team_project % git checkout feature/*** error: Your local changes to the following files would be overwritten by checkout: db/schema.rb Please commit your changes or stash them before you switch branches. # 変更を回避する team_project % git checkout . team_project % git checkout feature/*** # featureブランチで行う team_project % rails db:rollback team_project % rails db:migrate:status database: team_project_development Status Migration ID Migration Name -------------------------------------------------- up 年月日時      Create A up 年月日時 Create B up 年月日時 Devise create users up 年月日時 Devise create admin users # 今回実装して増えた分(Create C)が消える # developブランチに切り替えてmigrateを行う team_project % git checkout develop team_project % rails db:migrate こちらのrollbackはマイグレーションファイルが存在しない場合は実行ができないので、 今回のケース(↓)だとdevelopブランチではエラーとなります。(そのため、featureブランチでしかできませんでした。) # developブランチで確認 team_project % rails db:migrate:status database: team_project_development Status Migration ID Migration Name -------------------------------------------------- up 年月日時      Create A up 年月日時 Create B up 年月日時 Devise create users up 年月日時 Devise create admin users # rollbackしたくてもできない... up 年月日時 ********** NO FILE ********** 5.まとめ マージしていない場合でもマイグレーションファイルのstatusが引き継がれると知らなかったため、勉強になりました。 これからもエラーが出た際も一つ一つ検証し、解決したいと思います。 6.参考 1.リモートリポジトリfetch 2.gitでいろいろ取り消したい 7.最後に 記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。 読んでいただき、ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails link_toメソッドで開いたリンクを新しいタブで開くようにしたい。

通常、link_toメソッドで設定したリンクは普通にそのタブで開かれます。 ユーザー目線に立った時に、それが自分のサイト内であれば、問題ないと思いますが、特に外部リンクに行く時は新しいタブの方が便利だなぁと感じます。 ということで、link_toを使って新しいタブで開くリンクの設定方法 <%= link_to "#{archive.archiveurl}",:onclick=>"window.open(this.href,'#{archive.archiveurl}', 'height=400, width=800');return false;" do %> <% end %> こんな感じになりました。 私の場合はdo~endで結んでいますが、単純にリンクを設置するということであれば、特に必要はありません。 問題はonclick以降。 これをすることで、クリックされた時の挙動が選択できます。 参考文献 https://sakuramochi702.hatenablog.com/entry/2013/05/28/225612
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Rails 6のbundle installが重すぎる

Ruby on Rails 6にしてから、bundle installにかなり時間がかかるようになってしまった。 Dockerを使って開発・デプロイをしているのだが、新規作成したばかりのプロジェクトでもCloud Build上でのビルドに10分以上かかってしまう状況だ。 原因: sasscのインストールが遅い 調べてみるとbundle installで発生する時間のうち、ほとんどの時間はsasscのインストールで発生している。同様の報告は多数上がっている。 sass/sassc-ruby - sassc is very slow to compile and install #189 Up to version 2.1.0, sassc shipped precompiled Linux binaries, but as of 2.2.0, the only precompiled versions are for mingw32. ... In the meantime, a workaround might be to pin sassc-ruby to version 2.1.0. Rails: Why is bundle install frozen up by sassc 2.4.0 Using an older version of sass solves the issue. I advise changing 6 to 5.1.0 in the Gemfile. This file will be located in your rails folder (the name you used when creating a new rails) sassc 2.2.0以降でmigw32用以外のコンパイル済みバイナリが含まれなくなり、linux系の環境ではbundle install時にネイティブビルドが発生することが直接的な原因のようだ。どうやら不具合ではなく、意図的にLinux系のコンパイル済みバイナリを含めるのをやめたようだ。 対策: 古いバージョンのsasscを指定するか、sass-railsのバージョンを下げる ワークアラウンドとして、sasscの2.1系を使うかsasscに依存しているsass-railsのバージョンを下げる方法が紹介されている。 基本的にはsasscのバージョンを下げる方が影響範囲が小さくて良さそうだ。 sass-rails(が参照しているsassc-rails)の最新版のdependencyをみると、必要なsasscのバージョンは「2.0以上」となっているので、2.1に下げることは可能だ。 # Use SCSS for stylesheets gem 'sassc', '2.1.0' gem 'sass-rails', '6' 結果: Cloud Buildでのビルド時間は10分から4分に短縮 sasscのバージョンを2.1に下げたことで、bundle installにかかる時間が大幅に短くなった。Cloud Buildでのビルドでも、10分かかっていたものが4分まで短縮され、大分開発・デプロイが快適になった。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

再生数が多いもの上位5件をViewに表示したい。

桃鈴ねねさんのファンサイトを勝手に作ってます。 別記事でアーカイブ一覧表示することには成功してますが、サイトの誘導的に、アーカイブページ開いたら、全部表示されるのはさぞ迷惑なので、ブログやYouTubeであるオススメ動画というものを作りたい。 テーブル構成的にオススメ度合いを判断するのは再生数くらいなものなので、再生数が多いものを何件か表示したい。 app/controllers/home_controller.rb class HomeController < ApplicationController def index @archivetop = Archive.order(archiveviews: :desc).limit(14) end end 結論から言えばこんな感じになりました。 orderメソッドで昇順、降順を選択でき、その条件に再生数のカラムであるarchiveviewsを選択しておきます。 さらにlimitで上位14件を表示します。 と、その前にこのメソッドがちゃんと効いているのか確認したい。 ターミナルで rails c を入力し、 Archive.order(archiveviews: :desc).limit(5) とりあえず5件で。 => #<ActiveRecord::Relation [#<Archive id: 34, archiveid: "YeUkeAq1Dqg", archivetitle: "【 #桃鈴ねね3D 】?桃鈴ねね3Dお披露目!?【ホロライブ/桃鈴ねね】", archiveviews: 966420, archivepostdate: "2021-04-18 12:07:56", archiveurl: "https://www.youtube.com/watch?v=YeUkeAq1Dqg", archiveimg: "http://img.youtube.com/vi/YeUkeAq1Dqg/hqdefault.jp...", created_at: "2021-06-08 00:00:00", updated_at: "2021-06-08 00:00:00">, #<Archive id: 93, archiveid: "VMLjEUYLSy0", archivetitle: "【 #桃鈴ねね新ビジュアル】NEW SUPERNENECHI【桃鈴ねね/ホロライブ】", archiveviews: 718431, archivepostdate: "2021-01-31 12:06:35", archiveurl: "https://www.youtube.com/watch?v=VMLjEUYLSy0", archiveimg: "http://img.youtube.com/vi/VMLjEUYLSy0/hqdefault.jp...", created_at: "2021-06-08 00:00:00", updated_at: "2021-06-08 00:00:00">, #<Archive id: 92, archiveid: "kKqcQADSoIM", archivetitle: "【歌ってみた】私、アイドル宣言【ホロライブ/桃鈴ねね(cover)】", archiveviews: 652017, archivepostdate: "2021-01-31 12:30:14", archiveurl: "https://www.youtube.com/watch?v=kKqcQADSoIM", archiveimg: "http://img.youtube.com/vi/kKqcQADSoIM/hqdefault.jp...", created_at: "2021-06-08 00:00:00", updated_at: "2021-06-08 00:00:00">, #<Archive id: 267, archiveid: "fJ7ueGLuXk8", archivetitle: "【初配信!】ホロライブ5期生、桃鈴ねねある?【#ほろふぁいぶ】", archiveviews: 548034, archivepostdate: "2020-08-13 13:10:39", archiveurl: "https://www.youtube.com/watch?v=fJ7ueGLuXk8", archiveimg: "http://img.youtube.com/vi/fJ7ueGLuXk8/hqdefault.jp...", created_at: "2021-06-08 00:00:00", updated_at: "2021-06-08 00:00:00">, #<Archive id: 220, archiveid: "aCAMZvLX1Gs", archivetitle: "【マリオカート8DX】ペーパー最強!【ホロライブ/桃鈴ねね】", archiveviews: 529678, archivepostdate: "2020-09-20 14:23:57", archiveurl: "https://www.youtube.com/watch?v=aCAMZvLX1Gs", archiveimg: "http://img.youtube.com/vi/aCAMZvLX1Gs/hqdefault.jp...", created_at: "2021-06-08 00:00:00", updated_at: "2021-06-08 00:00:00">]> 結果はこんな感じで、大丈夫そうですね。 というか今気がついたんだけど、私、アイドル宣言の歌ってみたが3番目に多い再生数になってましたね。 少し前までは初配信だったはず。 個人的にはすごい素敵な歌声なんで、嬉しいです。 どうでも良い話はこんなところで。 こういう具合でテーブルに格納した情報もメソッドを組み合わせて、インスタンス変数に入れることで、Viewに表示することも可能です。 あとは app/views/home/index.html.erb <h2 class="major">Archives</h2> <h3>オススメ動画</h3> <div class="archive"> <%= render partial: "archivetop" , collection: @archivetop %> </div> <ul class="actions"> <li><a href="#" class="button">その他のアーカイブはこちらから</a></li> </ul> app/views/home/_archivetop.html.erb <div class = "archive_card"> <%= image_tag (archivetop.archiveimg) , class: :music_img %> <p><%= archivetop.archivetitle %></p> </div> renderメソッド、collectionオプションを使用すれば、 こんな感じで綺麗に纏まりました。 参考文献 https://qiita.com/Hal_mai/items/babb19560ace072c99f5
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Rails ログイン機能1 勉強用

deviseのインストール rails generate devise:install セットアップ 1. config/environments/development.rbファイルのendの前に記載 config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } 2.rootパスの設定 config/routes.rbファイルのendの前に記載 root to: "home#index" 3.flash messages(メッセージを表示する設定) app/views/layouts/application.html.erbフォルダのbodyに記載 <%# もしflash[:notice]があった場合表示させる %> <% if flash[:notice]%> <div class = "notification is-info"> <p class="notice"><%= notice %></p> </div> <% end %> <%#  エラーメッセージ %> <%#  もしflash[:alert]があった場合表示させる %> <% if flash[:alert]%> <div class = "notification is-danger"> <p class="alert"><%= alert %></p> </div> <% end %> 4.ターミナルで実行 実行するとviewsファイルにdeviseファイルが作られる ログイン画面 sessions/new.html.erb 新規登録画面 registrations/new.html.erb rails g devise:views
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Webアプリデプロイ方法(AWS EC2編)

目次 1.はじめに 2.前提 3.新規ユーザ作成 4.各種ソフトウェアインストール 5.githubからのアプリクローン 6.アプリのシークレット設定 7.webサーバ設定 8.applicationサーバ設定 9.db設定 10.アプリ起動 11.まとめ 12.参考 はじめに 前回の記事「Webアプリ公開のためのインフラ環境をCloudFormationで構築してみた」を通し、Webアプリデプロイ用のインフラ環境を準備することができました。今回は作成したAWS EC2上に、RailsのWebアプリをデプロイしましたので、大まかな手順を整理します。 前提 前回、CloudFormationで構築した以下のAWS構成にて、EC2上にRailsのWebアプリをデプロイしていきます。 ■ デプロイするWebアプリ 個人的に以下、学習系のWebアプリを開発してみましたので、こちらをデプロイしてみます。 WebアプリURL : https://www.memory-tank.ga/ (PC推奨) Rails:6.0.3 Ruby:2.6.5 概要 効率的なナレッジ蓄積と知識定着を支援するアプリ。 ユーザは様々なWord(単語)や自作の四択問題をカテゴリ別に管理した上で蓄積することができる。 また、蓄積したWordや四択問題はユーザ自身の定着率/正答率に応じて、習得済と未習得の2つのカテゴリに分割して自動管理される。 以降、実際のデプロイの手順を記載していきますが、まずは全体像、大まかな流れをまとめます。 作業概要 内容 新規ユーザ作成  アプリ管理用のOSユーザを作成する 各種ソフトウェアインストール プラグイン/MySQL/Node.js/rbenv/ruby-build/Rubyをインストールする GitHubからのアプリクローン  GitHubからEC2上にアプリをクローン/配置する アプリのシークレット設定  アプリのシークレットを生成し、設定する Webサーバ設定  Nginxの設定ファイルを修正する Applicationサーバ設定  Unicornの設定ファイルを修正する DB設定  DBへのアクセスに関わる設定ファイルを修正する アプリ起動  Nginx/Unicornを起動する 新規ユーザ作成 AWSのEC2インスタンスを作成するとデフォルトユーザ「ec2-user」が使えますが、複数人でアプリを管理していくことを想定し、ここでもう1つの管理用OSユーザを作成しておきます。 EC2へのログイン ローカル環境 #ローカル環境で、EC2インスタンスの秘密鍵が格納されたパスに移動する $ cd ~/.ssh #秘密鍵を指定し、ec2-userでEC2にログインする (yes/noを聞かれるので、yesと入力する) $ ssh -i 秘密鍵の名前.pem ec2-user@EC2のElasticIPアドレス 新規ユーザの作成 EC2 #adduserの後ろに、作成したいユーザのユーザ名を指定する $ sudo adduser ユーザ名 新規ユーザのパスワード設定 EC2 #以下のコマンドを実行後、設定したいパスワードを求められるので入力する $ sudo passwd ユーザ名 新規ユーザのsudo権限を設定 EC2 #visudoファイルを編集する $ sudo visudo 1. 以下の、rootに関する権限の記述箇所を探す   root ALL=(ALL) ALL 2. 「i」を入力して、入力モードに切り替える 3. 1で探した行の下に以下の記述を追記する ※ 新規作成ユーザの権限設定   ユーザ名 ALL=(ALL) ALL 4. 「esc」を押して入力モードを終了する 5. 「:wq」を入力後、エンターを押して編集を完了する 新規ユーザへの切り替えができることの確認 EC2 #以下を実行後、プロンプトの[ec2-user|の表示が新規作成のユーザ名に切り替わればOK $ sudo su - ユーザ名 EC2へSSH接続をするための鍵をローカル環境で作成 ローカル環境 #.sshディレクトリに移動する $ cd ~/.ssh #以下のコマンドでSSHの鍵を作成する $ ssh-keygen -t rsa -------------------------------- #以下のメッセージが表示されるので、「任意の名前_key_rsa」を入力する Enter file in which to save the key ():任意の名前_key_rsa #何もせずにエンターを押す Enter passphrase (empty for no passphrase): #何もせずにエンターを押す Enter same passphrase again: -------------------------------- 秘密鍵/公開鍵が作成されたことの確認 ローカル環境 #lsコマンド実行後、秘密鍵「任意の名前_key_rsa」と公開鍵「任意の名前_key_rsa.pub」が表示されることを確認する $ ls ~/.ssh/config (SSH経由でリモートサーバーに接続する際に利用される設定ファイル)の編集 ローカル環境 #~/.ssh/configファイルを編集する $ vi config 1. 「i」を入力し、入力モードに切り替え、以下を追記する -------------------------------- #Hostの後ろに、先ほど作成した秘密鍵の名前を記載する Host 任意の名前_key_rsa #Hostnameの後ろに、EC2のElastic IPアドレスを記載する Hostname EC2のElastic IPアドレス #ポート番号22番を指定する Port 22 #Userの後ろに、先ほど作成した新規ユーザのユーザ名を記載する User ユーザ名 #IdentityFileの後ろに、先ほど作成した秘密鍵のフルパスを記載する IdentityFile ~/.ssh/任意の名前_key_rsa -------------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する 公開鍵の中身をコピー ローカル環境 #公開鍵の中身をcatコマンドで出力し、全文をコピーする $ cat 任意の名前_key_rsa.pub サーバ側で公開鍵を設定 (先ほど作成したユーザで実施する) EC2 #公開鍵格納用のディレクトリを作成する $ mkdir .ssh #作成したディレクトリのアクセス権限を設定する $ chmod 700 .ssh #作成したディレクトリに移動する $ cd .ssh #公開鍵を記録するファイルを作成する $ vi authorized_keys 1. 「i」を入力し、入力モードに切り替え、以下を追記する ---------------------------------------- ローカル環境でコピーした公開鍵の中身を貼り付ける ---------------------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #公開鍵を記録するファイルのアクセス権限を設定する $ chmod 600 authorized_keys #新規作成ユーザからサインアウトする $ exit #ec2-userからサインアウトする $ exit 新規作成ユーザでのSSH接続確認 ローカル環境 #作成した秘密鍵を指定し、EC2にSSH接続をする $ ssh 任意の名前_key_rsa 無事にログインができたら、最初のステップ「新規ユーザ作成」は完了です。 各種ソフトウェアインストール 次に、Webアプリを動かす上で必要な各種ソフトウェアをインストールしていきます。 Nginxは前回記事のCloudFormationにて、EC2のユーザデータよりインストール済で自動起動設定もしてあります。 サーバのアップデート EC2 #まずはEC2内のソフトウェアをアップデートしておきます。 $ sudo yum update -y 各種プラグインのインストール EC2 #Git/コンパイル用コマンド/コンパイラ/パッチ適用コマンド/OpenSSL用ファイル/Ruby用パッケージ/アプリ開発用ライブラリ $ sudo yum install git make gcc-c++ patch openssl-devel libyaml-devel libffi-devel libicu-devel libxml2 libxslt libxml2-devel libxslt-devel zlib-devel readline-devel MySQL 5.7 のインストール EC2 #MySQL公式のyumリポジトリを追加 $ sudo rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm #MySQLをインストール $ sudo yum install mysql-devel mysql57 mysql57-server $ sudo yum install mysql mysql-server mysql-utilities Node.js 15.5 のインストール EC2 #Node.jsのバージョン管理ツールnvmをインストールする $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash #以下コマンド実行後、プロンプトに「nvm」と表示されることを確認する $ command -v nvm #上記で「nvm」が表示されなかった場合は以下を実行する $ source ~/.bash_profile #Node.jsをバージョン指定でインストールする $ nvm install 15.5.0 rbenvのインストール EC2 #rbenv (rubyのバージョン管理ツール)をインストールする $ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv #パスを通す $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile #shims と autocompletion の有効化設定を追記 $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile #設定ファイルを反映させる $ source ~/.bash_profile ruby-build のインストール EC2 #ruby-build (rubyのビルドツール)をインストールする $ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build # ~/.rbenv/versions/*/bin/ 以下のファイルを ~/.rbenv/shims/ 以下にコピーする $ rbenv rehash Rubyのインストール EC2 #ローカル環境で開発したアプリのRubyバージョンと同じバージョンを指定し、インストールする $ rbenv install -v 2.6.5 #使用するRubyのバージョンを指定する $ rbenv global 2.6.5 # ~/.rbenv/versions/*/bin/ 以下のファイルを ~/.rbenv/shims/ 以下にコピーする $ rbenv rehash # Rubyのバージョンを表示し、インストールしたものと同じになっていることを確認する $ ruby -v ここまでで「各種ソフトウェアインストール」は完了です。 githubからのアプリクローン 次に、GitHubから、開発したアプリをEC2上にクローンしていきます。 設定ファイルの作成 EC2 #ホームディレクトリに移動 $ cd ~ #gitの設定ファイルを作成する $ vi .gitconfig 1. 「i」を入力し、入力モードに切り替え、以下を追記する -------------------------------- [user] name = gitに登録した自分の名前 email = git登録時の自分のメールアドレス #pull、pushのための設定 [url "github:"] InsteadOf = https://github.com/ InsteadOf = git@github.com: -------------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する アプリ配置のディレクトリ作成 EC2 #ルートディレクトリに移動 $ cd / #var/wwwディレクトリを作成 $ sudo mkdir var/www #var/www/railsディレクトリを作成 $ sudo mkdir var/www/rails #varディレクトリの所有者を新規作成ユーザにする $ sudo chown ユーザ名 var #varディレクトリに移動する $ cd var/ #www配下の所有者を新規作成ユーザにする $ sudo chown -R ユーザ名 www git接続用の鍵作成 EC2 #ホームディレクトリに移動する $ cd ~ #.sshディレクトリの権限を設定する $ chmod 700 .ssh #.sshディレクトリに移動する $ cd .ssh #sshの鍵を作成する $ ssh-keygen -t rsa -------------------------------- 以下のメッセージが表示されるので、「ec2_git_rsa」と入力する Enter file in which to save the key ():ec2_git_rsa 何もせずにエンターを押す Enter passphrase (empty for no passphrase): 何もせずにエンターを押す Enter same passphrase again: -------------------------------- #lsコマンドを実行後、秘密鍵「ec2_key_rsa」と公開鍵「ec2_key_rsa.pub」が表示されることを確認する $ ls #設定ファイルを作成する $ vi config 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- Host github github.com Hostname github.com User git IdentityFile ~/.ssh/ec2_git_rsa ----------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #公開鍵の中身をcatコマンドで出力し、全文をコピーする $ cat ec2_git_rsa.pub 公開鍵をGitHubにアップ GitHubの「settings」→ 「SSH and GPG keys」を押下する 「New SSH key」を押下する 「Title」に先ほど作成した公開鍵名、「Key」に先ほどコピーした公開鍵の中身を入力し、「Add SSH key」を押下する EC2 #ターミナルへ戻り設定ファイルの権限を変更しておく $ chmod 600 config GitHubからアプリをクローン EC2 # /var/www/railsディレクトリに移動する $ cd /var/www/rails # アプリをクローンする $ git clone クローンしたいアプリのGitHubのURL #lsコマンド実行後、各自のアプリディレクトリ/ファイルが表示されればOK $ ls #アプリのディレクトリに移動する $ cd アプリ名 #Gemのインストール $ bundle install #「bundle install」で「Could not find 'bundler' 〜」、「To update to the latest version installed on your system, run `bundle update --bundler`.」のエラーが出た場合は以下を実施してからリトライする。 $ gem update bundler ※ アプリのURLはGitHubで「Code」→ 赤枠内のアイコンを押下するとコピーができる ここまでで「githubからのアプリクローン」は完了です。 アプリのシークレット設定 次にアプリのシークレット設定をしていきます。 マスターキーの作成 ローカル環境(開発したアプリのディレクトリ内で実施) #以下を実行し、表示されるマスターキーコピーする $ vi config/master.key 「:q!」を入力後、エンターを押して特に編集をせずに完了する EC2(クローンしたアプリのディレクトリ内で実施) #configディレクトリに移動 $ cd config #マスターキーの作成 $ vi master.key 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- 先ほどコピーしたマスターキーの値 ----------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する シークレットの作成 ローカル環境(開発したアプリのディレクトリ内で実施) #以下コマンドで表示されたシークレットキーをコピーする $ bundle exec rake secret EC2(クローンしたアプリのディレクトリ内で実施) #アプリのディレクトリ直下に移動する $ cd /var/www/rails/アプリ名 #credentials.yml.encを編集する $ EDITOR=vi bin/rails credentials:edit 1. 「i」を入力し、入力モードに切り替え、以下を編集する ----------------------------- # aws: # access_key_id: 123 # secret_access_key: 345 # Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies. secret_key_base: 先ほどコピーしたシークレットキーをペースト ----------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する ここまでで「アプリのシークレット設定」は完了です。 webサーバ設定 次にWebサーバ設定として、Nginxの設定ファイルを編集していきます。 設定ファイル編集 EC2(クローンしたアプリのディレクトリ内で実施) #nginxのディレクトリに移動する $ cd /etc/nginx/conf.d/ #設定ファイルを編集する ※ アプリ名の部分は各自、変えてください。 $ sudo vi アプリ名.conf 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- # log directory #エラーログのパス指定 error_log /var/www/rails/アプリ名/log/nginx.error.log; #アクセスログのパス指定 access_log /var/www/rails/アプリ名/log/nginx.access.log; #unicornとの接続設定 upstream unicorn_server { server unix:/var/www/rails/アプリ名/tmp/sockets/.unicorn.sock fail_timeout=0; } server { listen 80; client_max_body_size 4G; server_name 各自のアプリのドメイン名 keepalive_timeout 5; # Location of our static files root /var/www/rails/アプリ名/public; location ~ ^/assets/ { root /var/www/rails/アプリ名/public; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; if (!-f $request_filename) { proxy_pass http://unicorn_server; break; } } error_page 500 502 503 504 /500.html; location = /500.html { root /var/www/rails/アプリ名/public; } } ----------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する ここまでで「webサーバ設定」は完了です。 applicationサーバ設定 次にApplicationサーバ設定として、Unicornの設定ファイルを編集していきます。 Unicornのインストール EC2(クローンしたアプリのディレクトリ内で実施) #アプリのディレクトリ直下に移動する $ cd /var/www/rails/アプリ名 #Gemfileを編集する $ vi Gemfile 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- group :production, :staging do gem 'unicorn' end ---------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #Unicornをインストールする $ gem install bundler $ bundle install 設定ファイルの編集 EC2(クローンしたアプリのディレクトリ内で実施) #設定ファイルを編集する ※ アプリ名の部分は各自、変えてください。 $ vi config/unicorn.conf.rb 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- # set lets $worker = 2 $timeout = 30 $app_dir = "/var/www/rails/アプリ名" $listen = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir $pid = File.expand_path 'tmp/pids/unicorn.pid', $app_dir $std_log = File.expand_path 'log/unicorn.log', $app_dir # set config worker_processes $worker working_directory $app_dir stderr_path $std_log stdout_path $std_log timeout $timeout listen $listen pid $pid # loading booster preload_app true # before starting processes before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! old_pid = "#{server.config[:pid]}.oldbin" if old_pid != server.pid begin Process.kill "QUIT", File.read(old_pid).to_i rescue Errno::ENOENT, Errno::ESRCH end end end # after finishing processes after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end ----------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する ここまでで「applicationサーバ設定」は完了です。 db設定 次にDBアクセスの設定をしていきます。 dotenv-rails (環境変数を管理するGem)の導入 EC2(クローンしたアプリのディレクトリ内で実施) #Gemfileを編集する $ vi Gemfile 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- gem 'dotenv-rails' ---------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #dotenv-railsをインストールする $ bundle install #以下コマンドを実行し、表示されるシークレットキーをコピーする $ bundle exec rake secret #.envファイルの作成 $ touch .env #.envファイルの編集 $ vi .env 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- SECRET_KEY_BASE=先ほどコピーしたシークレットキー DB_NAME=RDSのDB名 DB_USERNAME=RDSのユーザー名 DB_PASSWORD=RDSのパスワード DB_HOSTNAME=RDSのエンドポイント ---------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #設定ファイルを反映させる $ source .env #設定した値が表示されることを確認する $ echo $SECRET_KEY_BASE $ echo $DB_NAME $ echo $DB_USERNAME $ echo $DB_PASSWORD $ echo $DB_HOSTNAME database.ymlの編集 EC2(クローンしたアプリのディレクトリ内で実施) #.database.ymlファイルの編集 $ vi config/database.yml 1. 「i」を入力し、入力モードに切り替え、以下の編集をする ----------------------------- production: <<: *default database: <%= ENV['DB_NAME'] %> username: <%= ENV['DB_USERNAME'] %> password: <%= ENV['DB_PASSWORD'] %> host: <%= ENV['DB_HOSTNAME'] %> ---------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #MySQLを起動する $ sudo systemctl start mysqld #マイグレーションを実行する $ bundle exec rake db:migrate RAILS_ENV=production ここまでで「db設定」は完了です。 アプリ起動 以上で、各種設定が完了しましたので、最後にアプリを起動していきます。 各種起動 EC2 #アプリのプリコンパイルをする $ bundle exec rake assets:precompile RAILS_ENV=production #プリコンパイルが正常に終了せず、「yarn」のエラーが発生した場合は以下を実施後にリトライする $ npm install -g yarn $ yarn upgrade #Nginxを再起動する $ sudo systemctl restart nginx #Unicornを起動する $ bundle exec unicorn_rails -c /var/www/rails/アプリ名/config/unicorn.conf.rb -D -E production #Unicornの起動を確認する。以下コマンド実行後、プロセスが3行程度表示されること $ ps -ef | grep unicorn | grep -v grep 稼働確認 ブラウザより独自ドメインにてアクセスをし、無事に画面が表示されることを確認する まとめ 以上で、RailsのアプリをAWS EC2上にデプロイすることができました。アプリのデプロイにはAWS CodeDeployやECSなど、他のサービスも使用できるため、今後はそちらについても学習してみたいと思います。 参考 この記事は以下の情報を参考にして執筆しました。 【画像付きで丁寧に解説】AWS(EC2)にRailsアプリをイチから上げる方法【その3〜サーバー設定とRailsアプリの配置編〜】
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails] 中間テーブルの特定のレコードを削除する

はじめに 私が作成中のオリジナルアプリで中間テーブルの特定の一つのレコードを削除したいときに、起こったエラーについて解説したいと思います。 各々の変数の名前の付け方が下手くそなのは目を瞑っていただけると幸いです。笑 簡単に、私の作成しているのはこのような中間テーブルです 一方的なフォロー機能のようなもので、studentがtextbookに対して「学習を始める」というボタンを押すと、students_textbookという中間テーブルにstudent_idとtextbook_idが一つのレコードに保存されるといった機能です。(イベントに参加するようなイメージの方がわかりやすいかも) そして、「学習をやめる」ボタンを押すと、その特定の中間テーブルのレコードが削除される仕組みです。 ここでエラーが起きました。 ArgumentError 発生 どうやら、destroyアクションの記述に問題があるようです。 現在のソースコード def destroy @found_recode = StudentsTextbook.where(student_id: current_student.id).where(textbook_id: @textbook.id) @found_recode.destroy redirect_to students_textbook_path(@textbook.id) end ちなみにbefore_actionで@textbookは下記のように定義されています。 現在のソースコード private def set_textbook @textbook = Textbook.find(params[:textbook_id]) end @found_recodeに代入した中身は、students_textbookテーブルの中の特定のレコードを消すために、whereメソッドで現在ログインしているstudent_idが含まれているレコードを全部取り出し、その中からさらに、whereメソッドで学習をやめるtextbookのidが含まれているレコードを取り出すと、特定の消したい一つのレコードが絞り出せると思ったのです。 結果的にこの考え方は間違っていなかったのですが、whereメソッドがどのような形で値を返していたかに問題がありました。あとdestroyの使い方です。 binding_pryで中身を確認 @found_recodeの中身をbinding.pryで調べてみます。 適当なtextbookに「学習をやめる」ボタンを押して@found_recodeを見ると [#<StudentsTextbook:0x00007fbb7f1d2e90 id: 29, student_id: 1, textbook_id: 16, created_at: Mon, 31 May 2021 17:46:02 JST +09:00, updated_at: Mon, 31 May 2021 17:46:02 JST +09:00>] このように表示されました。 たくさんあるレコードの中から特定の目的の一つのレコードが取り出せているかに見えます。しかし、これは配列で返ってきているのです。そして、その次の処理でdestroyメソッドを使用していますが、destroyメソッドは配列には使えないのです。これがエラーの原因でした。 そこでfind_byを使います。 find_byメソッドで解決する 先ほどのdestroyの記述の最後のwhereメソッドだけをfind_byメソッドに変更するだけで解決できました。 def destroy @found_recode = StudentsTextbook.where(student_id: current_student.id).find_by(textbook_id: @textbook.id) @found_recode.destroy redirect_to students_textbook_path(@textbook.id) end 最後に 今回学んだことはwhereメソッドは配列で値を返していたことと、destroyメソッドは配列には使えないってことですね。 後者は考えたら確かに、、、って感じですね。配列持ってこられても、どうやって削除するのかdestroyさんも困りますよね。すみません。 いつも思うんですが、エラーが発生して自分なりに答えを出して、それが解決につながったときの脳汁の分泌量は半端ないっすね。やめられないです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】 Decoratorパターンとは(コードは動けば良いわけではない)

1.はじめに 共同開発中にメンターさんから、「Decoratorについて調べてみて」とアドバイスを頂きました。 実装したい内容が実現できて安心してしまっていたので、「コードは動けば良いわけではないんだな...」と実感しました。 今回はDecoratorについて調べてみました。 2.環境 mac.os バージョン10.15.6 Ruby 2.7.2 Rails 6.1.3.1 psql (PostgreSQL) 12.6 3.MVCについて 冒頭でも少し触れましたが、メンターさんにDecoratorについてご紹介頂いたのは、「ビューのロジックに関することを、コントローラで定義してコードを書いていたから」だと思いました。 app/controllers/movies_controller.rb def index #動画の一覧を昇順(1,2,3...)にする @movies = Movie.order(created_at: :asc) #動画の番号を表示する(ために必要な変数を定義) ←ビューのロジックに関すること @base_number = ... end どこにコードを書くのか曖昧だと感じたので、まずMVCについて復習も兼ねて書いていきます。 3.1 モデル(M) データとデータに関わるビジネスロジック(アプリケーション特有の処理)をオブジェクトとして実装したもの。データベースの保存や読み込みを行う。 ※オブジェクト:関連する変数(値)とメソッド(動作)をまとめて、そのまとまりに名前を付けたもの。 3.2 ビュー(V) ブラウザに表示する画面、すなわちHTMLなどのHTTPレスポンスの中身を実際に組み立てる部分。必要に応じてコントローラからモデルなどのオブジェクトなどを受け取り、画面表示に利用する。 3.3 コントローラ(C) ユーザーが操作するブラウザなどのクライアントからの入力(リクエスト)を受け、適切な出力(レスポンス)を作成するための制御を行う。MとVのコントロールを行う。 4.Decoratorとは 原則として、モデルにはビジネスロジック、ビューではプレゼンテーション(見た目の)ロジックを記述するとした時に、「モデル固有のプレゼンテーションロジックはどこに書けばいいのか?」という問題が発生します。 ビューに書いた場合:モデル固有の処理なのに離れて分散してしまう。重複が発生しやすくなる。 モデルに書いた場合:コードの再利用性やメンテナンス性を損なう恐れがある。モデルが太る。 そこでDecoratorパターンを使うと、モデルごとや利用シーンごとにプレゼンテーションレイヤーの実装をまとめることができます。 アプローチの例 パターン1:モデルオブジェクトをインスタンス変数として保持し、ビュー用の処理を閉じ込めたクラスを作成して利用する 例:「アイスクリームのトッピングの処理のクラスを作り、トッピングクラスのインスタンス変数にアイスクリームのインスタンス変数を持たせる」ことでトッピングがのったアイスクリームを表現する。 パターン2:ビュー用の処理をモジュールとして定義し、ビューの文脈でモデルオブジェクトをextendして機能追加する モジュール:一連の振る舞いの設計図を一箇所にまとめたもの。 モジュールはオブジェクトを生成できず、includeメソッドを使ってクラスに取り込んで使用します。 includeはクラス(のインスタンス)に機能を追加しますが、extendはある特定のオブジェクトだけにモジュールの機能を追加したいときに使用します。 class VanillaIcecream # CashewNutsToppingIcecreamというモジュールを取り込みたい include CashewNutsToppingIcecream end パターン3:DraperやActiveDecoratorのgemを利用する gemを導入し、decoratorファイルに記述するという方法です。 # Gemfileに記述 gem 'draper' ①gemを導入し、bundle install(またはbundle)を実行します。 ②次に、 # generateはgでも可 # ターミナルで実行する rails generate draper:install rails generate decorator movie(モデル名) を順に実行します。 ③decorator.rbにコードを記入します。 movie(モデル名)_decorator.rb class movieDecorator < Draper::Decorator delegate_all # movie(モデル)のメソッドを全て呼び出せる def base_number(メソッド名) # モデルのメソッドを使用することもできる end end ④decoratorを用いたコードに書き換えます。 (1)コントローラ app/controllers/movies_controller.rb def index #動画の一覧を昇順(1,2,3...)にする @movies = Movie.order(created_at: :asc) #動画の番号を表示する(ために必要な変数を定義) ←ビューのロジックに関すること @base_number = ... end 書き換えた後(decoratorインスタンスを作成) app/controllers/movies_controller.rb def index # 複数のオブジェクトの場合はdecorate_collectionを使用する @movies = MovieDecorator.decorate_collection(Movie.order(created_at: :asc)) end (2)ビュー app/views/movies/index.html.erb <% @movies.each.with_index(1) do |movie, i| %> <p class="movie-title"> No.<%= @base_number + i %>:<%= movie.title %> </p> <% end %> 書き換えた後(decoratorメソッドを呼び出す) app/views/movies/index.html.erb <% @movies.each.with_index(1) do |movie, i| %> <p class="movie-title"> No.<%= movie.base_number + i %>:<%= movie.title %> </p> <% end %> おまけ draperやactive_decotratorを調べている際、「ヘルパーと何が違うのか?」混乱してきたので調べたところ、こちらに違いがありました。特定のモデルに関連しているビューの描写に関するものはdecoratorということですね。 5.まとめ 「モデル固有のプレゼンテーションロジックはどこに書けばいいのか?」という問題が発生した時に、「Decoratorパターンを使い、そこに記述しましょう」ということですね。 モデル→decorator→ ビュー とすることでモデルに関連したビューの表示をすることができました。 6.参考 1.大場寧子他, 現場で使えるRuby on Rails5速修実践ガイド, マイナビ出版, 2018. 2.Rubyのオブジェクトとは 3.draper 4.ActiveDecorator 5.decoratorを導入して、viewの記述をすっきりさせ、modelの肥大化を回避する【Day 3/30 2nd】 6.Rails Viewの表示のためにDecoratorを用意してHelperとModelを助ける 7.12. Decorator パターン 8.instance method Object#extend 9.Decoratorの役割とDraperについて 10.【入門】Draperを使ってみる 7.最後に 記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。 読んでいただき、ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Rails プロジェクトを作成 勉強用

デスクトップにrubyディレクトリを作成 rubyディレクトリに移動 mkdir Desktop/ruby cd Desktop/ruby rubyのバージョンを2.6.3に指定 ※ディレクトリ内でバージョンを指定 ※バージョンが違うとエラーになる rbenv local 2.6.3 プロジェクトを作成 #rails new プロジェクト名 rails new project プロジェクト先に移動 #cd プロジェクト名 cd project railsのサーバーを立ち上げる rails s railsのサーバーを停止 Controlle + c プロジェクトURL http://localhost:3000/ vsCodeでプロジェクトを開く code . Gemfileのファイルにインストールするgemを記載して保存 #ログイン機能 gem 'devise' gem 'refile',require: 'refile/rails',github: 'manfe/refile' gem 'refile-mini_magick' #スタイル gem 'bulma-rails' Gemfileの変更を適用 bundle install
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsの関連付けに関するエラーActiveRecord::HasManyThroughOrderErrorについて

1.エラー文 ActiveRecord::HasManyThroughOrderError at /posts Cannot have a has_many :through association 'Post#tags' which goes through 'Post#tag_relationships' before the through association is defined. .2やろうとしていること タグ機能をつけてpost投稿にタグを一緒に投稿できるようにしたい。 .3 原因 1.のエラー文を日本語訳してみたところ has_many :through association 'Post#tags'が、through associationが定義される前に、'Post#tag_relationships'を経由することはできません。 となっていたので post.rb has_many :tags, through: :tag_relationships has_many :tag_relationships, dependent: :destroy 中間テーブルと関連づけを定義するコードの順番が逆だということに気づきました。 4.解決 post.rb has_many :tag_relationships, dependent: :destroy has_many :tags, through: :tag_relationships とすることでこのエラーは解決しました! 最後までご覧いただき本当にありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】AWSのSESを使って本番環境でメールを送信する(aws-sdk-rails)

前提条件 macOS: Big Sur Ver11.2.3 Rails: 6.1.1 Ruby: 2.6.5 AWS: EC2(デプロイ),Route53(ドメイン取得),ACM(証明書取得) 前提条件に至るまで 固定IPアドレスに紐付いたドメインを取得し、取得したドメインにアクセスするとページが表示されるまで持っていくには、以下の記事のとおりでOK! 【初心者向け】AWSのサービスを使ってWebサーバーをHTTPS化する やりたいこと EC2上にデプロイしたRailsアプリケーションの本番環境で自由にメールを送信できるようにすること(Deviseのパスワード設定とか etc...)。 そのためにAWSのサービスのうち、SESを利用することにします。 手順(概要) ①AWS SESの設定 ②AWSのCSに制限解除のメールを送る(sandboxによる送信制限の解除) ③IAMユーザーの設定 ④Railsの設定 そして、上記の③までの設定については以下の方の記事が大変参考になりました。ありがとうございます! 【AWS】Amazon SESを用いてRuby on Railsのdeviseでメールを送信する ※なお、自分はすでにIAMユーザーを作成していたため、既存のIAMユーザーに「AmazonSESFullAccess」というインラインポリシーを後から追加する、といった方法で実装しました。まだIAMユーザーを作成していない方は上記のQiita記事の通りで良いのかと思います。 ④以降については、今回はAmazonが提供する正式なGemを使用したため、上記記事とは方法が少し異なります。 それでは、手順④以降について以下で具体的に見ていきます。 手順(詳細:Railsの設定) ①Gemのインストール Gemfileに以下を記述 # AWSのSESを使ってメールを送信するためにインストール gem 'aws-sdk-rails', '~> 3.6', '>= 3.6.1' そして、ターミナルで「bundle install」します。 ②AWSの初期設定ファイルを作成 以下のディレクトリにファイルを新規に作成します。 「aws.rb」としておきます。 config/initializers/aws.rb creds = Aws::Credentials.new( ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'] ) Aws::Rails.add_action_mailer_delivery_method(:aws_sdk, credentials: creds, region: 'ap-northeast-1') config.action_mailer.delivery_method = :aws_sdk 2〜3行目は環境変数になっているので、ターミナル上で設定されているか確認しておくこと。 (私の場合はS3に画像を保存していたため、すでに設定済みでした。) ちなみに、後でEC2上でも別途設定する必要があるので、忘れないよう注意! ③環境設定用ファイルを編集 開発環境と本番環境の設定を変更します。 config/environments/development.rb (中略) config.action_mailer.default_url_options = { host: '取得したドメインのフルURL' } config.action_mailer.delivery_method = :aws_sdk (中略) config/environments/production.rb config.action_mailer.default_url_options = { host: 'https://www.takeoutgohan.net/' } config.action_mailer.delivery_method = :aws_sdk ④Deviseの初期設定ファイルを編集(導入していなければとばしてOK) config/initializers/devise.rb (中略) # Configure the e-mail address which will be shown in Devise::Mailer, # note that it will be overwritten if you use your own mailer class # with default "from" parameter. config.mailer_sender = 'noreply@あなたのドメイン(hoge.netなど)' (中略) ⑤メールの送信元ドメインの変更 Deviseの設定に合わせ、送信元アドレスのドメインを書き換えます。 app/mailer/application_mailer.rb class ApplicationMailer < ActionMailer::Base default from: 'noreply@あなたのドメイン(hoge.netなど)' layout 'mailer' end ⑥AWSのSESコンソール上の設定を行う ⑤までを行ったところ、メールは送れているものの受信ボックスに届いていないという状態になりました。 調べたところ、メールの信頼性を確保するため追加の設定をすれば良さそう! ということでSESコンソール上で以下の設定を行いました。 DKIMの設定 AWSにルートユーザーでログインし、SESのコンソールに移動。 左メニューの「Domains」から該当のドメインを選び、DKIMの設定を行う。 MAIL FROM Domainの設定 AWSにルートユーザーでログインし、SESのコンソールに移動。 左メニューの「Domains」から該当のドメインを選び、一番下の「MAIL FROM Domain」の設定を行う。 今回は、「mail」とだけ入力して作成しました。 最後に 以上で設定は完了になります。お疲れさまでした。開発環境でメールが実際に届くか確認しましょう(私は自分のGmailアドレスに送りました)。 また、本番環境にデプロイしたあとはEC2上でAWSの環境変数が設定されているか確認し、Webサーバー(Unicorn)を再起動してからサイトに再度アクセスすると良いと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】CSVを整形してDBにデータを保存しよう

業務でCSVの整形処理を扱いました。 今後も割と扱うこと多いらしいので扱い方をざっくりまとめておきます。 実装手順に沿ってまとめたので以下に従って実装すればCSVを整形してDBにデータを保存できるようになるはずです。 前提 ruby 2.3.1 Rails4.2.3 hamlからCSVを送信する ①CSVをビューから受け取る Railsのビューファイルからフォームを送るとActionDispatch::UploadedFileオブジェクトとして送信されます。 CSVを整形するためにはこれをFileオブジェクトに変換する必要があります。 file = params[:file].tempfile ActionDispatch::UploadedFileオブジェクトには tempfile というキーでFileオブジェクトが格納されており params[:file].tempfile とすることでFileオブジェクトに変換できます。 ②CSV.forEachでCSVを1行ずつに分解 rubyのCSVクラスの持つ便利なメソッドに CSV.foreEach というのがあります。 これを使うとCSVのデータを1行ずつに分解できます。 file = params[:file].tempfile # ここから追記 CSV.forEach(file, header_row: true) do |row| row end こんな感じで CSV.forEach の中で各行に対して処理を行います。このとき、第一引数はFilleオブジェクトである必要があります。 ①でFileオブジェクトに変換したのはこのためです。 ここでポイントになるのが header_row: true というオプションで、これを使うとheader(列名)の値とrow(列に対応する値) の部分をキーバリューの組として取り出せます。例えば 日付 気温 2021/06/11 30℃ こんな感じのCSVがあれば以下のようなオブジェクトがブロック変数rowに代入されます。 <CSV::ROW '日付':'2021/06/11', '気温':'30℃' > このオブジェクトの便利なところとして、キーを指定して値を取り出せます。 row = <CSV::ROW '日付':'2021/06/11', '気温':'30℃' > row['日付'] => '2021/06/11' row['日付'] = '2021/06/10' row['日付'] => '2021/06/10' 次のステップでこれを利用します。 ③各行のデータをハッシュに変換 各行のデータを取り出す各行のデータをハッシュに変換する。このとき上記で確認したCSV::ROWオブジェクトが活躍します。 キーを指定して値を取り出せるので全体的なイメージとして以下のようなメソッドを組みます。 def convert_csv_to_hash(row) params = { date: row['日付'] temperature: row['気音'] } return params end # ここまで追記 file = params[:file].tempfile CSV.forEach(file, header_row: true) do |row| params = convert_csv_to_hash(row) end こうすることでCSV.forEachの各行をrailsで扱えるハッシュに変換できます。 ④変換したハッシュを元にDBにデータを保存 ハッシュに変換できたらDBにデータを保存します。 def convert_csv_to_hash(row) params = { date: row['日付'] temperature: row['気音'] } return params end file = params[:file].tempfile CSV.forEach(file, header_row: true) do |row| params = convert_csv_to_hash(row) # 追加。Hogeは保存したいモデル名 Hoge.create(params) end ⑤この処理を何かしらのクラスで行う ここまでで処理自体は記述できたのでこれをコントローラーなりに記述しましょう。 僕が今回実装したものだとCSVを扱う専用のService層を作ってそこに記述しました。 ⑥プラスアルファ…例外処理について CSVからデータを保存する際は複数データを纏めて保存する仕様のため、保存に失敗した際に具体的に どのデータの保存に失敗したのかを検知する仕組みがあったほうがいいと思います。 例えば今回僕は以下のような例外処理を組みました。 class ImportCSV def convert_csv_to_hash(row) params = { date: row['日付'] temperature: row['気音'] } return params end file = params[:file].tempfile CSV.forEach(file, header_row: true).with_index(1) do |row, line_num| params = convert_csv_to_hash(row) begin Hoge.create(params) rescue e return "#{line_num}行目が不正です。エラー内容:#{e.message}" end end end あとはこれをコントローラーで受け取ってビューに表示すればOK。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】CSVの中身を整形してDBにデータを保存しよう

業務でCSVの整形処理を扱いました。 今後も割と扱うこと多いらしいので扱い方をざっくりまとめておきます。 実装手順に沿ってまとめたので以下に従って実装すればCSVを整形してDBにデータを保存できるようになるはずです。 前提 ruby 2.3.1 Rails4.2.3 hamlからCSVを送信する ①CSVをビューから受け取る Railsのビューファイルからフォームを送るとActionDispatch::UploadedFileオブジェクトとして送信されます。 CSVを整形するためにはこれをFileオブジェクトに変換する必要があります。 file = params[:file].tempfile ActionDispatch::UploadedFileオブジェクトには tempfile というキーでFileオブジェクトが格納されており params[:file].tempfile とすることでFileオブジェクトに変換できます。 ②CSV.forEachでCSVを1行ずつに分解 rubyのCSVクラスの持つ便利なメソッドに CSV.foreEach というのがあります。 これを使うとCSVのデータを1行ずつに分解できます。 file = params[:file].tempfile # ここから追記 CSV.forEach(file, header_row: true) do |row| row end こんな感じで CSV.forEach の中で各行に対して処理を行います。このとき、第一引数はFilleオブジェクトである必要があります。 ①でFileオブジェクトに変換したのはこのためです。 ここでポイントになるのが header_row: true というオプションで、これを使うとheader(列名)の値とrow(列に対応する値) の部分をキーバリューの組として取り出せます。例えば 日付 気温 2021/06/11 30℃ こんな感じのCSVがあれば以下のようなオブジェクトがブロック変数rowに代入されます。 <CSV::ROW '日付':'2021/06/11', '気温':'30℃' > このオブジェクトの便利なところとして、キーを指定して値を取り出せます。 row = <CSV::ROW '日付':'2021/06/11', '気温':'30℃' > row['日付'] => '2021/06/11' row['日付'] = '2021/06/10' row['日付'] => '2021/06/10' 次のステップでこれを利用します。 ③各行のデータをハッシュに変換 各行のデータを取り出す各行のデータをハッシュに変換する。このとき上記で確認したCSV::ROWオブジェクトが活躍します。 キーを指定して値を取り出せるので全体的なイメージとして以下のようなメソッドを組みます。 def convert_csv_to_hash(row) params = { date: row['日付'] temperature: row['気音'] } return params end # ここまで追記 file = params[:file].tempfile CSV.forEach(file, header_row: true) do |row| params = convert_csv_to_hash(row) end こうすることでCSV.forEachの各行をrailsで扱えるハッシュに変換できます。 ④変換したハッシュを元にDBにデータを保存 ハッシュに変換できたらDBにデータを保存します。 def convert_csv_to_hash(row) params = { date: row['日付'] temperature: row['気音'] } return params end file = params[:file].tempfile CSV.forEach(file, header_row: true) do |row| params = convert_csv_to_hash(row) # 追加。Hogeは保存したいモデル名 Hoge.create(params) end ⑤この処理を何かしらのクラスで行う ここまでで処理自体は記述できたのでこれをコントローラーなりに記述しましょう。 僕が今回実装したものだとCSVを扱う専用のService層を作ってそこに記述しました。 ⑥プラスアルファ…例外処理について CSVからデータを保存する際は複数データを纏めて保存する仕様のため、保存に失敗した際に具体的に どのデータの保存に失敗したのかを検知する仕組みがあったほうがいいと思います。 例えば今回僕は以下のような例外処理を組みました。 class ImportCSV def convert_csv_to_hash(row) params = { date: row['日付'] temperature: row['気音'] } return params end file = params[:file].tempfile CSV.forEach(file, header_row: true).with_index(1) do |row, line_num| params = convert_csv_to_hash(row) # ここから追記 begin Hoge.create(params) rescue e return "#{line_num}行目が不正です。エラー内容:#{e.message}" end end end あとはエラーメッセージをコントローラーで受け取ってビューに表示する、Slackやメールで通知するなどすればOK。 感想 CSVの組み込みメソッドだけでほとんど処理できたので思ったよりかんたんでした。 まだまだ使えるメソッドはたくさんあると思うので今後もっと深堀りしていきたいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【rails】複数カラムでの複数フリーワード検索を実装する

はじめに railsで複数カラムに対して、検索されたワードが部分一致したレコードのみを取得する検索機能を実装する。 また、複数ワードで検索された場合は、そのワードが全てどこかのカラムに入っているレコードのみを取得する。 構成 機能の構成としては、 複数ワードで検索する際はスペースでワードを区切ってフォームに入力してもらう。(疑似カラムsearch_wordを作る) スペースで検索ワードを分解して配列にいれる。 injectメソッドを使って繰り返しの処理をする。 (複数のワードがマッチしたレコードだけ取得する) 実装 実際には複数モデルでの検索も入れているので、form objectを使っております。 forms/search_bugs_form.html.erb class SearchBugsForm include ActiveModel::Model include ActiveModel::Attributes attr_accessor :search_word def search relation = Bug.distinct if search_word.present? search_words = search_word.split(/[[:blank:]]+/) search_words.inject(relation) do |result, word| relation = result.where('name LIKE ?', "%#{word}%").or(result.where('feature LIKE ?', "%#{word}%")).or(result.where('approach LIKE ?', "%#{word}%")).or(result.where('prevention LIKE ?', "%#{word}%")).or(result.where('harm LIKE ?', "%#{word}%")) end end end end 解説 まず、search_wordという擬似カラムを作ってそれをattri_accessorでアクセスできるようにします。 attr_accessor :search_word searchメソッドでは最初に、レコードの集合を取得してrelationに代入します。 relation = Bug.distinct 取得したsearch_wordをsplit(/[[:blank:]]+/)を使ってスペースで分解し、ワードを配列search_wordsに代入します。 search_words = search_word.split(/[[:blank:]]+/) /[[:blank:]]+/にすると、スペースが全角でも半角でも対応できるようになります。 続いて、injectメソッドを使います。 search_words.inject(relation) do |result, word| relation = result.where('name LIKE ?', "%#{word}%").or(result.where('feature LIKE ?', "%#{word}%")).or(result.where('approach LIKE ?', "%#{word}%")).or(result.where('prevention LIKE ?', "%#{word}%")).or(result.where('harm LIKE ?', "%#{word}%")) end 初期値をレコードの集合であるrelationに設定し、これがresultに代入されます。 wordには先程のsearch_wordsの検索ワードが順番に入ります。 検索ワードごとにor検索をして、最低1つのカラムの値に、その検索ワードが含まれているレコードをrelationに代入します。 そのrelationの結果がresultに代入され、次のワードがwordに代入されて、再びor検索が実行されます。 これを検索されたワードの数だけ繰り返します。 これで検索されたワードが2つ以上の場合は、その2つ以上のワードが全て、指定したカラムのどこかに入っているレコードのみを取得してきます。 参考 キーワードを全角込みの空白で区切る Ruby on Railsでinjectを使う方法を現役エンジニアが解説【初心者向け】 もっといい方法があればご教示ください?‍♂️
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerを用いてRails6の環境構築をする方法

今回は開発環境において、Dockerを用いてRails6の環境構築をする方法をご紹介いたします。 それぞれのファイルや単語の意味などの解説はしていないので、詳しい解説は Dockerを用いてRuby on Railsの環境構築をする方法( Docker初学者向け ) をご覧ください。 ( ※ Rails5の環境構築方法になります) 環境 MacOS Docker 20.10.6 docker-compose 1.29.1 Ruby 3.0.1 Rails 6.1.0 MySQL 5.7 前提 DockerおよびDocker composeのインストールを済ませてください これ以降の説明のmyappの部分はご自身のアプリケーション名に変えてください アプリケーションの作業ディレクトリを作成 mkdirで作業ディレクトリを作成します。 $ mkdir myapp 必要なファイルを用意 ファイル構成は以下のようになります。 myapp |-- Dockerfile |-- docker-compose.yml |-- Gemfile |-- Gemfile.lock それでは、先ほど作成したディレクトリの中に以下の各ファイルを作成していきます。 ① Gemfile Gemfile source 'https://rubygems.org' gem 'rails', '>= 6.1.0' ② Gemfile.lock Gemfile.lock Gemfile.lockの中身は空でOKです。 ③ Dockerfile Dockerfile FROM ruby:3.0.1 RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list # yarnをインストールするための準備 RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ nodejs \ default-mysql-client \ yarn \ # yarnをインストール vim RUN mkdir /myapp WORKDIR /myapp COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install COPY . /myapp Rails6でwebpackerが搭載され、yarnのインストールが必要になりました。 ④ docker-compose.yml docker-compose.yml version: '3' services: db: image: mysql:5.7 environment: MYSQL_USER: user MYSQL_ROOT_PASSWORD: pass ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp ports: - 3000:3000 depends_on: - db volumes: mysql_data: rails new を実行 $ docker-compose run web rails new . --force --database=mysql アプリケーションの作業ディレクリに移動し、上記のdocker-compose runコマンドでrails newを実行します。 ( Rails5の時は--skip-bundleのオプションをつけて、bundle installをスキップしていましたが、今回はwebpackerのインストールをしなければならないためbundle installはスキップしません。 ) docker-compose build を実行 $ docker-compose build rails new で Gemfileが更新されたので、bundle installするため、docker-compose buildを実行します。 database.yml を編集 /config/database.yml # MySQL. Versions 5.1.10 and up are supported. # # Install the MySQL driver # gem install mysql2 # # Ensure the MySQL gem is defined in your Gemfile # gem 'mysql2' # # And be sure to use new-style password hashing: # https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html # default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root # 以下2行を編集 password: pass host: db development: <<: *default database: myapp_development # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default database: myapp_test # As with config/secrets.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot # the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # # On Heroku and other platform providers, you may have a full connection URL # available as an environment variable. For example: # # DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase" # # You can use this database configuration with: # # production: # url: <%= ENV['DATABASE_URL'] %> # production: <<: *default database: myapp_production username: myapp password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %> password: と host:を編集します。 password: には docker-compose.yml の MYSQL_ROOT_PASSWORD:に書いたパスワードを記載します。 host: には dbと記載します。 docker-compose up -d でコンテナを起動 $ docker-compose up -d データベースを作成 以下のコマンドでデータベースを作成します。 $ docker-compose exec web rails db:create localhost:3000にアクセス localhost:3000にアクセスし、以下のページが表示されれば DockerによるRails6の環境構築 は完了です。 その後の開発の仕方は こちら を参考にしてください。 参考 Dockerを使ってRails6環境の構築をしてみる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

YouTubeチャンネルの動画を一覧表示したい

桃鈴ねねさんが大好きで勝手にファンサイトを作ってます。 要するにアーカイブを全部表示したいと思っています。 ただまぁ流石に現時点で280本近くあるアーカイブを全部表示するのも問題なので、ページネーションを使いましょう。 gem "kaminari" で、いつも通り、bundle install(migration済みの場合はローカルサーバーの再起動) 次はルーティング config/routes.rb Rails.application.routes.draw do # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html root to: "home#index" resources :archive end 特に意味はないですが、全部ルーティングしておきました。 後々、追加機能を作りたくなった時に便利だと思うので。 次はcontroller app/controllers/archive_controller.rb class ArchiveController < ApplicationController def index @archive = Archive.all.page(params[:page]).per(15) end end 今回はkaminariを導入しているので、Archive.allの後にオプションをつけます。 perの引数に1ページあたりに表示する件数を設定できます。 ちなみに特に設定しなくても大丈夫ですが、デフォルトは25件になってます。 app/views/archive/index.html.erb #詳しい構成は省略 <h2 class="major">Archives</h2>   <h3>オススメ動画</h3>     <div class="archive">       <%= render partial: "archive" , collection: @archive %>     </div> <%= paginate @archive %> renderメソッドを使用して、さらにオプションをcollectionにします。 これで先程のcontrollerで設定した@archiveに入っている要素の数だけ、繰り返してくれるので、便利です。 最後のpaginateは実際にページネイトを表示したい場所に入れてください。 app/views/archive/_archive.html.erb <div class = "archive_card"> <%= image_tag (archive.archiveimg) , class: :music_img %> <p><%= archive.archivetitle %></p> </div> 先程の繰り返しになりますが、collectionのおかげで、この辺の記述はシンプルに。 わざわざeachで繰り返し処理を記述する必要もないです。 app/assets/stylesheets/main.css.erb .archive{ column-count: 2; display: inline-block; flex-wrap: wrap; justify-content: space-between; align-items: center; } .archive_card{ width:100%; height:100%; padding : 0; margin: 0 ; position: relative; } .archive_card p{ font-size : 0.5rem; position: absolute; color: black; top: 80%; left: 50%; -ms-transform: translate(-50%,-50%); -webkit-transform: translate(-50%,-50%); transform: translate(-50%,-50%); background-color: rgba(255, 255, 255, 0.6); width:100%; font-weight:bold; text-align:center; } 最後にCSSですね。 まずdisplay: inline-block;とかで横並びにしちゃってjustify-contentでspacebetweenにしてます。 あとサムネイル画像の上にタイトルを表示したいと思いました。 理由は単純で、アーカイブが多いから。 なんせ280件もあるので、いちいちサムネイルとタイトルをそれぞれ表示してたら情報量が多いし、そもそもタイトルの長さもまちまちでカラム表示しててもズレが生じてしまうので、サムネイル上にタイトルを表示すると言うことで落ち着きました。 重要なポイントだけ記述しておくと、サムネイル画像の親要素であるarchive_cardにposition:relativeを指定してその子要素のp要素にposition:abusolute;を指定しました。 これでサムネイルの画像にp要素を載せることができます。 あとはp要素にbackgroundカラーを指定して、透過もしておきます。 サムネイルは比較的上部に桃鈴ねねさんの顔がくることが多いので、下の方にタイトルを表示して可愛い顔と被らないようにします。 これがもしブログみたいな感じだったらセンターでも良いのでしょうが。 さて、長くなりましたが、完成形です。 PC表示 スマホ表示 必要な情報はありつつも、シンプルな構成にできたと思います。 これと似たようなことを他のモデルでも行うので、ひとまずベースがこんな感じ、と言うことで。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pagyのページネーションの件数をページごとに設定する

はじめに RailsのページネーションのGem、pagy。 ページネーションだとkaminariが有名ですが、pagyはメモリの負担が少なくkaminariよりも高速で動きます。 ページネーションの表示件数を設定すると思うのですが、紹介している記事の多くはページごとにではなく、アプリケーション全体の設定として記述するやり方が多かったのでコントローラーのアクションごとに設定できる(つまり、ページごとに設定できる)やり方をご紹介します。 pagyの基本の設定方法 まずや基本的なPagyの設定方法。 config/initializers配下にpagy.rbを配置し、以下の記述を追加します。(追加したらサーバーの再起動必要) pagy.rb Pagy::VARS[:items] = 30 この場合は、30件ずつの表示になります。ちなみにpagyのデフォルトは20件ずつです。 pagyの設定をそれぞれにする ページネーションさせるのがひとつのページならいいのですが、ここは10件ずつでとやりたい場合ができず、 上記の例だと30件ずつになってしまいます。 なので、一覧ページは10件、管理画面はは30件ずつなどと細かく設定したい場合はcontroller.rbにアクションごとに記述します。 controller.rb def index @pagy, @users = pagy(User.all, items: 10) end def admin @pagy,@users = pagy(User.all, items: 30) end このようにitems :表示する数と記述すると、ページごとにページネーションさせる数を変えることができます。 ちなみにransackを使った時はこんな感じになるかと思います。 ransackの例 def index @q = User.ransack(params[:q]) @pagy,@users = pagy(@q.result, items: 30) end それでは〜。 参考サイト Qiita Rails 新興のgem pagyをつかってページネーション機能を実装する TechRacho Rails:「Pagy」gemでRailsアプリを高速ページネーション(翻訳)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む