- 投稿日:2021-08-06T23:30:15+09:00
Rails 投稿詳細ページ
showメソッドを使った投稿詳細ページ ここでは詳細ページのshowメソッドだけではなく編集と削除機能も追加 officies_controller.rb def show @office = Office.find_by(id: params[:id]) render json: { 'office': @office } end def edit @office = Office.find_by(id: params[:id]) end def destroy @office = Office.find_by(id: params[:id]) @office.destroy render json: {'office': @office} end ルーティングはresourcesをofficiesにする。 routes.rb Rails.application.routes.draw do namespace :api do namespace :v1 do mount_devise_token_auth_for 'User', at: 'user_auth', controllers: { registrations: 'api/v1/registrations' # コントローラーの参照先を設定 } mount_devise_token_auth_for 'Admin', at: 'admin_auth', controllers: { registrations: 'api/v1/registrations' # コントローラーの参照先を設定 } get 'cities', to:'cities#get' get ':prefecture_id/cities', to:'cities#get' get ':area_id/:prefecture_id/cities', to:'cities#get' resources :offices resources :bookmarks, only: [:create, :destroy, :index] end end end
- 投稿日:2021-08-06T19:21:04+09:00
HerokuでWe're sorry, but something went wrong.とエラー出た場合の対処法
はじめに Herokuに追加機能を実装した後、サイトを開くと下記のエラー表示が出たので その時の対処法を記録します。 これだけでは何のエラーが出ているのか分からないので、原因を探るためにエラーログを確認します。 エラーログの確認 まずはアプリケーションの内容を確認するために ターミナルで以下のコマンド入力 $ heroku apps:info === sample-123456 Addons: cleardb:ignite Auto Cert Mgmt: false Dynos: web: 1 Git URL: https://git.heroku.com/sample-123456.git Owner: sample@sample.com Region: us Repo Size: 165 KB Slug Size: 56 MB Stack: heroku-18 Web URL: https://sample-123456.herokuapp.com/ sample-123456の部分がアプリケーション名です。 次に、下記のコマンドを入力してログを表示しましょう。 ターミナル $ heroku logs --tail --app <<アプリケーション名>> 今回はアプリケーション名がsample-123456なので $ heroku logs --tail --app sample-123456 とコマンドを入力します。 すると以下のようにログが表示されます。 2021-08-06T08:43:35.997532+00:00 app[web.1]: F, [2021-08-06T08:43:35.997422 #4] FATAL -- : [3b521c23-ff54-428d-963b-97b02366765e] 2021-08-06T08:43:35.997554+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] ActionView::Template::Error (Mysql2::Error: Table 'heroku_3c9be7b4803e9b6.likes' doesn't exist): 2021-08-06T08:43:35.997555+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] 52: 2021-08-06T08:43:35.997555+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] 53: <%# いいね機能 %> 2021-08-06T08:43:35.997556+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] 54: <div class="likes"> 2021-08-06T08:43:35.997556+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] 55: <% if current_user.liked_by? (problem.id) %> 2021-08-06T08:43:35.997557+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] 56: <p><%= link_to 'いいねを外す', destroy_like_path(problem), method: :DELETE %><%= problem.likes.count %></p> 2021-08-06T08:43:35.997558+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] 57: <% else %> 2021-08-06T08:43:35.997558+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] 58: <p><%= link_to 'いいね', create_like_path(problem), method: :POST %><%= problem.likes.count %></p> 2021-08-06T08:43:35.997559+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] 2021-08-06T08:43:35.997559+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] app/models/user.rb:15:in `liked_by?' 2021-08-06T08:43:35.997559+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] app/views/problems/index.html.erb:55 2021-08-06T08:43:35.997560+00:00 app[web.1]: [3b521c23-ff54-428d-963b- 97b02366765e] app/views/problems/index.html.erb:45 2021-08-06T08:43:36.001198+00:00 heroku[router]: at=info method=GET path="/" host=bouldering-395.herokuapp.com request_id=3b521c23-ff54-428d-963b- 97b02366765e fwd="180.147.68.165" dyno=web.1 connect=1ms service=710ms status=500 bytes=1827 protocol=https ログの4行目を見るとActionView::Template::Error (Mysql2::Error: Table 'heroku_3c9be7b4803e9b6.likes' doesn't exist):とあります。 要約すると「likesテーブルが存在していません」という意味です。 テーブルはマイグレーションファイルを実行することで作成されます。 ローカル環境では正常に動いていて、本番環境(Heroku)の方でみマイグレーションの実行ができていないという可能性が高そうです。 Herokuでマイグレーションファイルの実行をしましょう。 ターミナル $ heroku run rails db:migrate リロードすると正常に動きました。 まとめ 今回は追加でテーブルを作成したのにHeroku上でマイグレーションの実行をしていないためにエラーが出ていました。 エラーが出た場合 1. エラーログの出力 2. 最新のログ確認 3. ログを元に仮設検証していきましょう
- 投稿日:2021-08-06T18:56:00+09:00
PV数実装時のsession_hashでのエラー【impressionist】【Ruby on Rails】
{TypeError の改善方法} はじめに impressionist gemを使用して、PV数の表示を実装しました。 その際に、エラーにぶつかったため共有します。 エラー内容 ここのuniqueにて、session_hashを値として、閲覧数をカウントすると規定しました。 ですが、サーバーを立ち上げてると、typeErrorが出現しました。 原因 調べてみると、session_hashは、string型のため、そのまま使用しようとするとエラーが出るみたいです。 改善方法 なので、session_hash.to_sとして、変換すれば改善します 。
- 投稿日:2021-08-06T18:51:33+09:00
MultiParameterAssignmentErrorsは複数の属性でエラーが発生した際に出力される
API dockや公式Githubに書いてあることを訳すとまんまタイトルになる いやもう全くもって(ハァ・・・)おっしゃる通りです・・・!!!(わーわー Rails6.1.4にて検証 経緯 対象となるModelは以下の通り class TestModel < ActiveRecord::Base validates_datetime :column_datetime validates_date :column_date end RSpecのエラー調査をしている時にこんなソースを見た it "short params is nil" do expect(TestModel.new("column_date(1i)" => "2021", "column_date(2i)" => "13").\ to raise_error(ActiveRecord::MultiParameterAssignmentErrors) end テスト名でnilとして返ってくることを想定しているのに例外処理書いているのはさておき、 このMultiParameterAssignmentErrorsを当方見たことがなかったのでどういった時に出されるのかを調べてみた 調査 困ったときのAPI dock Raised when there are multiple errors while doing a mass assignment through the {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method. The exception has an errors property that contains an array of AttributeAssignmentError objects, each corresponding to the error while assigning to an attribute. 要するにattributes=による属性更新中に複数のエラーが発生した場合にこのエラーが出力されるとのこと そのような状況は今までに何度も遭遇したのに見たことがないのはなぜ...? 実際に下記のような操作を行ってみたが確認できず create_table(:users) do |t| t.string :name t.integer :age end User.new(name: 19, age: "name") # => User(name: "19", age: 0) 以前、attributesは自動的にタイプキャストする仕様だと特定したことをすっかり忘れていた このエラーが記載してあった箇所はDate等の時刻系であったことを思い出し、再度試してみる TestModel.new("column_date(1i)" => "9999", "column_date(2i)" => "9999" # => nil どうも上手くいかない 行き詰ったため公式Githubのソースを読んでいたところ、このような記述を発見 rails/activerecord/lib/active_record/attribute_assignment.rb def execute_callstack_for_multiparameter_attributes(callstack) errors = [] callstack.each do |name, values_with_empty_parameters| if values_with_empty_parameters.each_value.all?(NilClass) values = nil else values = values_with_empty_parameters end send("#{name}=", values) rescue => ex errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name) end unless errors.empty? error_descriptions = errors.map(&:message).join(",") raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]" end end これで調べてみるとかなり類似する内容の記事を発見 assign_attributesでタイプキャストされた後にvalues_with_empty_parameters.each_value.all?(NilClass)でnilか否かを判別する、このタイミングでエラーを発生させないとMultiParameterAssignmentErrorsは出力されなさそう つまり? タイプキャスト後にnilにならず例外的な処理になるような値を登録する必要があるらしい そう考えると時刻系でよく発生するエラーであることが良くわかる ※見やすいように改行しています TestModel.new("column_date(1i)" => "9999", "column_datetime(1i)" => "9999" # => ActiveRecord::MultiparameterAssignmentErrors: 1 error(s) # on assignment of multiparameter attributes [error on # assignment [0] to column_datetime (Provided hash {1=>0} # doesn't contain neccessary keys: [2, 3])] やっと確認できた
- 投稿日:2021-08-06T17:15:09+09:00
ransackで複数モデルの検索フォームを一つのページに実装する
Railsアプリケーションにransackを導入し,検索機能を実装しました。 今回は一つのページにUserモデルとPostモデルそれぞれの検索フォームがある場合の実装例をご紹介します。 実行環境 macOS 10.15.7 (19H1217) Ruby 2.6.7 Rails 6.0.3.7 ransack 2.4.2 コントローラ側 コントローラ側のポイントはsearch_keyです。 これにより,モデル別に(検索に使用するparamsの)キーを指定することができます。 app/controllers/hoge_controller.rb ... @users_q = User.ransack(params[:users_q], search_key: :users_q) ... ... @posts_q = Post.ransack(params[:posts_q], search_key: :posts_q) ... ビュー側 ビュー側のポイントはasです。 これにより,検索フォームに入力された内容を,params内でモデル別に分けて格納することができます。 app/views/hoge.html.erb ... <%= search_form_for @users_q, as: :users_q do |f| %> ... <% end %> ... ... <%= search_form_for @posts_q, as: :posts_q do |f| %> ... <% end %> ... 参考文献
- 投稿日:2021-08-06T15:44:58+09:00
ややこしい、難しいN+1問題を解決する
今回はincludesとかを使ってN+1問題を解決していきたいです。 さっさと解決しようかと思ったのですが、一筋縄じゃいかなかったので、今から頑張って解決しようと思います! https://qiita.com/hirotakasasaki/items/e0be0b3fd7b0eb350327 またこの方の記事を全面的に参考にして(パクって)記事を書いていこうと思います。 あとタイトルがクソすぎるので、いいタイトルあったら編集リクエスト待ってます。 今回のモデルのアソシエーション drinkがいわゆる投稿です。 userはいろんな投稿をするので、 userとdrinkで1対多の関係 これだけだったら単純なのですが、 それらに加えて、imageがあります。 投稿画像とユーザー画像がそれぞれある感じ。 bulletが検知したN+1 user: root USE eager loading detected Drink => [:image_attachment] Add to your query: .includes([:image_attachment]) DrinkモデルがN+1問題を引き起こしてるっぽい。 解決していこう drinks_controller @pagy,@drinks = pagy(Drink.includes(image_attachment: :blob) .where.not(user_id: 6) .where("user_id IN (#{following_ids}) OR user_id = :user_id", user_id: @user.id) .order('drinks.created_at DESC')) んーややこしい。。。。 色々調べてみるとこーゆー感じで書き直したらいいんじゃないかと思った。 drinks_controller @pagy,@drinks = pagy(Drink.includes(user: {image_attachment: :blob}) .where.not(user_id: 6) .where("user_id IN (#{following_ids}) OR user_id = :user_id", user_id: @user.id) .order('drinks.created_at DESC')) したら今度は、 user: root USE eager loading detected Drink => [:image_attachment] Add to your query: .includes([:image_attachment]) とbulletに検知された。 userの方は解決できたっぽいけど、、、。 今度はimageの方でN+1が発生してる。。。。 この書き方でどうだ!!!(無策) @pagy,@drinks = pagy(Drink.includes(:user ,{image_attachment: :blob}) .where.not(user_id: 6) .where("user_id IN (#{following_ids}) OR user_id = :user_id", user_id: @user.id) .order('drinks.created_at DESC')) 解決できた。 ログを実際に見てみる Processing by DrinksController#index as HTML web_1 | User Load (0.6ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 7 LIMIT 1 web_1 | ↳ app/helpers/sessions_helper.rb:52:in `current_user' web_1 | (0.8ms) 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 | Rendering layout layouts/application.html.erb web_1 | Rendering drinks/index.html.erb within layouts/application web_1 | Drink Load (1.1ms) SELECT `drinks`.* FROM `drinks` WHERE `drinks`.`user_id` != 6 AND (user_id IN (SELECT followed_id FROM relationships WHERE follower_id = 7) OR user_id = 7) ORDER BY drinks.created_at DESC LIMIT 2 OFFSET 0 web_1 | ↳ app/views/drinks/_drinks_index.html.erb:12 web_1 | User Load (0.6ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 7 web_1 | ↳ app/views/drinks/_drinks_index.html.erb:12 web_1 | ActiveStorage::Attachment Load (0.7ms) SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_type` = 'Drink' AND `active_storage_attachments`.`name` = 'image' AND `active_storage_attachments`.`record_id` IN (8, 7) web_1 | ↳ app/views/drinks/_drinks_index.html.erb:12 web_1 | ActiveStorage::Blob Load (0.8ms) SELECT `active_storage_blobs`.* FROM `active_storage_blobs` WHERE `active_storage_blobs`.`id` IN (12, 13) web_1 | ↳ app/views/drinks/_drinks_index.html.erb:12 web_1 | ActiveStorage::Attachment Load (0.6ms) SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 7 AND `active_storage_attachments`.`record_type` = 'User' AND `active_storage_attachments`.`name` = 'image' LIMIT 1 web_1 | ↳ app/views/drinks/_drinks_index.html.erb:18 web_1 | Like Load (0.7ms) SELECT `likes`.* FROM `likes` WHERE `likes`.`user_id` = 7 AND `likes`.`drink_id` = 8 LIMIT 1 web_1 | ↳ app/views/likes/_like.html.erb:2 web_1 | (0.6ms) SELECT COUNT(*) FROM `likes` WHERE `likes`.`drink_id` = 8 web_1 | ↳ app/views/likes/_like.html.erb:6 web_1 | Rendered likes/_like.html.erb (Duration: 9.1ms | Allocations: 1639) web_1 | Like Load (0.7ms) SELECT `likes`.* FROM `likes` WHERE `likes`.`user_id` = 7 AND `likes`.`drink_id` = 7 LIMIT 1 web_1 | ↳ app/views/likes/_like.html.erb:2 web_1 | (0.7ms) SELECT COUNT(*) FROM `likes` WHERE `likes`.`drink_id` = 7 web_1 | ↳ app/views/likes/_like.html.erb:6 web_1 | Rendered likes/_like.html.erb (Duration: 10.2ms | Allocations: 1558) web_1 | Rendered drinks/_drinks_index.html.erb (Duration: 56.6ms | Allocations: 12908) web_1 | Rendered drinks/index.html.erb within layouts/application (Duration: 57.9ms | Allocations: 12979) web_1 | [Webpacker] Everything's up-to-date. Nothing to do なぜこの書き方で上手くいったのかの僕の予想 @drinks = pagy(Drink.includes(:user ,{image_attachment: :blob}) って書き方は、 drinkとアソシエーション組んでるuserとimageをどっちもincludesメソッドの引数に指定したから上手くいったのでしょう。 一方失敗した下のような書き方は @drinks = pagy(Drink.includes(user: {image_attachment: :blob}) userモデルとアソシエーションを組んでるimegeをN+1問題を起こさないようにしてーー。 って意味のコードになってしまったのでしょう。。。。きっと。。。 https://qiita.com/makitokezuka/items/f13b2e7bad77b5594911
- 投稿日:2021-08-06T14:35:30+09:00
Docker-compose 関連でつまづいたときに参考になった記事[M1 Mac]
M1 Mac関連の問題 Dockerコンテナでyarnをインストールする Docker に yarn を入れるための yarnpkg で no valud opengpg data found になった時の対処法 M1 MacでHeroku containerにデプロイしたら Exec format error と出て困った話 M1 MacでHerokuにデプロイする手順 docker-compose build Dockerでコンテナ内にbundle installされない問題の解決法
- 投稿日:2021-08-06T14:24:28+09:00
パス間違いはないが、Railsで写真が表示されない原因
パス間違いはないが、Railsで写真が表示されない。 自分のポートフォリオを作っているときに発生した問題なのですが、パスはあっているのに写真が表示されず30分くらい手が止まってしまったので、ここで今回の解決策を共有させていただきます。 結論:ファイル名にカタカナを用いてはいけない。 例えば、マネー.jpgとかレベルアップ.pngなど。 写真の種類をわかりやすくするため自分でファイル名を変更することがあると思うのですが、まさかカタカナがダメだとは思いませんでした。なかなかの盲点だったのでみなさんも注意してみてください!
- 投稿日:2021-08-06T09:20:24+09:00
docker-compose upした際のログが出ない問題
今回の問題 今回はただ今Docker初心者の私がとても悩んだ問題です。 正直、メンターさんと一緒に考えてもなかなか答えが見えなかった問題でした。 調べても調べてもなかなか出てこなくてものすごく大変でした。 やっと解決したので、今後のためにも残しておこうと思います。 使用環境 ・Ruby(2.5.7) ・Ruby on Rails (6.1.3.2) ・Docker (20.10.7) ・MySQL (5.7) 問題点 上のスクリーンショットを見ていただくと、本来スクリーンショット最下部「Use Ctrl-C to stop」以下にRailsのログ情報が本来出力されるはずなのですが、Railsを起動して画面読み込みをしても何もログが出力されていません。(動作自体は正常にしています。) ターミナル $ docker-compose up -d $ docker attach onsen_app_1 で起動したコンテナに接続してもRailsのログは出力されませんでした。 Docker化する以前は問題なくRailsログがターミナルに出力されていたので、Docker化した際の設定に原因があるかと思いましたが、調査してもどこが引っかかっているのかわかりませんでした。 解決方法 結論を先に言うと、今回の原因は「config/environments/development.rb」にある記述を追加すれば正常に動くことができました。 development.rb Rails.application.configure do # ... config.logger = Logger.new(STDOUT) # ... end 上記に書いた「config.logger = Logger.new(STDOUT)」と言うのを「config/environments/development.rb」に追加すれば、正常に動くようになりました。 ちなみに「rails STDOUT not working docker」で検索したらようやくヒットしました。 最後に Dockerはまだまだ初心者ゆえに大変な作業でした。 これからもDockerにはお世話になると思うので、勉強は怠らずに励んでいきたいですね。 変なまとまりになりましたが、以上で終了です。 見て頂きありがとうございました。 参考サイトです。 https://blog.eq8.eu/til/ruby-logs-and-puts-not-shown-in-docker-container-logs.html
- 投稿日:2021-08-06T08:27:49+09:00
【Ruby on Rails】kaminariを使用してページング機能を実装する方法
対象者 一覧ページにページング機能を作りたい方 目的 kaminariをインストールしてページング機能を作成すること 実際の手順と実例 1.Gemを導入 Gemfileの最終行に以下のgemを導入 : : gem 'kaminari','~> 1.2.1' その後bundle installを実行する 2.kaminariの設定ファイルを作成 以下のコマンドを実行する $ rails g kaminari:config 最後にkaminariがページャで利用するテンプレートを作成します。 $ rails g kaminari:views default 3.ViewとControllerへ追加する 本の投稿を行うサイトを例にあげます。 書き方は下記の通りです。 books/index.html.erb <% @books.each do |book| %> : : <% end %> <%= paginate @books %> 続いてControllerの記述を変更します。 変更前 books_controller.rb def index @books = Book.all end 変更後 books_controller.rb def index @books = Book.page(params[:page]).reverse_order end これで実装完了です! ちなみに私としては下記の記述の方好みです。 books_controller.rb def index @books = Book.page(params[:page]).per(5) end 最後のper(数字)だと表示したいページ数を設定できて便利です! 参照 Kaminariの使い方 まとめ - 猫Rails 投稿者コメント 最後の行書きたいがために記事にしました笑 参照させて頂いた記事がとてもわかり易いです。 My Profile プログラミング学習歴3ヶ月目のアカウントです! プログラミングスクールで学んだ内容や自分が躓いた箇所等のアウトプットの為に発信しています。 また、プログラミング初学者の方にわかりやすく、簡潔にまとめて情報共有できればと考えています。 もし、投稿した記事の中に誤り等ございましたら、コメント欄でご教授いただけると幸いです。
- 投稿日:2021-08-06T02:33:37+09:00
【Rails】URL直打ち対策
忘備録として残します。 URL直打ちとは、アドレスバーにURLを直接打ち込むことです。 直打ちを禁止しないと、だれでもプロフィールや投稿内容を編集できてしまうので対策しておきましょう。 posts_controller.rb 直打ちをさせたくないコントローラーを開き、before_actionで、特定のアクションの直打ちを制限します。 app/controllers/posts_controller.rb class PostsController < ApplicationController before_action :authenticate_user! before_action :correct_post,only: [:show, :edit] #追記 def show @post = Post.find(params[:id]) end def edit @post = Post.find(params[:id]) end private # ここから追記 def correct_post @post = Post.find(params[:id]) unless @post.user.id == current_user.id redirect_to root_path #直打ちした時リダイレクトするパスを指定 end end # ここまで end
- 投稿日:2021-08-06T01:50:58+09:00
【Rails】toastrでフラッシュメッセージを表示
ポートフォリオを作成中、手軽にフラッシュメッセージをおしゃれにしたくて 何か便利なGemないかなと探していたらtoastrというものがあったので、導入しました。 jQuery導入が前提です。 Gemの追加 まず、Gemをインストール Gemfile gem 'toastr' bundle install toastrをJavaScriptとSassに読み込ませます。 assets/javascripts/application.js // This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's // vendor/assets/javascripts directory can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. JavaScript code in this file should be added after the last require_* statement. // // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // //= require rails-ujs //= require activestorage //= require turbolinks //= require jquery //= require jquery3 //= require jquery_ujs //= require popper //= require bootstrap //= require data-confirm-modal //= require toastr #追加 //= require_tree . app/assets/stylesheets/application.scss @import "toastr"; #追加 実装 application.html.erbに記述します。 app/views/layouts/application.html.erb <% if flash.any? %> <script type="text/javascript"> <% flash.each do |key, value| %> <% key = "success" if key == "notice" %> <% key = "error" if key == "alert" %> toastr['<%= key %>']('<%= value %>'); <% end %> </script> <% end %> 私はDeviseを使用しているので、フラッシュメッセージのシンボルは:noticeと:alertです。 ですが、toastrのメソッドはsuccessとerrorなので、noticeをsuccessに、alertをerrorに変換してあげましょう。 toastrは他にもwarningやinfoのメソッドがあります。 メソッドによって色が変わるので可愛いです! こんな感じで表示されました!