20220225のRailsに関する記事は14件です。

【Rails】クラスメソッドとインスタンスメソッドの使い分け

はじめに  本記事は、プログラミング初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。  そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。  間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。 クラスメソッドとインスタンスメソッドの使い分け クラスメソッドとインスタンスメソッドの違い クラスメソッドとインスタンスメソッドの違いは メソッドの記述方法 メソッドの呼び出し方法 です。 メソッドの記述方法 クラスメソッドの場合には以下のようにメソッド名の頭にselfを記述します。 def self.exists_no_name_user? no_name_user_list = User.where(name: nil) no_name_user_list.exits? end インスタンスメソッドの場合には以下のようにselfのない形になります。 def full_name self.first_name + self.last_name end メソッドの呼び出し方法 クラスメソッドはクラス名.クラスメソッドのように記述し、クラスに対してメソッドを呼び出します。 User.self.exists_no_name_user? インスタンスメソッドはインスタンス名.インスタンスメソッドのようにインスタンスに対し、メソッドを呼び出します。 kato = User.new(name: 'kato') kato.full_name クラスメソッドとインスタンスメソッドの使い分け クラスメソッドの特定のインスタンスに対して実行したいメソッドはインスタンスメソッドで定義し、クラス全体に対して何等かの処理を行いたい場合に使用します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActiveJob でジョブのメモリ使用量がしきい値を超えた場合に通知する

やりたいこと ActiveJob でジョブのメモリ使用量がしきい値以上だった場合に通知したい。 僕の具体的なユースケース: Sidekiq で大量にメモリを使用して、かつ解放されない場合が結構ある。そこで、具体的にどのジョブが関係しているのかを調べたい。 方法 around_perform メソッドを使う。 今回は Rollbar というエラーモニタリングサービスで警告を通知する。 Rollbar.warning の部分は、環境に応じて任意の通知方法に置き換えること。 app/jobs/application_job.rb class ApplicationJob < ActiveJob::Base around_perform do |job, block| MonitorMemoryUsage.call(job, &block) end end app/jobs/monitor_memory_usage.rb module MonitorMemoryUsage extend ActionView::Helpers::NumberHelper class HighMemoryUsage < StandardError; end THRESHOLD = 100.megabytes def self.call(job) before_memsize = ObjectSpace.memsize_of_all results = yield after_memsize = ObjectSpace.memsize_of_all usage = after_memsize - before_memsize if usage > THRESHOLD message = "#{job.class.name} が #{number_to_human_size(usage, locale: :en)} のメモリを消費しました。" Rollbar.warning(HighMemoryUsage.new(message), arguments: job.arguments) end results end end こんな感じ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSのS3で画像が保存できない

