- 投稿日:2021-02-20T23:49:30+09:00
【Rails】時刻のJST(日本標準時)への変更
Railsアプリは、デフォルトでUTC(協定世界時)タイムゾーンを使用します。日時を扱う際、自動的にActiveSupport::TimeWithZoneクラスを用います。
タイムゾーンの変更
アプリケーションの起動時に任意のタイムゾーンの値にするには、Time.zoneの値の制御が必要です。
製作中のアプリは日本での使用を想定しているため、日本時間に変更します。config/application.rbにconfig.time_zoneから始まる1行を追加します。config/application.rbmodule TweetApp class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.2 config.time_zone = 'Asia/Tokyo' ... end endこれで、日時がJST(日本標準時)で表示されるようになりました!
ですが、このままだと読みづらいので表示を変更します。時刻のフォーマットファイルを作成し…
config/initializers/time_formats.rbTime::DATE_FORMATS[:datetime_jp] = '%Y/%m/%d %H:%M'あとは以下のコードを投稿時間と更新時間の箇所へと書き換えればOK!
.created_at.to_s(:datetime_jp) .updated_at.to_s(:datetime_jp)参考
現場で使える Ruby on Rails 5速習実践ガイド
【Rails】created_at、updated_atを日本時間に変更して良い感じに表示する方法
- 投稿日:2021-02-20T23:21:24+09:00
Railsで開発中にデータベースのレコードを削除したい時は?
目的
開発中に作成したデータベース内のレコードをすべて削除したい。
例)ユーザーテーブルの「test_user」など適当に作ったユーザーデータ方法
ターミナルで「rails db:reset」コマンドを実行。
これでデータベースの中身が空っぽになる。terashimatakaya@MacBook-Air furima-34501 % rails db:reset Dropped database 'furima_34501_development' Dropped database 'furima_34501_test' Created database 'furima_34501_development' Created database 'furima_34501_test'Railsガイドv6.1 「4.3データベースをリセットする」によるとこのコマンドで行ったことは、「rails db:drop db:setup」と同等とのこと。
注意点としては「rails db:migrate」の意味は含まれていない点。解説
「rails db:drop」コマンド
データベースを削除するコマンド。usersテーブルやらが全て削除される。
「rails db:create」する前の状態に戻ると思えばOK。「rails db:setup」コマンド
データベースの作成、スキーマの読み込み、シードデータを用いてデータベースの初期化を実行。
実際にRailsがやってる処理の流れは、
①既存のdb/schema.rbを読み込む
②①の情報を頼りにデータベースを再作成
③再作成のタイミングでdb/seeds.rbに開発用のサンプルデータがあればそれもこのタイミングで再度流し込む補足
なぜ「db/schema.rb」を参照するのか?
簡単に説明すると、古いマイグレーションファイルたちもイチから順に実行するとエラーが起きやすくなるから。
それよりも常に最新の状態に保たれているだろうschema.rbの情報をもとにしたほうがエラーが起こらず再度データベースを作成できるから、といったかんじだろうか。
詳細は以下のリンクで確認してください。
- 投稿日:2021-02-20T21:59:10+09:00
【Rails】カテゴリー機能
はじめに
レシピ投稿サイトを作成し、レシピに紐づくカテゴリー機能を実装します。
gemのancestryは使っていません。
RecipeモデルとUserモデルが紐づいており、1ユーザーが複数投稿できる仕様です。その辺りは割愛させて頂きます。
投稿(Recipe)とカテゴリー(Category)のモデル、コントローラーは実装済みで進めさせて頂き、今回は投稿とカテゴリーの紐付けについての内容に重点を置いてQiita投稿させて頂きます。完成イメージ
中間テーブルの作成
recipe_category_relationsテーブルを中間テーブルとします。
$ rails g model Recipe_category_relation recipe_id:integer category_id:integerdb/schema.rbcreate_table "categories", force: :cascade do |t| t.string "category_name" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "recipe_category_relations", force: :cascade do |t| t.integer "recipe_id" t.integer "category_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "recipes", force: :cascade do |t| t.string "recipe_title" t.text "recipe_body" t.string "image_id" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "recipe_food" end投稿のモデル、中間テーブル、カテゴリーテーブルの関連付け
app/models/recipe.rbclass Recipe < ApplicationRecord has_many :recipe_category_relations has_many :categories, through: :recipe_category_relations endapp/models/recipe_category_relation.rbclass Recipe_category_relation < ApplicationRecord belongs_to :recipe belongs_to :category endapp/models/category.rbclass Category < ApplicationRecord has_many :recipe_category_relations has_many :recipes, through: :recipe_category_relations endthrough: :recipe_category_relationsの記述で、中間テーブルrecipe_category_relationを経由してrecipeとcategoryが関連付けることができます。
viewに表示
app/views/recipes/new.html.erb<h1>レシピ投稿</h1><br> <%= form_with model:@recipe, url: recipes_path , local:true do |f| %> <%= f.attachment_field :image %> <%= f.label :title, '料理名'%> <%= f.text_field :recipe_title, class:"form-control", placeholder:"料理名" %> <%= f.label :category, 'カテゴリ' %> <%= f.collection_check_boxes(:category_ids, Category.all, :id, :category_name) do |category| %> <%= category.label do %> <%= category.check_box %> <%= category.text %> <% end %> <% end %> <%= f.label :body, '材料'%> <%= f.text_area :recipe_food, class:"form-control", placeholder:"材料をここに" %> <%= f.label :body, '作業工程'%> <%= f.text_area :recipe_body, class:"form-control", placeholder:"作業工程をここに" %><br> <%= f.submit "レシピ投稿", class: "btn btn-warning" %> <% end %>collection_check_boxesというViewヘルパー関数を使って複数選択できるチェックボックスを実装しています。
app/controllers/recipe_controller.rbclass RecipesController < ApplicationController def new @recipe = Recipe.new end def create @recipe = Recipe.new(recipe_params) @recipe.user_id = current_user.id @recipe.save! redirect_to recipe_path(@recipe) end private def recipe_params params.require(:recipe).permit(:recipe_title, :recipe_body, :image, :recipe_food, category_ids: []) end endcategory_ids はチェックボックスの各チェックに関連付けられるIDが入ります。
app/views/recipes/index.html.erb<% @recipes.each do |recipe| %> ・ ・ ・ <% recipe.categories.each do |category| %> <%= category.category_name %> <% end %> <% end %>上記の記述で、冒頭で表示した2枚目の画像のようにcategory_nameが表示されます。
最後に
今回多対多のアソシエーション、collection_check_boxesメソッドについての実装をしました!
collection_check_boxesメソッドに関してはまだ理解が浅いので、もう少し深く勉強します
長くなりましたが、ここまで見て頂きありがとうございました!!参考
https://qiita.com/sho012b/items/3a595fde14516081dff5
https://qiita.com/cawaz3/items/e755a58177212f2aca6c
- 投稿日:2021-02-20T21:08:58+09:00
Rubyインストールに伴うMSYS2インストール時のエラーについて
環境
- Windows 10
- Ruby 3.0.0
どこで引っかかったか
Rubyをインストールする
RubyInstallerを使ってインストールした
ここは特に問題なし。MSYS2をインストールする
ここで以下のようなエラーで出てうまくインストールできていないような感じ
エラー: mingw32: "David Macek <david.macek.0@gmail.com>" の署名は信頼されていません エラー: mingw64: "David Macek <david.macek.0@gmail.com>" の署名は信頼されていません詳細
C:\Windows\System32>ridk install _____ _ _____ _ _ _ ___ | __ \ | | |_ _| | | | | | |__ \ | |__) | _| |__ _ _ | | _ __ ___| |_ __ _| | | ___ _ __ ) | | _ / | | | '_ \| | | | | | | '_ \/ __| __/ _` | | |/ _ \ '__/ / | | \ \ |_| | |_) | |_| |_| |_| | | \__ \ || (_| | | | __/ | / /_ |_| \_\__,_|_.__/ \__, |_____|_| |_|___/\__\__,_|_|_|\___|_||____| __/ | _ |___/ _|_ _ __ | | o __ _| _ _ | (_) | |^| | | |(_|(_)\^/_> 1 - MSYS2 base installation 2 - MSYS2 system update (optional) 3 - MSYS2 and MINGW development toolchain Which components shall be installed? If unsure press ENTER [1,3] 3 > sh -lc true MSYS2 seems to be properly installed Install MSYS2 and MINGW development toolchain ... > pacman -S --needed --noconfirm auto略ds-git エラー: mingw32: "David Macek <david.macek.0@gmail.com>" の署名は信頼されていません エラー: mingw64: "David Macek <david.macek.0@gmail.com>" の署名は信頼されていません エラー: msys: "David Macek <david.macek.0@gmail.com>" の署名は信頼されていません エラー: データベース 'mingw32' は無効です (無効または破損したデータベース (PGP 鍵)) エラー: データベース 'mingw64' は無効です (無効または破損したデータベース (PGP 鍵)) エラー: データベース 'msys' は無効です (無効または破損したデータベース (PGP 鍵)) Install MSYS2 and MINGW development toolchain failed Installation failed: pacman failed 1 - MSYS2 base installation 2 - MSYS2 system update (optional) 3 - MSYS2 and MINGW development toolchain Which components shall be installed? If unsure press ENTER []どうやって解決したか
- MSYS2を更新
- 再度ridk installを実施
という感じで進めました。
Rubyをインストールしたフォルダ内にあるMSYS2.exeを実行する
C:\Ruby30-x64\msys64\msys2.exe表示されたコマンドラインでMSYS2を更新
以下issueを参考に、↓のコマンドを実行
https://github.com/msys2/MINGW-packages/issues/240pacman-key --init pacman-key --populate msys2 pacman-key --refresh-keysこの後↓を複数回実施する
pacman -Syuu再度ridk installを実施したら、通りました。
やったぜ
- 投稿日:2021-02-20T19:00:29+09:00
devise x omniauth-twitter x bootstrap-social にてTwitterサインインボタンを出力する
めっちゃ苦戦した。ポイントは link_to の文字列をなくして
do-end
で囲み、中にspanを置くことと、'twitter`が文字列でなくシンボルなこと。## app/views/devise/shared/_links.html.erb <%- if devise_mapping.omniauthable? %> <%- resource_class.omniauth_providers.each do |provider| %> <% puts provider.class %> <% if provider == 'twitter'.to_sym %> <%= link_to omniauth_authorize_path(resource_name, provider), class: "btn btn-block btn-social btn-twitter" do %> <span class="fab fa-twitter"></span>Sign in with Twitter <% end %> <% else %> <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br /> <% end %> <% end %> <% end %>bootstrap-socialはGithubの
bootstrap-social.css
をapp/assets/stylesheets
配下に配置しようとしたが、bootstrap自体の読み込みをapp/javascript/src/application.scss
でやっていたので、scssファイルとして同階層に配置し@import 'bootstrap-social.scss
としたものの、読み込み順が違ったりBootstrapのバージョンなのか、Fontawesome5を使っているからなのかレイアウトが崩れたりする。結局、必要なCSSを Developer Tool を開きながら抜き出す形に‥。つまり言いたいのはTwitterボタンのデザイン適用方法はここのBootstrapのインストール方法によるので何とも言えないってこと。色々と非効率だし美しくない‥。
- 投稿日:2021-02-20T18:22:43+09:00
cannot load such file -- nokogiri/nokogiri (LoadError) を解決する方法
この記事では、
cannot load such file -- nokogiri/nokogiri (LoadError) を解決する方法
について書いていきます。あくまで、僕自身が実際に行った方法ですので、全員がうまくいくとは限りません。
ですが、少しでも参考にしていただけたら幸いです。
解決法
実際のエラー
$ rails s require': cannot load such file -- nokogiri/nokogiri (LoadError)何行もあるエラーの最後にこのような文が記載されていました。
gem install nokogiri
などを行っても変わりませんでした。$ which ruby /usr/bin/ruby
which ruby
でrubyの場所を調べたところ、
/usr/bin/ruby
に存在している事がわかりました。$ [[ -d ~/.rbenv ]] && \ export PATH=${HOME}/.rbenv/bin:${PATH} && \ eval "$(rbenv init -)" $ which ruby /Users/XXXX/.rbenv/shims/rubyこのようにrubyの場所を変更します。
$ bundle install --path vendor/bundle最後に
bundle install
を行うことでエラーが解消されると思います。まとめ
$ [[ -d ~/.rbenv ]] && \ export PATH=${HOME}/.rbenv/bin:${PATH} && \ eval "$(rbenv init -)“ $ bundle install --path vendor/bundleこの2つで僕自身の環境では治せました。
それぞれ環境は違うと思うので、参考程度によろしくお願いいたします。質問や訂正等ございましたら、コメントの方でお願いできればと思います。
最後まで読んでいただきありがとうございました。参考
cannot load such file -- nokogiri/nokogiri (LoadError) のエラーを解決するまで。 - Qiita
注意
この記事は、プログラミング初学者が書いており、内容に誤りがある場合がございます。
あしからずご了承願います。
また、誤りにお気付きの場合にはご指摘いただけると幸いです。
よろしくお願いいたします。
- 投稿日:2021-02-20T17:47:42+09:00
Railsでdeviseを使うときに設定すること【超初心者】
自分用。練習用に作るときに設定することの備忘録。
目次
1.導入
2.ユーザーテーブルの作成
3.マイグレーションファイルの編集
4.コントローラへの記述追加
5.devise.rbの記述追加
6.ルートに記述追加
7.ログイン画面を編集する
8.ログアウト機能を作る
9.サインイン画面を編集する1.導入
deviseをインストールするためGemfileにdeviseを記載
Gemfilegem 'devise'ターミナルにてインストール
tarminal$ bundle install $ rails g devise:install2.ユーザーテーブルの作成
tarminal$ rails g devise UserUserがモデル名
3.マイグレーションファイルの編集
追加することがあれば追加する。id,password,emailは標準装備。今回はname,age,gender,introduction,profile_image_idを追加する
db/migrate/202102~~01_devise_create_users.rb(略) # t.datetime :locked_at t.string :name t.integer :age t.integer :gender t.text :introduction t.string :profile_image_id #ここまで追加 t.timestamps null: false end (略)そしたらターミナルで
rails db:migrate
を行う4.コントローラへの記述追加
before_action :authenticate_user!はonlyだと記述したものだけ通す。exceptは記述したものだけ通さない。
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base before_action :authenticate_user!, only: [:top, :index, :show] before_action :configure_permitted_parameters, if: :devise_controller? def after_sign_in_path_for(resource) ログイン後に遷移させたい所_path end def after_sign_out_path_for(resource) ログアウト後に遷移させたい所_path end protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) endend5.devise.rbの記述追加
ログイン時に必要な項目を変えたい場合に変更。変更しなくても使える。
config/initializers/devise.rb49行目ぐらい # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. # config.authentication_keys = [:email] これをコメントアウトを外してemailを変える connfig.authentication_keys = [:name]6.ルートに記述追加
順番に注意!順番を間違えるとエラーになったり無限に繰り返したりする。
config/routes.rbdevise_for :users root to: 'homes#top'7.ログイン画面を編集する
tarminal$ rails g devise:views出来たら勝手にできたログイン(サインイン)画面を編集
app/views/devise/registrations/new.html.erb<%= form_with model: @user, url: user_session_path, local: true do |f| %> #変更 <div class="field"> #追加 <%= f.label :name %> <%= f.text_field :name, autofocus: true %> </div> (略)8.ログアウト機能を作る
置きたいところ.erb<body> <% if user_signed_in? %> <li> <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> </li> #追加したいものを書く <% else %> <li> <%= link_to "新規登録", new_user_registration_path %> </li> <li> <%= link_to "ログイン", new_user_session_path %> </li> #追加したいものを書く <% end %> <%= yield %> </body>9.サインイン画面を編集する
合ってるか不安
app/views/devise/registrations/new.html.erb<h2>Sign up</h2> <%= form_with model: @user, url: user_registration_path, id: 'new_user', class: 'new_user', local: true do |f| %> #編集 <%= render "devise/shared/error_messages", resource: resource %> <div class="field"> <%= f.label :name %> <%= f.text_field :name, autofocus: true %> </div> <div class="field"> <%= f.label :email %> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <div class="field"> <%= f.label :age %> <%= f.number_field :age, autofocus: true, min: 1, max: 100 %> </div> <div class="field"> <%= f.label :gender %> <%= f.select :gender, [ ["男性",1], ["女性", 2], ["未選択", 3 ] , prompt: "性別を選択" %> (略)とりあえずこれで一通り。
記録をし忘れているところがあったら編集していく所存。
間違えていないか不安なので見直す。
- 投稿日:2021-02-20T17:27:44+09:00
【Rails】アソシエーションで紐づいたレコードを自動保存
概要
中級者は知ってて当然なので、初心者向けです?
アソシエーションで関連付けられたモデルを保存する時に、片方のレコードに外部キーが設定されているせいで、「保存処理を2回に分けなきゃ」と思ったことはないですか?(保存するまでidが確定しないので)
そんなときどうするのというお話です
※ 自分もかつて良くないコードを書いていたので、同じような初心者の参考になってもらえれば幸いです
具体例
例えば本のモデル(Book)と著者のモデル(Author)があると想定します
(book has_many authors
の関係)Bookモデル?
カラム 型 補足 id integer title string Authorモデル
カラム 型 補足 id integer book_id integer 外部キー name string このとき初心者がやりがちなのが以下の書き方
books_controller# createアクション book = Book.new(book_params) if book.save author = Author.new(book_id: book.id, name: author_params[:name]) if author.save # 保存後の処理 else # 失敗時の処理 end else # 失敗時の処理 end # book_params, author_paramsの定義は省略してますこれだと以下のようにデメリットが大きいです
- if文の階層が深くなる
- bookだけ保存されてauthorが保存されない場合が出てしまう
早期リターンやtransactionでこれらを回避することもできますが、わざわざそんな面倒なことをしなくて済む方法があるのです✨(以下)
books_controller# createアクション book = Book.new(book_params) author = book.build_author(author_params) return ['保存成功時の処理'] if book.save # 失敗時の処理この場合
book
の保存が成功した場合はauthor
の保存も保証してくれます(片方だけ保存されることはない)当然外部キーは関連付けられて保存されます
すっきりしていて見やすく、ファットコントローラ対策にもなります?
※ 早期リターンでリファクタもしてますモデルの関係性が、
belongs_to
とhas_many
とで書き方が変わるので注意が必要です(以下参照)
belongs_to
で関連付けられたモデルのbuildbook.build_authorhas_oneでの関連付けもこちらになります
has_many
で関連付けられたモデルのbuildauthor.books.build
1つだけ紐づくモデル
=>build_[モデル名の単数形]
複数紐づくモデル
=>[モデル名の複数形].build
と覚えとけば良さそうです?
(build_複数形
にするとインスタンスが複数buildされるイメージがつくからこのように分けたんですかね?)参考
- 投稿日:2021-02-20T16:56:55+09:00
rails db:migrateするとStandardError: An error has occurred, all later migrations canceled:のエラーコード発生
①内容
deviseをinstallした後のrails db:migrateをしたところStandardError: An error has occurred, all later migrations canceled:のエラーコード発生。
②結論
config/database.ymlのencoding: utf8mb4 ⇒ utf8にした事で解消。
③詳細
①ログイン機能実施の為、deviseのinstall実行
②rails g devise user(userモデルを作成)
③rails db:migrate(マイグレーションの実行)
④rails db:migrate:statusで確認すると、、、Status Migration ID Migration Name -------------------------------------------------- down 20210215130947 Devise create users◉ここでUPになっていないことに気付く。
⑤rails db:migrate:resetもNG
⑥調査しconfig/database.ymlのencoding: utf8mb4 ⇒ utf8にした事で解消。
⑦その後rails db:migrate:reset ⇒ rails db:migrateの順でターミナル実行
⑧rails db:migrate:status
Status Migration ID Migration Name -------------------------------------------------- up 20210215130947 Devise create usersこちらで解消。
今回も勉強になりました!!
初心者ですが、解消方法などを載せていきます。
間違い等ございましたら、ご指導ご鞭撻の程、よろしくお願いします。
- 投稿日:2021-02-20T16:27:46+09:00
rspecのテストでFactorybotが代入されなかった!?
WHY
rspecでテストコードの記述中、Factorybotで二つの変数を定義しようとしたところ、片方は代入されるのに、片方はされなかったことが起きたのでアウトプットしていきます。
問題
今回はテストコードを記述し、いざ実行!とするとこのようなエラー文がずらり、、、
対処
最近エラーを解除するのがとても楽しくなってきた自分ですが、とりあえず最初に目が止まったのは
「 Failure/Error: user = FactoryBot.create(:user)」
というエラー、
まぁ調べるまでもなくuserに入っていないという意味でしょう、、しかし、コードをみてみると、before do item = FactoryBot.create(:item) user = FactoryBot.create(:user) @sample = FactoryBot.build(:sample, user_id: user.id, item_id: item.id) end記述は上のitemと同じ、記述は間違っていない、、、となるとFactoryBot内がおかしいのか?とおもいましたが、
UserのFactoryBotは他のspecファイルでも使用しており、そこでは問題なく動作している、、、続いてエラー文の下の方をみてみると
「Failure/Error: _query(sql, @query_options.merge(options))」
という文字が、調べてみるとテストではたまに起きて、変数が代入しきる前にテストが実行されたりすることで起こるのだそう、、、
解決策としてはsleepというものを使う。
なので書いてみたbefore do item = FactoryBot.create(:item) user = FactoryBot.create(:user) @sample = FactoryBot.build(:sample, user_id: user.id, item_id: item.id) sleep(1) endこれでテストは1秒ごとに実行される。
しかしエラーは治らなかった、となればやっぱり代入がされない何かの理由がある!!
ということで次に目が行ったのは
「Validation failed: Email has already been taken」という文字直訳すると「メールはすでに使われている」というもの、
deviseを使っているので一意性があるのでしっかりバリデーションが仕事してくれています!解決
ということでFactorybotをみにいくと、
FactoryBot.define do factory :user do nickname { 'Test' } email { 'test@test' } password { 'test111' } password_confirmation { password } end endこのEmailに注目!
一意性のある値をテストするときはFakerを指定しなければならないのでemailの値を修正します!!email { Faker::Internet.free_email }その後テストはエラーなく無事解決しました!!
なお、「Failure/Error: _query(sql, @query_options.merge(options))」に関してはその後も出たので、
sleepはそのままにしています。
- 投稿日:2021-02-20T14:44:09+09:00
【AWS】デプロイ後にadminユーザーを追加する方法〜seedsファイルの実行〜
なんの話し?
AWSにデプロイした後にadminユーザーを追加する方法がわからなくて悩んだ結果の話しです。
開発環境ではseedsファイルにadmin: true
の記述をしていた。awsにデプロイした後にadminユーザーを追加したい
などで検索するとIAMアカウント関連の結果ばかり出てきてしまい、なかなか欲しい情報にたどり着けない。
そもそもseedsを追加した時のコマンドは開発環境で下記のように実行していた。開発環境のとき
% rails db:seed
そしてHerokuにデプロイした時にも同じことで悩み、実行したコマンドがこちら。
Herokuにデプロイしたとき
# アプリケーションのディレクトリで実行 % heroku run rails db:seedEC2のリポジトリでRailsを起動するときのコマンドを見ていたら、
「rails~
コマンドを使えれば追加できるのではないか?」と考え、実行してみた。AWSにデプロイしたとき
# EC2のリポジトリ内で実行 $ rails db:seed RAILS_ENV=productionこれでadminユーザーが追加された。
- 投稿日:2021-02-20T14:01:06+09:00
【Rails】【nested_form】追加された要素自体のIDを取得する方法
- 投稿日:2021-02-20T13:45:25+09:00
Postgresがサーバーに接続できない問題(could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/tmp/.s.PGSQL.5432"?)
環境
❯ sw_vers ProductName: macOS ProductVersion: 11.2.1 BuildVersion: 20D75 ❯ ruby -v ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin20] ❯ rails -v Rails 6.1.2.1 ❯ postgres --version postgres (PostgreSQL) 13.2状況の説明
macのローカル環境をリセットするために、Homebrewやその他諸々をアンインストール後、再び同じ環境を構築し、
bin/rails s
でサーバーをスタートさせると以下の画像のようなエラーが出てきた。brew services restart postgresql
などやっても変わらず。
原因
以前のpostgresのプロセスが残ってしまっているのが原因。バージョンアップの際にしばしば起こるらしい。
解決策
rm -rf /usr/local/var/postgres && initdb /usr/local/var/postgres -E utf8
でデータベースをリセットした後、brew services start postgresql
で接続できるようになった。データベースの情報はなくなってしまうので注意。
- 投稿日:2021-02-20T13:31:50+09:00
PostgreSQLで全ての行の特定のカラムの値を一括セットする方法
Railsプロジェクトで
posts
テーブルにuser_id
を持たせる必要性がでた。カラムは無事追加できたが、既存のレコードに1個ずつユーザーIDを手打ちする(Posticoを使ってます)のはめんどくさい。SQLは書いたことなかったが、以下のシンプルなコードでいける(かならず Export CSV なりしてバックアップをとってから実施されることをおすすめします)。UPDATE posts SET user_id=1https://stackoverflow.com/questions/10364200/setting-value-for-one-column-of-all-records-in-table
- 投稿日:2021-02-20T13:30:56+09:00
【Rails】ActiveRecord::ConnectionNotEstablished を解消する
1.はじめに
railsでアプリを作成し、サーバーを立ち上げ
rails s
を行い、http://localhost:3000/XX
にアクセスしました。
すると、ActiveRecord::ConnectionNotEstablished
と表示されました。2.使用環境
- mac.os バージョン10.15.6
- Ruby 2.6.6
- Rails 6.0.3.5
- psql (PostgreSQL) 12.6
3.実際のエラー
4.試したこと
4.1 データベースの確認
error.rb# 利用可能な全てのデータベースを一覧表示する hogehoge@hogenoAir sample_app % psql -l psql: error: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/tmp/.s.PGSQL.5432"?4.2 postmaster.pidの削除
hogehoge@hogenoAir sample_app % rm /usr/local/var/postgres/postmaster.pidこちらを試すと、うまくいきました。
補足 /usr/の場所
macの場合、Finderの移動タブから、
フォルダへ移動
を選択し、/usr/
と入力すると表示されます。5.まとめ
今回はリンクの5番に近い状況で、
① パソコンがフリーズ
② 全て保存・終了して再起動
③ 表題のエラーが表示される ...という流れでした。②で全て終了でいたはずが、うまく終了されなかったようです。
傷がついてしまったpostmaster.pid
を削除することで、解決できました。6.参考リンク
1:PostgreSQL 9.1.5文書
2.Postgresqlに接続できなくなった時
3.Postgres could not connect to server
4.【Mac】Finderから /usr / local ディレクトリを参照する
5.Mac+HomebrewでPostgreSQLが起動しない場合の対応7.最後に
記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。
読んでいただき、ありがとうございました。
- 投稿日:2021-02-20T13:00:42+09:00
Rails 6.0 でカラムの型を string -> integer に変更する方法
ググったら
'integer USING CAST(column_name AS integer)'
みたいなやり方がでたけどこれは古い書き方のようでエラーが出た。Rails6で上手く行ったのは下記。20210219164606_change_user_id_in_posts.rbclass ChangeUserIdInPlatforms < ActiveRecord::Migration[6.0] def change change_column :posts, :user_id, :integer, using: 'user_id::integer' end endhttps://stackoverflow.com/questions/3537064/rails-migration-to-convert-string-to-integer
役立ちそうなコマンド
ただしrollbackやマイグレーションファイルの削除は特にチーム開発ではご法度。やらないことを推奨する。
# 戻したいとき ## マイグレーションのバージョン確認 $ rails db:version ## バージョンを戻す(ただし非推奨) $ rails db:rollback step=2 $ rails db:rollback 20210219164606_change_user_id_in_posts.rbただし
change
メソッドで定義した操作のうちremove_column
やchange_column
はrollbackすることはできない。そのときはup
メソッドとdown
メソッドの2つ(migrateはup, rollbackはdown)にマイグレーションファイルを置き換える必要がある(rails db:migrate
した後にマイグレーションファイルを変更してrails db:rollback
するみたい‥怖すぎるけど)。class removeColumnHoge < ActiveRecord::Migration def change remove_column :hoge, :fuga end endclass removeColumnHoge < ActiveRecord::Migration def up remove_column :hoge, :fuga end def down add_column :hoge, :fuga, :string end endhttp://tanihiro.hatenablog.com/entry/2014/01/10/182122
その他
投稿とユーザーを紐付ける場合、投稿モデルに持たせるuser_idはintegerじゃなくてreferrenceで持つべきというQiitaもあった。Progateではintegerになってたけど
- 投稿日:2021-02-20T12:43:27+09:00
評価機能 + 自己完結型多対多アソシエーション
はじめに
前回作成したrails 評価機能(数字のみ)(https://qiita.com/inoponA/items/60384b454e16024295ff)を投稿しました
まぁ当然と言っちゃ当然だがこれだとユーザー、一人一人の評価が評価される訳ではなくでのページでも同じ評価がなされてしまうと言う訳で、個別表示+α機能を備えた評価機能を作りました
自己完結多対多とは?
まず個別に表示するには?と考えた時、一対多だとどのユーザーが評価した?しか分からない訳です
よって、一対多のアソシエーションではなく、多対多のアソシエーションを組むことによって誰が誰に評価したかわかりやすくする
例:ラーメン店のレビュー
これでレビューは出来るのだが、今回が人が人に評価する図式となるので上記ものだと少し違う
少しややこしいのだが、userテーブル一つにreviweテーブルが中間テーブルと言う形になる
今回はこの自己完結多対多を利用します
DB,カラム
_create_reviews.rb
t.integer :speedy t.integer :kindness t.integer :frantically t.references :reviewer, null: false, foreign_key: { to_table: :users } t.references :reviewing, null: false, foreign_key: { to_table: :users } t.timestamps注目していただきたいのはreviewerとreviewingと言うカラムが作らているがこれはforeign_key: { to_table: :users }でuserテーブルを外部キーとして指定している
でもこれだけだとただのreviewer、reviewingカラムができただけであるので下記のモデルにこのカラムが擬似的なuser.idだとするようにしてあげる必要があるreviewモデル
class Review < ApplicationRecord belongs_to :reviewer, class_name: "User" belongs_to :reviewing, class_name: "User" endここできもなのがclass_nameオプションである
これによって同じuser_idをreviewer_id、reviewing_idと言う形で分ける事が可能になるので誰が誰にと言う図式が完成するコレで中間テーブルは完成
でも中間テーブルがあると言うことは多の部分も作成していくことになるuser.rb
has_many :active_reviews, class_name: "Review",foreign_key: :reviewing_id has_many :reviewings, through: :active_reviews, source: :reviewer has_many :passive_reviews, class_name: "Review",foreign_key: :reviewer_id has_many :reviewers, through: :active_reviews, source: :reviewing def followed_by?(user) passive_reviews.find_by(reviewing_id: user.id).present? end一つ一つ説明します
まずactive_reviewsとかpassive_reviewsなんやねんと思ったでしょうが、reviewと言う中間テーブルを扱ってもいいのだがこれだと後述の評価を一人一回と言う制限をする為には少々不都合なので
”レビューする側のテーブルとされる側のテーブル”とclass_nameで名前を変える要するに
- active_reviewsはレビューされる側
- passive_reviewsはレビューする側
であるdef followed_by?(user) passive_reviews.find_by(reviewing_id: user.id).present? endはpassive_reviewsのレビューされる側からレビューされるIDを探せと言うコードを記述し一人一回しか評価できないようにします
routes.rb
resources :users do resources :reviews, only: :create endユーザーにレビューをネストさせる
レビューされる為にはユーザーのIDが欲しいのでこれをする必要があるcontroller-review
class ReviewsController < ApplicationController def create @review = Review.create(review_params) if @review.save redirect_to root_path else render :show end end private def review_params params.require(:review).permit(:speedy, :kindness, :frantically).merge(reviewer_id: current_user.id, reviewing_id: params[:user_id]) end end言うまでもないが、mergeで各ユーザーIDも保存している
- reviewer_idは評価した人(評価の人)
- reviewing_idはされた人(ユーザーページの人)controller-user
def show @posts = @user.posts @review = Review.new @kindness = Review.where(reviewing_id: params[:id]).average(:kindness) @speedy = Review.where(reviewing_id: params[:id]).average(:speedy) @frantically = Review.where(reviewing_id: params[:id]).average(:frantically) if @kindness != nil && @speedy != nil && @frantically != nil @comprehensive = (@kindness + @frantically + @speedy) / 3 else @speedy = 0 @kindness = 0 @frantically = 0 @comprehensive = @kindness + @frantically + @speedy end今回はshowページで一連の流れを行っているのでshowに必要な事を記述しています
@review = Review.newでレビュー内容を生成
以下は平均値を求める内容です
Review.where(reviewing_id: params[:id])でされた人のIDを探しその中でも特定のカラムの平均が欲しかったので.averageを利用しましたview1 表示側
- if @user.id != current_user.id - if current_user.followed_by?(@user) .UserEvaluate 評価は一人一回です - else .UserEvaluate %button.EvaluateBtn = "#{@user.name}さんを評価する" = render "evaluate" .UserStatus 他のユーザーの評価 .UserStatus__Kindness = icon('fa','smile') + "親切度 : #{@kindness.round(1)} point" .UserStatus__speedy = icon('fa','shipping-fast') +"迅速さ : #{@speedy.round(1)} point" .UserStatus__frantically = icon('fa','redo')+"repeat : #{@frantically.round(1)} point" .UserStatus__comprehensive = icon('fa','star')+"総合力 : #{@comprehensive.round(1)} point" .UserEdit1行目:投稿者と閲覧者が同一ユーザー出ない時に分岐するIF文の作成
同一だと評価できない図式に
2行目:followed_by?メソッドをビューで利用してもしログインしているユーザーがレビューした側にいたら評価は一人一回ですと言う表示をしていなければ評価出来るように分岐する
ビューはこれだけview2 入力側
.EvaluateSide .EvaluateSide__EvaluateBox = form_with model:[@user,@review],local: true do |f| .close = icon('fas','times') .UserEvaluate .UserEvaluate__title = "#{@user.name}さんを評価しよう" .UserEvaluate__UserKindness = "#{@user.name}さんをは親切でしたか?" .form .form__KindnessGood = f.radio_button :kindness,"3",id: "kaidness-good" ,class: "UserKindnessEvaluate" .form__KindnessGood__good = f.label "親切" ,for:"kaidness-good" .form__KindnessUsually = f.radio_button :kindness,"2",id: "kaidness-usually" ,class: "UserKindnessEvaluate" .form__KindnessUsually__Usually = f.label "普通" ,for:"kaidness-usually" .form__KindnessBad = f.radio_button :kindness,"1",id: "kaidness-bad" ,class: "UserKindnessEvaluate" .form__KindnessBad__bad = f.label "不親切" ,for:"kaidness-bad" .UserEvaluate__UserSpeedy = "#{@user.name}さんをは迅速な対応でしたか?" .form .form__SpeedyGood = f.radio_button :speedy, "3",id: "speedy-good" ,class: "UserKindnessEvaluate" .form__SpeedyGood__good = f.label "迅速" ,for:"speedy-good" .form__SpeedyUsually = f.radio_button :speedy, "2",id: "speedy-usually" ,class: "UserKindnessEvaluate" .form__SpeedyUsually__Usually = f.label "普通" ,for:"speedy-usually" .form__SpeedyBad = f.radio_button :speedy, "1",id: "speedy-bad" ,class: "UserKindnessEvaluate" .form__SpeedyBad__bad = f.label "遅い" ,for:"speedy-bad" .UserEvaluate__frantically = "#{@user.name}さんにもう一度お願いしたいですか?" .form .form__franticallyGood = f.radio_button :frantically, "3",id: "frantically-good" ,class: "UserKindnessEvaluate" .form__FranticallyGood__good = f.label "頼みたい" ,for:"frantically-good" .form__FranticallyUsually = f.radio_button :frantically, "2",id: "frantically-usually" ,class: "UserKindnessEvaluate" .form__FranticallyUsually__Usually = f.label "普通" ,for:"frantically-usually" .form__FranticallyBad = f.radio_button :frantically, "1",id: "frantically-bad" ,class: "UserKindnessEvaluate" .form__FranticallyBad__bad = f.label "これっきり" ,for:"frantically-bad" .UserEvaluate__SendBox = f.submit "#{@user.name}さんを評価する",class:"send-btn"ざっと長いコードになってしまったが重要なのは
= form_with model:[@user,@review],local: true do |f|
の一文である
ただそれだけ
ちなみにこれは逆だとエラーが起こる、私はこれの解決に時間がかかってしまったがどっちは親かって考えたら普通はわかるだろうと思う?最後に
かなり解釈が間違えているかもですがそこはご愛敬お願いします笑
- 投稿日:2021-02-20T12:37:39+09:00
simpackerでRails + React + Typescript環境構築
はじめに
simpackerとは
webpackerを使わず、シンプルなwebpackでRailsを開発するgem。
クックパッド技術部の方が作られたgemです。
https://github.com/hokaccha/simpacker
Simpacker: Rails と webpack をもっとシンプルにインテグレーションしたいのです
Githubと、このクックパッドの開発者ブログを見れば、simpackerが何なのかほとんどわかると思います。なぜsimpacker?
Rails6以降、webpackerが標準搭載になっていますが、webpackerは独自のDSLになっており、webpack本来の設定などが見えなくなっています。簡単にwebpackを扱えますが、設定のカスタマイズには独自DSLを学ぶコストがついてきます。またwebpackの細かい設定などは調整しにくかったりできないこともあるので、純粋なwebpackを使いたいならsimpackerの導入をおすすめします。
またwebpackerの独自DSLを学ぶなら、webpackそのものを学んだ方が今後の開発に活かせる気がします。私は初めて現場で触れたのがsimpackerの方で、webpackerのことはよくわかってなかったりします。笑Rails + React + TypeScriptで環境構築
バックエンドはRails、フロントエンドはReact + TypeScriptで構成された開発手順をメモしたいと思います。
開発環境
ruby 3.0.0
rails 6.1.1
yarn 1.22.10
tsc 4.1.3手順
グローバルを汚さないRails環境構築やMySQLのコンテナ化は別記事に解説してますので、よければ参考にしてください。
Dockerでコンテナ化したMySQLを使用してRails環境構築
Railsの環境構築(グローバル環境を汚さずに)railsプロジェクト立ち上げ
bundle exec rails new my_app --skip-javascript bundle exec rails db:createwebpackerを入れたくないので、
--skip-javascript
を付けます。simpackerをGemfileに追加
Gemfilegem 'simpacker'gemインストール
bundle installsimpacker初期化コマンド実行
bundle exec rails simpacker:installReact, TypeScript、必要なパッケージをインストール
yarn add -D react react-dom yarn add -D typescript ts-loaderyarnを使っていますが、npmでも問題ありません。
ts-loaderはtypescriptをjavascriptにトランスパイルするためのパッケージです。webpack.config.jsを作成
ここにwebpackの設定を書いていきます。
純粋なwebpackと全く同じ書き方です。webpack.config.jsconst path = require("path"); const WebpackAssetsManifest = require("webpack-assets-manifest"); const { NODE_ENV } = process.env; const isProd = NODE_ENV === "production"; module.exports = { mode: isProd ? "production" : "development", devtool: "source-map", entry: { application: path.resolve(__dirname, "app/frontend/js/packs/application.tsx"), }, output: { path: path.resolve(__dirname, "public/packs"), publicPath: "/packs/", filename: isProd ? "[name]-[hash].js" : "[name].js", }, resolve: { extensions: [".js", ".ts", ".jsx", "tsx"], }, module: { rules: [ { test: /\.(js|ts|jsx|tsx)$/, exclude: /node_modules/, use: [ {loader: "ts-loader"} ] } ] }, plugins: [ new WebpackAssetsManifest({ publicPath: true, output: "manifest.json", }), ], };
const path = require("path");
node.jsのpathモジュールを読んでます。
const WebpackAssetsManifest = require("webpack-assets-manifest");
を生成してくれるパッケージです。
manifest.json
const { NODE_ENV } = process.env;
こちらで任意の環境変数を読み込んでいます。
mode:
modeによって出力ファイルの形式が変わります。productionだと圧縮され、develomentだとみやすく整形されて出力されます。
devtool:
ソースマップを指定できます。ソースマップを有効にすると、ブラウザコンソールでエラーを確認するときに、エラー箇所を特定できるため必須だと思います。
entry:
webpackに読み込ませるエントリポイントを指定します。
path.resolve(__dirname, "")
と言う表記は環境に依存しない絶対pathを取得できるっぽいです。
output:
ファイルに出力先を指定します。
publicPath
は本番環境での解決pathを指定しています。
railsではデフォルトでpublic配下がドキュメントルートなので、/packs/
を指定しています。
extensions:
importするファイルの拡張子を省略できます。同じファイル名の異なる拡張子ファイルが存在した場合、配列の先頭のものが読み込まれます。import File from '../path/to/file';
rules:
トランスパイルするローダーの設定を書きます。
test:
で対象ファイルを指定します。
use
で使用するローダーをしてします。複数書いた場合は後ろから実行されます。
WebpackAssetsManifest
:
manifest.jsonを作成するwebpack用ライブラリです。webpackの設定はやはり公式を参照すべきだと思います。
https://webpack.js.org/concepts/
こちらも充実しています。
webpack 4 入門 - Qiitatsconfig.jsonを作成
typescriptの設定を書いていきます。
tsconfig.json{ "compilerOptions": { "target": "es5", "module": "es2015", "jsx": "react", "allowJs": true, "moduleResolution": "node", "sourceMap": true, "strict": true, "noImplicitAny": false, }, "include": [ "app/frontend/js/**/*" ], "exclude": [ "**/*.(spec|test).ts", "**/setup.jest.ts", ] }
target:
出力するjsのバージョンを指定します。
module:
使用するモジュールを指定します。targetやmoduleについてまだ詳しく理解していないので、今後勉強していきたいと思ってます。
jsx:
reactを使用する場合、reactを指定します。
allowJs:
trueでjsファイルもトランスパイルしてくれます。
moduleResolution:
とりあえずnodeにしておけばいい?
strict:
全ての型チェックを有効にします。tsconfig.jsonについては、
公式にコンパクトにまとまっています。
https://typescript-jp.gitbook.io/deep-dive/project/compilation-context/tsconfig
日本語だと、こちらの記事でかなり詳細に解説してくださっています。
tsconfig.jsonの全オプションを理解する(随時追加中) - QiitaReactコンポーネントを作成
エントリーポイントのファイルを作成していきます。
app/frontend/js/packs/application.tsximport * as React from 'react'; import * as ReactDOM from 'react-dom'; import Index from '../pages/Index'; const appElement = document.getElementById('app'); if (appElement) { ReactDOM.render(( <Index /> ), appElement); }レンダーするコンポーネント
app/frontend/js/pages/Index.tsximport * as React from 'react'; interface Props {} const Index: React.FC<Props> = () => { return( <div>Hello React</div> ) }; export default Index;これをwebpackでビルドしてjsファイルを出力します
yarn webpack
/public/packs/
配下にapplication.js
,application.js.map
,manifest.json
が作成されていると思います。これらをRails側で読み込みましょう。
bundle exec rails g controller Topapp/controllers/top.rbclass TopController < ApplicationController def index; end endapp/views/top/index.html.erb<div id="app"></div>app/views/layouts/application.html.erb<!DOCTYPE html> <html> <head> <title>Sample</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> </head> <body> <%= yield %> <%= javascript_pack_tag 'application' %> </body> </html>simpackerが良い感じに
<%= javascript_pack_tag 'application' %>
を解釈して読み込んでくれます。
http://localhost:3000/index
にアクセスしてHello Reactが表示されれば成功です。終わりに
simpackerはシンプルにwebpackを扱えるようにしてくれます。
ただ、今のRailsのフロント周りのgemはwebpackerを前提に作られているものが多いので、そういうgemを利用する際には、かなり苦労することもありますので、少なからずデメリットも存在します。
- 投稿日:2021-02-20T12:13:48+09:00
ActiveHash
ActiveHash
都道府県名一覧やカテゴリーなど「基本的に変更されないデータ」は、データベースに保存する必要性がありません。
ビューファイルなどにそれらのデータを直接書いてしまうと、記述量が多くなり見づらくなります。
そのようなケースでは、ActiveHashを使って実装します。
モデルファイルに直接記述した変更されないデータに対して、ActiveRecordのようなメソッドを用いることができます。ミニアプリを作りながら使ってみましょう。
% rails _6.0.0_ new active_hash -d mysql # active_hashに移動 % cd active_hash # データベースの生成 % rails db:createGemを追加します
Gemfilegem 'active_hash'住所を管理するaddressモデルを作成しましょう。
% rails g model address都道府県を管理するprefectureモデルを作成しデータを定義します
モデルの「prefectureクラス」を定義し、ActiveHash::Baseクラスを継承します。
app/modelsディレクトリ配下にprefecture.rbを作成します。ActiveHash::Base
あるモデル内(クラス内)でActiveHashを用いる際に必要となるクラスです。ActiveHashのGemに定義されていて継承することで、ActiveRecordと同じようなメソッドを使用できるようになります。
class Prefecture < ActiveHash::Base self.data = [ { id: 0, name: '--' }, { id: 1, name: '北海道' }, { id: 2, name: '青森県' }, { id: 3, name: '岩手県' }, { id: 4, name: '宮城県' }, { id: 5, name: '秋田県' }, { id: 6, name: '山形県' }, { id: 7, name: '福島県' }, { id: 8, name: '茨城県' }, { id: 9, name: '栃木県' }, { id: 10, name: '群馬県' }, { id: 11, name: '埼玉県' }, { id: 12, name: '千葉県' }, { id: 13, name: '東京都' }, { id: 14, name: '神奈川県' }, { id: 15, name: '新潟県' }, { id: 16, name: '富山県' }, { id: 17, name: '石川県' }, { id: 18, name: '福井県' }, { id: 19, name: '山梨県' }, { id: 20, name: '長野県' }, { id: 21, name: '岐阜県' }, { id: 22, name: '静岡県' }, { id: 23, name: '愛知県' }, { id: 24, name: '三重県' }, { id: 25, name: '滋賀県' }, { id: 26, name: '京都府' }, { id: 27, name: '大阪府' }, { id: 28, name: '兵庫県' }, { id: 29, name: '奈良県' }, { id: 30, name: '和歌山県' }, { id: 31, name: '鳥取県' }, { id: 32, name: '島根県' }, { id: 33, name: '岡山県' }, { id: 34, name: '広島県' }, { id: 35, name: '山口県' }, { id: 36, name: '徳島県' }, { id: 37, name: '香川県' }, { id: 38, name: '愛媛県' }, { id: 39, name: '高知県' }, { id: 40, name: '福岡県' }, { id: 41, name: '佐賀県' }, { id: 42, name: '長崎県' }, { id: 43, name: '熊本県' }, { id: 44, name: '大分県' }, { id: 45, name: '宮崎県' }, { id: 46, name: '鹿児島県' }, { id: 47, name: '沖縄県' } ] endデータは、配列にハッシュ形式で格納しています。
マイグレーションファイル変更
class CreateAddresses < ActiveRecord::Migration[6.0] def change create_table :addresses do |t| t.string :area, null: false t.text :text, null: false t.integer :prefecture_id, null: false t.timestamps end end endマイグレーション実行
% rails db:migrateアソシエーションを設定
住所を表示する際、都道府県を取得できるように、AddresモデルとPrefectureモデル間でアソシエーションを設定しておきましょう。
ActiveHashを用いてアソシエーションを設定する場合は、ActiveHashで定義されているmoduleをモデルに取り込む必要があります。module(モジュール)
特定の役割を持つメソッドや定数に名前を付けてまとめたものです。moduleはどんなオブジェクトにも取り込んで使うことが可能です。複数のクラスにまたがるメソッドや定数をmoduleとしてまとめることで、コードの肥大化を防いだり、複数クラスの特徴を継承させたいクラスを作成するときに使います。
Addressモデルのアソシエーションを設定
住所は、1つの都道府県に紐付いています。そのため、Addressモデルにはbelongs_toを設定します。
ActiveHashを用いて、belongs_toを設定するには、
extend ActiveHash::Associations::ActiveRecordExtensionsと記述してmoduleを取り込みます。class Address < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions belongs_to :prefecture endPrefectureモデルのアソシエーションを設定しましょう
1つの都道府県は、たくさんの住所に紐付いています。そのため、Prefectureモデルにはhas_manyを設定します。ActiveHashを用いて、has_manyを設定するには、
include ActiveHash::Associationsと記述してmoduleを取り込みます。class Prefecture < ActiveHash::Base self.data = [ { id: 0, name: '--' }, { id: 1, name: '北海道' }, { id: 2, name: '青森県' }, { id: 3, name: '岩手県' }, { id: 4, name: '宮城県' }, { id: 5, name: '秋田県' }, { id: 6, name: '山形県' }, { id: 7, name: '福島県' }, { id: 8, name: '茨城県' }, { id: 9, name: '栃木県' }, { id: 10, name: '群馬県' }, { id: 11, name: '埼玉県' }, { id: 12, name: '千葉県' }, { id: 13, name: '東京都' }, { id: 14, name: '神奈川県' }, { id: 15, name: '新潟県' }, { id: 16, name: '富山県' }, { id: 17, name: '石川県' }, { id: 18, name: '福井県' }, { id: 19, name: '山梨県' }, { id: 20, name: '長野県' }, { id: 21, name: '岐阜県' }, { id: 22, name: '静岡県' }, { id: 23, name: '愛知県' }, { id: 24, name: '三重県' }, { id: 25, name: '滋賀県' }, { id: 26, name: '京都府' }, { id: 27, name: '大阪府' }, { id: 28, name: '兵庫県' }, { id: 29, name: '奈良県' }, { id: 30, name: '和歌山県' }, { id: 31, name: '鳥取県' }, { id: 32, name: '島根県' }, { id: 33, name: '岡山県' }, { id: 34, name: '広島県' }, { id: 35, name: '山口県' }, { id: 36, name: '徳島県' }, { id: 37, name: '香川県' }, { id: 38, name: '愛媛県' }, { id: 39, name: '高知県' }, { id: 40, name: '福岡県' }, { id: 41, name: '佐賀県' }, { id: 42, name: '長崎県' }, { id: 43, name: '熊本県' }, { id: 44, name: '大分県' }, { id: 45, name: '宮崎県' }, { id: 46, name: '鹿児島県' }, { id: 47, name: '沖縄県' } ] include ActiveHash::Associations has_many :addresses endnumericality
数値かどうかを検証するバリデーションの一種です。
数値であればデータベースに保存を許可して、それ以外では保存が許可されないようにできます。
今回は、--を保存されないようにしたいので、id: 1以外であれば保存できるように設定します。class Address < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions belongs_to :perefecture validates :area, :text, presence: true validates :prefecture_id, numericality: { other_than: 1 } endルーティングを設定
config/routes.rb
Rails.application.routes.draw do root to: 'addresses#index' resources :addresses endコントローラーとビューを作成
% rails g controller addresses index newaddresses_controller.rbを編集
class AddressesController < ApplicationController def index @adress = Address.order("created_at DESC") end def new @address = Address.new end def create @address = Address.new(address_params) if @address.save redirect_to root_path else render :new end end private def address_params params.require(:address).permit(:area,:text,:prefecture_id) end endindex.html.erbを編集
<h1>エリア一覧</h1> <%= link_to "投稿する", new_address_path, class:"post" %> <% @adress.each do |address| %> <div class="address"> <div class="address-area"> <%= address.prefecture.name %> </div> <div class="address-title"> <%= address.area %> </div> <div class="address-text"> <%= address.text %> </div> </div> <% end %>index.cssを以下のように作成し編集してください。
h1 { text-align: center; } .post { display: block; width: 150px; padding: 10px; border: 1px solid white; background-color: lightskyblue; color: white; text-decoration: none; text-align: center; margin: 0 auto; margin-bottom: 20px; } .address { height: 200px; background-color: lemonchiffon; display: flex; align-items: center; flex-direction: column; border: 1px solid #fff; padding: 20px; } .address-area { font-size: 16px; border: 1px solid; padding: 5px; background-color: lightblue; } .address-title { font-size: 20px; font-weight: bold; }collection_select
データをプルダウン形式で表示することができるメソッドです。
new.html.erbを編集
<%= form_with model: @address, url:addresses_path, local: true do |f| %> <div class="address-box"> 投稿する <%= f.text_field :area, class:"area", placeholder:"エリア" %> <%= f.text_area :text, class:"text", placeholder:"テキスト" %> <%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {}, {class:"prefecture-select"}) %> <%= f.submit "投稿する" ,class:"btn" %> </div> <% end %>collection_selectは、下記のような順番で記述します。
<%= form.collection_select(保存されるカラム名, オブジェクトの配列, カラムに保存される項目, 選択肢に表示されるカラム名, オプション, htmlオプション) %>
引数 値 役割 第一引数(保存されるカラム名) :prefecture_id 保存先のカラム名 第二引数(オブジェクトの配列) Prefecture.all 配列データを指定する 第三引数(カラムに保存される項目) id 表示する際に参照するDBのカラム名 第四引数(選択肢に表示されるカラム名) name 実際に表示されるカラム名 第五引数(オプション) {} 今回はオプションの指定なし htmlオプション {class:"prefecture-select"} 今回はクラス名を付与 new.cssを以下のように作成し編集してください。
.address-box { height: 800px; background-color: lightseagreen; display: flex; justify-content: center; align-items: center; flex-direction: column; } .area { height: 30px; width: 300px; margin: 20px; } .text { height: 100px; width: 300px; resize: none; margin-bottom: 20px; } .prefecture-select { height: 30px; width: 250px; } .btn { width: 200px; margin-top: 20px; padding: 15px; border: 1px solid white; background-color: lightslategray; color: white; }http://localhost:3000/articles/new にアクセスして
挙動を確認してみましょう。以上です。
- 投稿日:2021-02-20T10:40:51+09:00
【Rails】特定のカラムのオプションだけを変更したい
Rails6.0.0でアプリを作っていて、既に作成済みのテーブルのカラムにオプションの制約をつけ忘れていた。
なので、特定のカラムのオプションだけを追加で設定する方法をまとめる。現状
現状のマイグレーションファイルは以下のように「null:false」オプションを付け忘れているカラムがある。
class CreateItems < ActiveRecord::Migration[6.0] def change create_table :items do |t| t.string :name t.text :explain t.integer :price t.references :user, null: false, foreign_key: true t.integer :category_id, null: false t.integer :item_status_id, null: false t.integer :shipping_fee_id, null: false t.integer :prefecture_id, null: false t.integer :delivery_id, null: false t.timestamps end end end手順
①新しいマイグレーションファイルを作る。
「rails g migration ChangeColumnOfItems」とコマンドを打つ(アッパーキャメル)。
コマンドの意味は「Itemsテーブルのカラムを変更せよ」という感じ。terashimatakaya@MacBook-Air furima-34501 % rails g migration ChangeColumnOfItems Running via Spring preloader in process 8220 invoke active_record create db/migrate/20210220012237_change_column_of_items.rb②マイグレーションファイルを自分で修正する。
「Railsガイドv6.1」のマイグレーションの章を参考に、以下のように記述した。
意味としては、「itemsテーブルのnameカラムにnull:falseのオプションを追加してね」という感じ。class ChangeColumnOfItems < ActiveRecord::Migration[6.0] def change change_column_null :items, :name, false change_column_null :items, :explain, false change_column_null :items, :price, false end end③マイグレーションを実行
「rails db:migrate」を実行。
- 投稿日:2021-02-20T04:37:25+09:00
sqlcommenterをRuby on Railsのデモアプリケーションで動かしてみる
Googleが提供しているオープンソースのツールで、ORMが生成するSQLの調査を容易にしてくれるらしいので使ってみました。
具体的にはログなどに、コメントが含まれるようになり、ORMが生成したSQL文はどのコードで生成されたものかを知ることができるみたいです。今回Rails APIモードのデモアプリケーションが用意されているので、どのようなコメントが出力されるか動かして確認してみます。
google/sqlcommenter | GitHubsqlcommenterが対応する言語、フレームワーク、DBは以下
言語
- Ruby
- Python
- JavaScript
- Node.js
- Java
フレームワーク
- Ruby on Rails
- Flask
- Django
- Express
- Knex.js
- etc...etc
DB
- MySQL
- MariaDB
- PostgreSQL
- SQLite
- Google Cloud SQL
デモRailsアプリケーションで試してみる
google/sqlcommenter | Rails demo
RailsのAPIデモアプリケーションでとりあえずsqlcommenterがどんなものかを体験ができるみたいです。
ただ、sqlcommenter_railsはrubygemsではリリースされていないようなので、上記のREADMEの手順に沿って環境構築すればとりあえずは使うことができます。APIは以下の2つが用意されています。
- Get /posts
- POST /posts
APIを叩くcurl
bashcurl localhost:3000/postsbashcurl -X POST localhost:3000/posts -d 'title=my-post'POST /postsを実行
bashcurl -X POST localhost:3000/posts -d 'title=my-post'INSERT INTO "posts" ("title", "created_at", "updated_at") VALUES (?, ?, ?) /*action='create',application='SqlcommenterRailsDemo',controller='posts',db_driver='ActiveRecord::ConnectionAdapters::SQLite3Adapter', framework='rails_v6.0.3.5',route='/posts', traceparent='00-e71c784d7151a939ef4e8d886a326456-82ad00a116eaa038-01'*/初期設定では以下の情報が出力されるようです。
- action
- application
- controller
- db_driver
- framework
- route
- traceparent
設定を追加することで、出力する情報の変更 / 追加が可能です。
bashmkdir config/initializers touch config/initializers/marginalia.rb vim config/initializers/marginalia.rb # 追加 Marginalia::Comment.components = [ :action, :application, :controller_with_namespace, :hostname, :job, :line] ~ ~ ~Rails serverを再起動して再度curlを実行すると先ほど追加した情報が表示されます
/*action='create',application='SqlcommenterRailsDemo',controller_with_namespace='PostsController', hostname='xxxx',line='/app/controllers/posts_controller.rb:25:in `create\''*/GET /postsを実行
次にpostの一覧を取得してみます。
bashcurl localhost:3000/postsSELECT "posts".* FROM "posts" /*action='index',application='SqlcommenterRailsDemo',controller_with_namespace='PostsController', hostname='xxxx',line='/app/controllers/posts_controller.rb:19:in `index\''*/先程のPOSTと同じくactionや実際にSQL文が生成されたコードの位置を出力してくれました。
posts_controller.rbは以下のようになっています。
app/controllers/posts_controller.rb#... 17 class PostsController < ApplicationController 18 def index 19 render json: Post.all 20 end 21 22 def create 23 title = params[:title].to_s.strip 24 head :bad_request if title.empty? 25 render json: Post.create!(title: title) 26 end 27 end参考
- 投稿日:2021-02-20T04:35:32+09:00
N+1問題の発見方法と解決方法(備忘録)
概要
N+1問題とは必要以上にSQL文が発行されてパフォーマンスが低下する問題です。
N+1問題の解決方法
便利なgem bullet(N+1を検出してくれる)の導入
最後に初学者のただの備忘録です。
環境
- Ruby: 2.6.6
- Rails: 6.0.3.5
実装例
例えば、パラメータのcategory_nameがDBに存在するかどうかによって
@ideasに代入される値が変わる処理があるとします。app/controllers/ideas_controller.rbdef index category = Category.find_by(name: params[:category_name]) if category.present? @ideas = category.ideas render formats: :json else @ideas = Idea.all render formats: :json end endcategoryとideaの関係は
app/models/category.rbhas_many :ideas, dependent: :destroyapp/models/idea.rbbelongs_to :categoryN+1問題が発生してない場合
category.present?がtrueの場合は@ideasにcategory.ideasが代入されて
レンダリングされる。
そのときのログを一応確認(わかりやすいように一部ログをはしょっています)
CategoryとIdeaが1回ずつ読み込まれてます。N+1問題は発生していません。ターミナルCategory Load (0.5ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`name` = 'hoge1' LIMIT 1 ↳ app/controllers/api/v1/ideas_controller.rb:13:in `index' Idea Load (0.4ms) SELECT `ideas`.* FROM `ideas` WHERE `ideas`.`category_id` = 1 ↳ app/views/api/v1/ideas/index.json.jbuilder:2N+1問題が発生している場合
category.present?がfalseの場合、@ideasにIdea.allが代入されてレンダリングされる。
ログを確認するとCategory Loadが何回も...
これがN+1問題です。ターミナルIdea Load (0.5ms) SELECT `ideas`.* FROM `ideas` ↳ app/views/api/v1/ideas/index.json.jbuilder:2 Category Load (0.3ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.3ms) ↳ app/models/idea.rb:4:in category_name CACHE Category Load (0.0ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.3ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.4ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.3ms) ↳ app/models/idea.rb:4:in category_name CACHE Category Load (0.0ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.4ms) ↳ app/models/idea.rb:4:in category_name CACHE Category Load (0.0ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.4ms) ↳ app/models/idea.rb:4:in category_nameN+1問題を解決する方法
結論から言いますとincludes、preload、eager_loadのいずれかを使用すると解決できます。
他の記事ではよくincludesで解決してますが、結局のところincludesは条件によって
preloadしたりeager_loadしたりする。preloadはエラー(例外)を発生させることもあるので
eager_loadを使用するのが無難だと思います。詳しく知りたい方は
下記の記事を読んでみてください。ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い
では、解決していきます。
eager_load (LEFT OUTER JOIN)の場合
app/controllers/ideas_controller.rb# def index # category = Category.find_by(name: params[:category_name]) # if category.present? # @ideas = category.ideas # render formats: :json # else @ideas = Idea.eager_load(:category) # もとはIdea.all # render formats: :json # end # endターミナルCategory Load (0.6ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`name` = 'hoge1ddd' LIMIT 1 ↳ app/controllers/api/v1/ideas_controller.rb:13:in `index' Rendering api/v1/ideas/index.json.jbuilder SQL (0.5ms) SELECT `ideas`.`id` AS t0_r0, `ideas`.`category_id` AS t0_r1, `ideas`.`body` AS t0_r2, `ideas`.`created_at` AS t0_r3, `ideas`.`updated_at` AS t0_r4, `categories`.`id` AS t1_r0, `categories`.`name` AS t1_r1, `categories`.`created_at` AS t1_r2, `categories`.`updated_at` AS t1_r3 FROM `ideas` LEFT OUTER JOIN `categories` ON `categories`.`id` = `ideas`.`category_id` ↳ app/views/api/v1/ideas/index.json.jbuilder:2何回もCategoryがLoadされていたSQL文が発行されなくなりました。
preloadの場合
app/controllers/ideas_controller.rb# def index # category = Category.find_by(name: params[:category_name]) # if category.present? # @ideas = category.ideas # render formats: :json # else @ideas = Idea.preload(:category) # もとはIdea.all # render formats: :json # end # endターミナルCategory Load (0.4ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`name` = 'hoge1ddd' LIMIT 1 ↳ app/controllers/api/v1/ideas_controller.rb:13:in `index' Rendering api/v1/ideas/index.json.jbuilder Idea Load (0.5ms) SELECT `ideas`.* FROM `ideas` ↳ app/views/api/v1/ideas/index.json.jbuilder:2 Category Load (0.4ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` IN (1, 2, 3, 4, 5, 6, 7) ↳ app/views/api/v1/ideas/index.json.jbuilder:2includesの場合
app/controllers/ideas_controller.rb# def index # category = Category.find_by(name: params[:category_name]) # if category.present? # @ideas = category.ideas # render formats: :json # else @ideas = Idea.includes(:category) # もとはIdea.all # render formats: :json # end # endターミナルCategory Load (0.3ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`name` = 'hoge1ddd' LIMIT 1 ↳ app/controllers/api/v1/ideas_controller.rb:13:in `index' Rendering api/v1/ideas/index.json.jbuilder Idea Load (0.4ms) SELECT `ideas`.* FROM `ideas` ↳ app/views/api/v1/ideas/index.json.jbuilder:2 Category Load (0.2ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` IN (1, 2, 3, 4, 5, 6, 7) ↳ app/views/api/v1/ideas/index.json.jbuilder:2おまけ
Ideaモデルに複数の関連付けがある場合は下記のように書くことができます。
app/controllers/ideas_controller.rb# def index # category = Category.find_by(name: params[:category_name]) # if category.present? # @ideas = category.ideas # render formats: :json # else @ideas = Idea.eager_load(:category, :hoge, :huga) # render formats: :json # end # endgem "bullet"の導入方法
N+1問題を検出してくれるgemです。
通常はターミナルに出ますが、jquery等でカスタムもできます。
今回それは割愛Gemfilegem "bullet"bundleだけでも可能
ターミナル$ bundle installyでconfig/environments/development.rbを自動作成
ターミナル$ bundle exec rails g bullet:install Would you like to enable bullet in test environment? (y/n)N+1問題が発生するとターミナルに下記のようにでます。(一部省略)
IdeasテーブルにCategoriesテーブルをincludesしてねということターミナルuser: shu GET /api/v1/ideas?category_name= USE eager loading detected Idea => [:category] Add to your query: .includes([:category])以上。
間違っている等ありましたらご指摘頂けると幸いです。
最後に
N+1問題の解決方法自体はそんなに難しいコードを書くわけではないですがSQLを読んで
なにが起こっているのかしっかり理解することが大切だと思います。
(解決できたらいいやーでは逆に遠回りになることを身を持って感じております。)
- 投稿日:2021-02-20T01:16:51+09:00
【Rails】 フラッシュメッセージ使い分け
はじめに
お恥ずかしながら、私は最近までフラッシュメッセージってflash[:notice] = ⚪︎⚪︎と書いておけばいいんだろうくらいの認識しかありませんでした。ポートフォリオ作成時にフラッシュメッセージの使い分けの方法があることを知り、少し理解を深めることができたので、自身の備忘録として残しておきたいと思います。
フラッシュメッセージって何?
何かの処理を行った後に画面に表示されるメッセージのことを指します。
例) ● ログイン時
「ログインに成功しました」
● 記事の投稿時
「記事の投稿に成功しました」
見本
フラッシュメッセージの種類
● flash
次のリクエストまで表示させることができる。
= redirect_toの際に使用する。
※render時に使用すると次のリクエスト時までメッセージが画面に表示され続けてしまうので、不適切になります。● flash.now
現在のリクエストまでしか表示できない。
= renderの際に使用する。
● notice
通知を出す時。主に成功した時のメッセージなど。
● alert
警告の通知を出す時。何かの動作に失敗時など。
コントローラー
今回は、投稿した際の保存成功時と失敗時にメッセージが表示されるようにしています。
books_contoroller.rbdef create @book = Book.new(book_params) @book.user_id = current_user.id if @book.save redirect_to books_path, notice: = "投稿に成功しました" else flash.now[:alert] = "投稿に失敗しました" render :new end end # 2行に分けて記述することも可能 # redirect_to books_path # flash[:notice] = "投稿に成功しました"ビュー
viewにもフラッシュメッセージが表示されるように記述を加えます。
※フラッシュメッセージを表示させるタイミングは何度もあるかと思いますので、部分テンプレートに書き出し、呼び出す形にしています。books/index.html.erb<%= render 'layout/flash' %> <% @books.each do |book| %> <%= book.user.name %> <%= book.title %> <%= book.content %> <% end %>layout/_flash.html.erb<% if notice %> <%= notice %> <% elsif alert %> <%= alert %> <% end %>終わり
今回は以上になります。
私自身もプログラミング初心者ですが、同じ様な立場の方に少しでも参考になれば幸いです。
また、もし内容に誤りなどがございましたら、ご指摘いただけますと幸いです。
- 投稿日:2021-02-20T01:00:40+09:00
[Ruby on Rails] CSSが反応してくれない時の対処法
自身の備忘録を書いて行きます。
CSSを書いても全く反応してくれないことがありました。
なんでや?と思い調べて行くと、ちゃんと動いてくれるようになりました。それの解決策を書いて行きます。
解決策
layouts/application.html.erb<%= stylesheet_link_tag 'application', media: 'all'%>上記の記述をすることでCSSを読みこむようになりました。
こちらはCSSの類を全て読みこんでくれる記述らしいです。
その他に
ユーザー管理機能(devise使用の場合)の
ログイン等の配置を動かす場合はconfig/initializers/devise.rbconfig.scoped_views = true上記の記述は元々、247行目でコメントアウトになっている
config.scoped_views = false
こういった記述になっている。それをコメントアウトを外してtrueにすればいいらしい。
実際、両方やってたら問題なく動いているので、
今の所は大丈夫そう。
- 投稿日:2021-02-20T00:32:20+09:00
Rails ERDのススメ
About Rails ERD?
Railsのテーブル情報を自動生成するためのgem
https://github.com/voormedia/rails-erd
ER図をpdfで出力することができる。Getting started ?
for mac
brew intall graphviz
gemfilegem install ‘rails-erd’, group: :development
- 設定でmigrationの度に自動生成することも可能
Pros and cons
?
クライアント・新入メンバーへの説明するのに便利
?
関連にもよるがテーブル数が50超えてくるとごちゃごちゃしてすごく見づらい
内部の開発に関しては、モデル数20以下の場合annotateで十分
ある程度の規模のサービスの場合、LucidChartやdraw.ioで作図するするのがオススメ
- 投稿日:2021-02-20T00:26:27+09:00
Docker,CircleCI,AWS,Railsでポートフォリオを作成
前書き
就職活動用のポートフォリオをDocker,CircleCI,AWS(ECS)を用いてWebアプリケーションを作成しました。
バックエンドにRuby on Railsを用いました。
今回は作成したポートフォリオの機能、参考記事などを紹介したいと思います。概要と作成背景
今回作成したアプリはスイーツのデリバリーに特化したECサイトです。
- ケーキ屋のアルバイト経験からお店の業務改善をしたい
- 手軽にお店のスイーツを食べたい
- 店舗で販売しているようなスイーツを配達するサービスが存在しない(自分調べ)
上記の理由により飲食店にもユーザーにもメリットのあるサービスを作成しようと思いました。
アプリのURL: http://sweetsdeli.com
GitHubのURL: https://github.com/sekine617/sweetsdeli
画面イメージ紹介
トップページ
新着商品、人気商品などを表示
人気商品はユーザーの購入履歴から購入数が多い商品を表示しています。
商品一覧ページ
商品詳細ページ
こちらでは商品をカートに入れる、お気に入り登録、商品のレビュー投稿などができます。
マイページ
マイページではプロフィール編集、お気に入り、購入履歴、投稿したレビューを閲覧できます。
ショッピングカート
こちらではカートに入れた商品の確認、個数の変更、カートから削除などができます。
購入画面
カートに入れた商品から合計金額を確認し、クレジットカードによる決済が可能です。実際に決済する場合はpay.jpのてすとカードを使用してください。
このようにカード情報の入力フォームがモーダルウィンドウで出てきます。
使用言語
- フロントエンド
- jQuery
- HTML
- CSS/Sass
- Bootstrap
- バックエンド
- Ruby on Rails
- Ruby
- PAY.JP(外部API)
- インフラ
- Docker/docker-compose
- CircleCI
- nginx
- mysql
- AWS(ECS, ALB, S3, RDS, Route53, ECR, VPC, IAM)
インフラ構成図
開発環境
機能一覧
- ユーザー関連(devise)
- 登録機能
- プロフィール編集機能
- ログイン・ログアウト機能
- 決済機能(PAY.JP API)
- 人気商品表示機能
- タグ機能
- 商品登録機能
- 画像アップロード機能(AWS S3バケット, carrierwave)
- お気に入り機能(非同期処理, jQuery)
- フラッシュメッセージ表示機能
- レビュー投稿機能
- カート関連
- カート登録機能
- カート編集機能
- 住所自動入力機能(jQuery)
- 商品名検索機能
- カテゴリー検索機能
- ページネーション機能(kaminari)
データベース設計
テーブル説明
テーブル名 説明 users ユーザー情報 orders 注文管理(受け取り日時など) orders_products 注文商品管理 products 商品情報 reviews 商品に対するレビューを管理 likes 商品へのお気に入り情報 address ユーザーの住所 cart_items cartsとproductsの中間テーブル shops ショップ情報 carts カート追加した商品情報一時的に保存 product_tag_relations productsとtagsの中間テーブル tags 商品のカテゴリ情報 ポイントはproductsテーブルのquantity_per_dayで、1日の提供数を指定し注文数が1日の提供数を上回らないようにしました。
また注文時に受け取り日時を指定し、各店舗ごと、日にちごとに管理が可能です。苦労した点
CircleCIでAWSへの自動デプロイ
CircleCIを用いて開発環境のDockerイメージをECRにpushし、ECSのタスク定義を更新してデプロイをしましたが、config.ymlの設定でのエラーに悩まされました。
またAWSの各設定にもかなり悩まされ、インフラの知識がないことで時間が結構かかりました。credentials.ymlでのpay.jpなどのアクセスキー管理でなかなかうまく行かずインデントの重要性がよくわかりました。
参考記事
Railsでのテストを参考にしました。
【Rails】はじめてのRSpec!テストコードを書こう!deviseのログイン機能を参考にしました
【Rails】ログイン機能を実装する
- 投稿日:2021-02-20T00:04:23+09:00
git push -u origin mainでpushされずerrorになる
rails tutorialのversion 6.0の1章でgitの扱い方を学びながら進めていたがgit push -u origin mainをしたら下記のようなエラーに遭遇した
terminal
error: src refspec main does not match any error: failed to push some refs to '自分のgithubアカウント'原因
2020/10月からgithubはレポジトリ名をmasterからmainに変更したためmainでpushしてもレポジトリ名が違うためerrorになるとのこと
次のようにgit branchで調べるとその通りだった
% git branch * masterので次のようにブランチを変えて解決
% git branch -M main % git branch * mainまだまだ初学者なのだと実感させられる
参考になったURL