簡易的なフリマアプリを作成中。 AWSのS3に画像を保存するための実装を実施。 必要なファイルや記述なども終え、まずローカル環境で画像がS3に保存できるかの挙動確認を行う。 が、エラー発生。 エラー文は以下の通り。 NoMethodError (undefined method `upload' for nil:NilClass): 「スペルミスでもしたかな?」 まずは今回新たに追記したconfig/environments/developmentとconfig/storage.ymlのファイルを見直す。 しかし特に間違っている様子はない。 次にエラー内容をgoogleにて検索。 すると、同じ境遇の方々がたくさんいらっしゃいました笑 それぞれの記事を見ていると「:が抜けている」や「""を忘れている」などの内容が多かったので、再度その辺りを確認するため、各コードを見直し。 が、やはり間違いが見当たらない・・・ S3に入る直前に挙動確認を行った際は、問題なく画像が保存されていたので、コードの書き間違いは考えにくい。 間違いがあるのはconfigの箇所であることはほぼ確定している。 でもどこが間違っているのかが全くわからない・・・ するととある記事を発見。そこには「余計なスペースが入っていた」と書かれている。 「スペース?そういえばそこは意識してなかったかも」 再度コードとにらめっこ開始。 すると・・・ 発見!!! config/storage.yml local: service: Disk root: <%= Rails.root.join("storage") %> amazon: service: S3 region: ap-northeast-1 bucket: バケット名 access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %> secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %> amazon:の前に半角スペースが! 調べてみると、半角スペースがあるせいで、上記のlocal:の続きと見なされてしまうのだとか。 早速この余計なスペースを削除して、再度挙動確認! が、まだ保存できない・・・ さらに1時間考えた末、出した結論は PC再起動 すると無事にエラー解決できました笑
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【RSpec】テストコードはループを使わない方がベター

なぜループ処理を使わない方がいいのか テストコードは仕様がひと目でわかることが大事なため、可読性が下がるループはしない方がベター describe '#format_date_of_birth' do it '生年月日を和暦で表示すること' do %w(1977-06-06 1988-06-06 1989-06-06 2016-06-06).each do |date_text| date = Date.parse(date_text) person = Person.new('Taro', date) jp_year = date.year >= 1989 ? "平成#{date.year - 1988}年" : "昭和#{date.year - 1925}年" expected = "#{jp_year}#{date.month}月#{date.day}日" expect(person.format_date_of_birth).to eq expected end end end ただ、テストデータを作成するときだけはループ処理で書いてしまった方が見やすい気がする。 「テストはループ処理を使わない方がいい」という言葉だけだとデータ作成までベタ書きするのかなと勘違いしそうになったので。 (Date.new(2021, 1, 1)..Date.new(2021, 1, 15)).each do |date| create(:post, date: date, user: user) end さいごに 記事の中で伊藤さんがおっしゃっていた言葉が印象的だった。 何事も機械的に適用しない。目的を考えて最適な選択肢を選ぶ コードの書き方に絶対はなく、一個人がより良いと思う方を自分で考えて自分なりの信念を持って選択していくことが大事だと思う。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSのEC2の環境構築で参考にしたサイト(rails,docker,nginx)

以下のインフラ環境を構築するまでに参考にしたサイトをご紹介します。 1,AWSの全体的な知識を付けるために参考にしたもの <動画教材> WEBエンジニアの山浦さんのUdemyの動画教材です。 解説が初心者に優しく、わかりやすいのでおすすめです。 <書籍> 解説がわかりやすいです。 イラスト使って説明してくれるので、なにをやっているのかイメージしやすく、すぐに読み終えることができました。 補足: ご紹介した2点は内容が共通している部分が多いです。 山浦さんの動画教材の方が、内容が濃いので、そちら1点だけでも良いかもしれません。 2,VPC作成からEC2にデプロイするまで 有料の教材です。 買っても良いと思いますが、chapter3まで無料なのでそこまでやって、その後は次にご紹介する記事を参考にすると良いと思います。 この記事にはかなり助けられました。 これを進めれば、RDSの作成やdocker環境でwebサーバーがnginxのrailsアプリをEC2にデプロイまでできます。 3,ALBを使用してHTTPからHTTPSでサイトにアクセスできるようにする サイトのHTTPS化には次のサイトを参考にしました。 chapter6でHTTPS化、 chapter7でHTTPでアクセスしてもHTTPSになるように設定できるようになります。 ちなみにサイトのドメインの取得方法は、最初にご紹介した山浦さんの動画で、「お名前.com」でドメインを購入し、Route53と連携する所まで紹介されています。 4,SESを使ったメール送信 AWSのSESを使用してメール送信は以下のサイトを参考にしました。 SES導入はエラーがでまくり、かなり苦戦したので、一応自分のエラーが出なかったproduction.rbを貼っておきます。 config/enviroments/production.rb creds = Aws::Credentials.new( ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACESS_KEY'] ) Aws::Rails.add_action_mailer_delivery_method( :aws_sdk, credentials: creds, region: ENV['AWS_REGION'] ) config.action_mailer.default_url_options = { host: 'あなたが取得したドメイン名' } config.action_mailer.delivery_method = :aws_sdk config.action_mailer.perform_deliveries = true config.action_mailer.perform_caching = false config.action_mailer.raise_delivery_errors = true ポイントは、 config.action_mailer.delivery_method = :aws_sdk の部分です。 rails aws sesで検索すると、ここが「:ses」になっている記事が多いですが、「:aws_sdk」にしないとエラーが出たので、よかったら参考にしてください。 4,S3に画像をアップロードする S3はRailsチュートリアルを参考に実装しました。 最後に 山浦さんのUdemyの講座が全体を網羅しているので、山浦さんの教材を軸にご紹介した記事などを参考に進めれば、環境構築はできると思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「Herokuで画像表示できない」を解決

はじめに  現在オリジナルアプリの開発中です。Heroku環境でアプリをアップロードしているのですが、assetsに配置した画像が表示されないという問題がありました。解決方法がわかったのでまとめておきます。 問題  app/assets/images 配下に設置した画像が表示されない。(ローカル環境では表示されている) ローカル環境では表示されているため、本番環境では追加の設定がいるのかもしれない。と思い調べると解決方法が出てきました。 解決方法  解決方法は image_tagのファイルの指定方法を修正することでした。 qiita.rb <%= image_tag "/assets/top.png" ,class:"img-fluid" %> image_tagに渡す画像のバスの指定方法を間違えていました。 この書き方では、ローカルだと表示されるのですが、本番環境だと表示されません。 以下に修正しました。 qiita.rb <%= image_tag "top.png" ,class:"img-fluid" %> 結果無事に本番環境でも画像を表示する事ができました。 追記 以下の方法は間違いでした 最初自分が採用した以下の解決方法は間違いでした。(画像は表示されるけど推奨されない) 編集リクエストありがとうございます。 production.rb config.assets.compile = false という記述があるので、 production.rb config.assets.compile = true に変更するやり方です。 この方法でも画像を表示できるのですが、本番環境でのパフォーマンスに悪影響を及ぼすため推奨しないとのことです。 以下を参考にしました。 https://qiita.com/jnchito/items/3d225112a3ac95379b1d まとめ  本番環境でのエラーだったため、最初何が原因か特定できなかったのですが、調べたらすぐに出てきました。 分からなくても焦らず、まずは冷静になる。→状況を整理する。→ググる という習慣を身につけたいと思います。 また、解決方法にも様々あるので、精査できるようになりたいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】find_or_initialize_byとfind_or_create_byの違い

find_or_create_by 条件を指定して初めの1件を取得(find)し、1件もなければ作成(create) 作成する時に呼ぶメソッドがcreateなので、新規作成して保存まで行う Category.find_or_create_by!(name: "ディナー") Category Load (0.6ms) SELECT "categories".* FROM "categories" WHERE "categories"."name" = $1 LIMIT $2 [["name", "ディナー"], ["LIMIT", 1]] TRANSACTION (0.5ms) BEGIN Category Create (2.0ms) INSERT INTO "categories" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "ディナー"], ["created_at", "2022-02-21 12:19:12.868048"], ["updated_at", "2022-02-21 12:19:12.868048"]] TRANSACTION (1.4ms) COMMIT => #<Category:0x00007fed472719b0 id: 1, name: "ディナー", created_at: Mon, 21 Feb 2022 12:19:12.868048000 JST +09:00, updated_at: Mon, 21 Feb 2022 12:19:12.868048000 JST +09:00> Category.find_or_create_by!(name: "その他") Category Load (0.6ms) SELECT "categories".* FROM "categories" WHERE "categories"."name" = $1 LIMIT $2 [["name", "その他"], ["LIMIT", 1]] => #<Category:0x00007fed4483f0e8 id: 2, name: "その他", created_at: Thu, 03 Feb 2022 12:20:21.014342000 JST +09:00, updated_at: Thu, 03 Feb 2022 12:20:21.014342000 JST +09:00> find_or_initialize_by 条件を指定して初めの1件を取得(find)し、1件もなければ作成(new) 作成する時に呼ぶメソッドがnewなので、保存はしない 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rspec,Rails】full_title helperの単体テスト

テストの対象となる機能 application helperに次のようなfull_title helperを定義している。 appplication_helper.rb module ApplicationHelper BASE_TITLE = "HOGE".freeze def full_title(page_title) page_title.blank? ? BASE_TITLE : "#{page_title} - #{BASE_TITLE}" end end ページタイトルを取得して、ベースタイトルとともにtitleタグに動的な表示を行うために作られた、普通のタイトルヘルパーである。 Rspecによって、この機能のテストを記述したい。 helperの単体テスト この機能をテストを記述するにあたっては、次のように、他のviewの要素とともに、system specにテストを記述する方法もある。 system_spec expect(page).to have_title "#{content.name} - HOGE" #content.nameという内容をタイトルに表示したい場合を想定している。 ただし、この方法だと、ページが増えるたびにこれをsystem_specに記述することになるし、このhelperの本質である「動的な表示をテスト」している記述であるかと言われれば、そうも言えない。 そこで、このhelperの単体のテストを別途設け、そこに条件分岐を与えた上で、条件に応じた動的な表示の機能があるかをテストしていきたい。 具体的には、spec/helpers/application_helper_spec.rbを作成し、次のようなテストを書く。 application_helper_spec.rb require 'rails_helper' RSpec.describe ApplicationHelper, type: :helper do describe "#full_title" do it "引数が渡されている場合に動的な表示がなされること" do expect(full_title('sample')).to eq('sample - HOGE') end it "引数が空白の場合に動的な表示がなされること" do expect(full_title('')).to eq('HOGE') end it "引数がnilの場合に動的な表示がなされること" do expect(full_title(nil)).to eq('HOGE') end end end 注意点はfull_title helperをタイトルを表示するためのものとして扱わないこと、 つまり、viewに特有の概念や「タイトル」という言葉をapplication_helper_spec内では使わないことである。 full_titleという名前ではあるが、このヘルパーは本来、viewや特定のタイトルに依存しない、汎用的な機能である。 単に与えられた引数を取得し、元々ある定数と一緒に返す機能に過ぎない。 たとえ、与えられた引数がviewやタイトルに関係のない内容であっても、この機能自体は担保されていないといけない。 「機能」をテストするために作られた、application_helper_specというファイルで実行される内容は、あくまでも機能をテストすることに終始すべきである。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[テスト] qiita api items

テストです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】APIモードのルーティング例

はじめに  本記事は、プログラミング初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。  そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。  間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。 Rails APIモードのルーティング ルーティング例 コメントで解説を記述していますのでご確認ください。 config/routes.rb Rails.application.routes.draw do # namespaceで名前空間を付与する。 namespace :api do # APIに大きな変更が発生する場合に備えてスイッチングしやすいようにURL自体にバージョンを持たせる。 # ただし、バージョンは「必要な場合にのみ」つけることが推奨されている。 namespace :v1 do # resouresはindex、show、new、edit、create、update、destroyアクションに対応するルーティングを作成できる。 resources :restaurants do # only: %i[index]等と記述することで特定のアクションのみルーティングを設定することができる。 resources :foods, only: %i[index] end resources :line_foods, only: %i[index create] # resourcesでは設定することのできないルーティングは以下のように記述することで設定可能 put 'line_foods/replace', to: 'line_foods#replace' resources :orders, only: %i[create] end end 上記の通り記述すると以下のようなルーティングは以下のようになります。 ターミナル % rails routes Prefix Verb URI Pattern Controller#Action api_v1_restaurant_foods GET /api/v1/restaurants/:restaurant_id/foods(.:format) api/v1/foods#index api_v1_restaurants GET /api/v1/restaurants(.:format) api/v1/restaurants#index POST /api/v1/restaurants(.:format) api/v1/restaurants#create api_v1_restaurant GET /api/v1/restaurants/:id(.:format) api/v1/restaurants#show PATCH /api/v1/restaurants/:id(.:format) api/v1/restaurants#update PUT /api/v1/restaurants/:id(.:format) api/v1/restaurants#update DELETE /api/v1/restaurants/:id(.:format) api/v1/restaurants#destroy api_v1_line_foods GET /api/v1/line_foods(.:format) api/v1/line_foods#index POST /api/v1/line_foods(.:format) api/v1/line_foods#create api_v1_line_foods_replace PUT /api/v1/line_foods/replace(.:format) api/v1/line_foods#replace api_v1_orders POST /api/v1/orders(.:format) api/v1/orders#create
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CGI.escape

CGIモジュールのescapeメソッド # @をエスケープ >> CGI.escape('foo@example.com') => "foo%40example.com" # 'とスペースと!をエスケープ >> CGI.escape("Don't panic!") => "Don%27t+panic%21" テストファイルでテスト用ユーザーのメールアドレスをエスケープできる CGI.escape(user.email)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails いいね機能の非同期を実装する際の注意するべきポイント

いいねの非同期を行う際、何回かエラーでつまづいた。 そんな時に確認するべきポイントをまとめる!! ##1.jQueryがちゃんと読み込まれているか Gemfile. gem 'jquery-rails' その後、bundle install を忘れずに。 app/assets/javascripts/application.js //= require jquery //= require rails-ujs //= require jquery_ujs webpacker/environment.js const { environment } = require('@rails/webpacker') const webpack = require('webpack') environment.plugins.prepend('Provide', new webpack.ProvidePlugin({ $: 'jquery/src/jquery', jQuery: 'jquery/src/jquery' }) ) module.exports = environment app/javascript/packs/application.js require('jquery') jQueryはこの辺り。。 ##2.link_toにremote:true _like_button.html.erb = link_to photo_like_path(@photo), method: :post, remote: true do _lunike_button.html.erb = link_to photo_like_path(@photo), method: :delete, remote: true do ajax用のviewファイル内のlink_toにremote: true を追加。 HTMLリクエストではなく、JavaScriptのリクエストがコントローラに送られる。 HTML →画面にリダイレクトする(ページを読み込む) JavaScript →いいね部分のみの更新(ページ読み込みなし) ##3.renderでテンプレートを読み込む&idで変更箇所に名前をつける <div id="like-button-<%= @photo.id %>"> <% if current_user.likes.exists?(photo_id: @photo.id) %> <%= render 'likes/unlike_button', photo: @photo %> <% else %> <%= render 'likes/like_button', photo: @photo %> <% end %> </div> ##4.js.erbファイル create.js.erb $("#like-button-<%= @photo.id %>").html("<%= j(render 'unlike_button', photo: @photo) %>") destroy.js.erb $("#like-button-<%= @photo.id %>").html("<%= j(render 'like_button', photo: @photo) %>") 以上。抜かりないよう。 #参考 https://qiita.com/hapiblog2020/items/3ba7e7edc02f01d987b9 https://qiita.com/masahisa/items/eaacb0c3b82f4a11fc13
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

includesを使ってSQLの発行件数を減らそう(N+1問題)

SQLの発行件数が多いと指摘を受ける。 業務にて、ある一覧画面を作成していたところ、 自分が書いたソースをみた先輩から、 「この一覧画面のSQLの発行件数が多すぎる。ちょっと減らしてみて。」とご指摘を受けました。 SQLの発行件数が多いのはN+1問題が起きていたことが原因で、 includesを使用することで 事象を解決できたのでアウトプットしてみようと思います。 N+1問題とは 必要以上にSQLが実行されて、パフォーマンスが低下する問題。 今回指摘を受けた画面では、 ログを見ると、他のテーブルの情報を取得するため何度もSQLが発行されていました。 includesとは includesメソッドは、関連している複数のテーブルからデータをあらかじめ取得するメソッドです。 N+1問題を解決させるためには、 都度SQLを発行させるのではなく、あらかじめデータをすべて取得しておくことで解決することができます。 例えば、 UserクラスとPostクラスがあって、 投稿からユーザ名を取得する処理があったとします。 # models/user.rb class User < ApplicationRecord has_many :posts end # models/post.rb class Post < ApplicationRecord belongs_to :user end # 投稿の一覧を取得する posts = Post.all posts.each do |post| p post.user.name end 上記のメソッドを実行すると、 投稿の数だけSQL文が発行されてしまい、 効率が悪いです。 そこで、下記のようにincludesメソッドを使用して、 あらかじめ投稿に関するユーザ情報を最初にすべて取得します。 そうすることで、 投稿がいくらあってもSQLの発行を一度で済ますことが可能です。 # 投稿と、投稿に関連したユーザ情報を取得する。 posts = Post.includes(:user) posts.each do |post| p post.user.name end 余談 ※SQLの発行件数は画面に対してAlt+Pを押下したり、  ログを見ることで確認できます。 参考記事: https://techacademy.jp/magazine/22031 https://qiita.com/south37/items/b2c81932756d2cd84d7d
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

assert_matchメソッド

正規表現で文字列をテスト。 assert_match( regexp, string, [msg] ) stringは正規表現 (regexp) にマッチすると主張する。 assert_match 'foo', 'foobar' # true assert_match 'baz', 'foobar' # false assert_match /\w+/, 'foobar' # true assert_match /\w+/, '$#!*+@' # false Rubular
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む