20210511のRubyに関する記事は18件です。

User.allを使わない。selectへ。

本記事の目的: モデルから取り出す際に、不要なデータ量を抑える 結論 user_controller.rb(変更前 : def index @users = User.all.page(params[:page]) end def following @title = "フォロー" @user = User.find(params[:id]) @users = @user.following.page(params[:page]) render "show_follow" end : user_controller.rb(変更後 : def index @users = User.select(:id, :username). includes([:works, avatar_attachment: :blob]). page(params[:page]) end def following @title = "フォロー" @user = User.find(params[:id]) @users = @user.following.select(:id, :username). includes([:works, avatar_attachment: :blob]).page(params[:page]) render "show_follow" end : 本文 例の如くN+1問題の解消に取り掛かるべく、includesを用いて関連付けされているデータを同時に取り出す事で、クエリの発行を抑えていた。 そこでもう一つ。User.allの利用をやめることにした。理由としては、モデルから取り出す不要なデータ量を抑えるためである。解決方法としては、selectメソッドを用いることで、必要なデータだけを指定することとする。 具体例を以下に示します。 User.all => TRANSACTION (0.4ms) BEGIN User Load (0.8ms) SELECT `users`.* FROM `users` [#<User id: 1, username: "Test_User", email: "test@example.com", created_at: "2021-05-03 13:07:22.877662000 +0900", updated_at: "2021-05-03 13:07:58.184592000 +0900", uid: nil, provider: nil, description: "My name is Test_User", website: "http://example.com/">, #<User id: 2, username: "Mon Mothma", email: "test1@example.com", created_at: "2021-05-03 13:07:23.807304000 +0900", updated_at: "2021-05-03 13:07:58.296445000 +0900", uid: nil, provider: nil, description: "My name is Savage Opress", website: "http://example.com/">, : #<User id: 22, username: "Bail Organa", email: "test21@example.com", created_at: "2021-05-03 13:07:29.297810000 +0900", updated_at: "2021-05-03 13:07:29.297810000 +0900", uid: nil, provider: nil, description: "My name is Nute Gunray", website: "http://example.com/">] User.select(:username, :id) => User Load (1.3ms) SELECT `users`.`username`, `users`.`id` FROM `users` [#<User username: "Test_User", id: 1>, #<User username: "Mon Mothma", id: 2>, : #<User username: "Bail Organa", id: 22>] 以上のように結果は歴然であるが、必要なデータだけを取り出すことに成功した。ちなみにこれは、2行目にあるActiveRecordが発行するSQLの違いにより発生している。 User.all => User Load (0.8ms) SELECT `users`.* FROM `users` User.select(:username, :id) => User Load (1.3ms) SELECT `users`.`username`, `users`.`id` FROM `users` また、これは関連付けを行っているモデルにおいても同様の事が可能であった。 これもActiveRecordが発行するクエリに準じている事がわかる。 pry(main)> user = User.first User Load (1.9ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1 => #<User id: 1, username: "Test_User", email: "test@example.com", created_at: "2021-05-03 13:07:22.877662000 +0900", updated_at: "2021-05-03 13:07:58.184592000 +0900", uid: nil, provider: nil, description: "My name is Test_User", website: "http://example.com/"> # 変更前 pry(main)> user.following => User Load (0.9ms) SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1 [#<User id: 3, username: "Lyra Erso", email: "test2@example.com", created_at: "2021-05-03 13:07:24.080580000 +0900", updated_at: "2021-05-03 13:07:58.435753000 +0900", uid: nil, provider: nil, description: "My name is Jango Fett", website: "http://example.com/">, #<User id: 4, username: "Borvo the Hutt", email: "test3@example.com", created_at: "2021-05-03 13:07:24.351829000 +0900", updated_at: "2021-05-03 13:07:58.993427000 +0900", uid: nil, provider: nil, description: "My name is Darth Sidious", website: "http://example.com/">, : #<User id: 21, username: "Mon Mothma", email: "test20@example.com", created_at: "2021-05-03 13:07:29.023478000 +0900", updated_at: "2021-05-03 13:07:29.023478000 +0900", uid: nil, provider: nil, description: "My name is Jango Fett", website: "http://example.com/">] # 変更後 pry(main)> user.following.select(:id, :username) => User Load (1.7ms) SELECT `users`.`id`, `users`.`username` FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1 [#<User id: 3, username: "Lyra Erso">, #<User id: 4, username: "Borvo the Hutt">, : #<User id: 21, username: "Mon Mothma">] 以上です! 最後まで読んで頂きありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】ユーザー管理機能をDeviseを使って実装する方法

1: Gemのインストール Gemfile # 最下部に追記 gem 'devise' ターミナル % bundle install # 再起動 control + C rails s 2: deviseの設定ファイルを作成 ターミナル % rails g devise:install 3: userモデルを生成 ターミナル % rails g devise user 4: マイグレーションの実行 #db/migrate/20XXXXXXXXX_devise_create_users.rb に記述 # マイグレーションを実行 % rails db:migrate # usersテーブルを確認 # ターミナルにて 再起動 control + C rails s # localhost:3000 で確認 5: deviseのビューを作成 ターミナル rails g devise:views # ログイン画面・サインアップ画面を編集 以上がdeviseを使ってユーザー管理機能を実装する方法でした!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

herokuにデプロイした際にassetsに配置した画像が表示されない。

環境 Ruby 2.6.5 Rails 6.0.3.5 heroku エラー確認 ActionView::Template::Error (The asset "default_icon" is not present in the asset pipeline. //中略 <%= image_tag 'default_icon', id: 'preview-icon' %> herokuへのデプロイ後、アプリにアクセスし新規登録を行おうとした時に、上記のエラーが発生した。 image_tagでassets/imagesに配置している画像を指定しているのだが "default_icon"というアセットは存在しませんよと言われている。 開発環境では問題なく動作していたため本番環境由来のエラーだと判断し探索開始 参考記事 https://qiita.com/___xxx_/items/fa15f358beba2b9389da 公式ドキュメント 解決法 config/environments/production.rbファイルの書き換え # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false # <= trueに変換 本番環境ではフォールバックが無効化されているため画像のあるファイルを参照してくれていなかった様です。 RailsにおけるJSやCSSの取り回しの理解がまだまだ浅いので、この辺りもバックエンドの後に詰めたいですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rspec]未解決:Dockerを導入後、Rspecでエラーが発生

はじめに dockerとdocker-composeを導入したはいいが、テストでめちゃくちゃエラーがでたので備忘として記録する エラー内容 結合テストのみ例外なくエラーが発生 (一部抜粋) 47) Practices 投稿編集 投稿編集できないとき ログイン後、編集ページで、誤った情報が入力されているとエラー Failure/Error: url: ENV.fetch("SELENIUM_DRIVER_URL"), KeyError: key not found: "SELENIUM_DRIVER_URL" # ./spec/support/capybara.rb:7:in `fetch' # ./spec/support/capybara.rb:7:in `block (2 levels) in <main>' 試したこと おそらく自分が知らない知識として、「Docker上で結合テストを行うには環境構築が必要のなのだろう」と仮説を立てて、情報収集をおこなう。 こちらの記事に行き着くも,一向に変化はなし。 なお、ローカル上では間違いなくテストは成功していたことを考えると、間違いなくDockerを導入したことが影響していると考えられるので、ここらへんを疑って引き続き考えていきたい コード FROM ruby:2.6.5 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 RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs yarn WORKDIR /soccer_app COPY Gemfile /soccer_app/Gemfile COPY Gemfile.lock /soccer_app/Gemfile.lock RUN gem install bundler RUN bundle install COPY . /soccer_app RUN yarn install --check-files RUN bundle exec rails webpacker:compile docker-compose.yml version: "3" services: db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: "password" ports: - "4306:3306" selenium_chrome: image: selenium/standalone-chrome-debug logging: driver: none web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/soccer_app ports: - "3000:3000" depends_on: - db stdin_open: true tty: true environment: BASIC_AUTH_USER: ${BASIC_AUTH_USER:-default} BASIC_AUTH_PASSWORD: ${BASIC_AUTH_PASSWORD-default} Gemfile. source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.6.5' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 6.0.0' # Use mysql as the database for Active Record gem 'mysql2', '>= 0.4.4' # Use Puma as the app server gem 'puma', '~> 3.11' # Use SCSS for stylesheets gem 'sass-rails', '~> 5' # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker gem 'webpacker', '~> 4.0' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.7' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use Active Model has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use Active Storage variant # gem 'image_processing', '~> 1.2' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.4.2', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem 'rspec-rails', '~> 4.0.0' gem 'factory_bot_rails' gem 'faker' gem 'rubocop', require: false end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' gem 'rubocop', require: false # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' end group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara', '>= 2.15' gem 'selenium-webdriver' # Easy installation and use of web drivers to run system tests with browsers gem 'webdrivers' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] gem 'devise' gem 'pry-rails' gem 'active_hash' gem 'carrierwave', '~> 1.3', '>= 1.3.1' gem 'mini_magick' gem 'image_processing', '~> 1.2' gem 'rails-i18n' gem 'kaminari' gem "gretel" gem 'simple_calendar', '~> 2.0' gem "aws-sdk-s3", require: false capybara.rb require 'capybara/rspec' RSpec.configure do |config| config.before(:each, type: :system) do driven_by :selenium, using: :headless_chrome, options: { browser: :remote, url: ENV.fetch("SELENIUM_DRIVER_URL"), desired_capabilities: :chrome } Capybara.server_host = 'web' Capybara.app_host='http://web' end end おわりに 今回はまじで解決しなさそうな匂いがぷんぷんしますが、諦めず、前向きに取り組んでいきます! はやくこの記事を解決済みに更新したいな〜
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Proc?lambda?違いは何?

はじめに 現場での開発にて、「Procや、lambdaってどうやって使うんだろう?」って思って、使い方が曖昧だったので、調べてみました! よく使う技術だと思うので、ぜひ習得しましょう! Procオブジェクトとは 処理をオブジェクトとして抽象化したもの。 これを使うことで、処理を使い回すことが可能です。 基本的な使い方 Proc.new { 処理 }で処理を作成して、.call()で実行出来ます。 sample = Proc.new do |name| puts "Hello, #{name}" # 最後に評価される式の値が戻り値となる end sample.call("Tanaka") #=> "Hello, Tanaka" lambdaとは? lambdaとはProcオブジェクトを作る方法の一つで、Procと比べて引数チェックとreturnの挙動に違いがあります。 sample = lambda { |name| puts "Hello, #{name}" } sample.call('Tanaka') #=> 'Hello, Tanaka' # 省略系 sample = ->(name) { puts "Hello, #{name}" } sample.call('Tanaka') #=> 'Hello, Tanaka' 引数チェックの相違 <Proc.newの場合> 引数が多い場合は、先頭から必要な数分だけ取って残りは無視する。 少ない場合は、足りない部分にnilを割り当てるます。 proc_sample = lambda do |a, b, c| p [a, b, c] end proc_sample.call(1, 2) #=> [1, 2, nil] <lambdaの場合> lambdaの場合は、引数の数が違うとArgumentErrorが発生します。 proc = lambda do |a, b, c| p [a, b, c] end proc.call(1, 2) => ArgumentError: wrong number of arguments (2 for 3) returnの挙動 <Proc.newの場合> return後は、メソッド自体を抜け出します。 def proc_method proc = Proc.new { return p "return proc"} proc.call p "proc method" end proc_method #=> "return proc" <lambdaの場合> lambdaの場合はreturnした後にメソッドに戻り、メソッドを最後まで実行します。 def lambda_method lambda1 = lambda { return p "return lambda"} lambda1.call p "lambda method" end lambda_method #=> "return lambda" #=> "lambda method" おわりに Procとlambdaの違いを理解して利用することで、現場での開発でも再利用可能で綺麗なコードを書くことが出来そうですね!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

知識0からProcオブジェクトについて調べてみた。

はじめに 現場での開発にて、「Procや、lambdaってどうやって使うんだろう?」って思って、使い方が曖昧だったので、調べてみました! よく使う技術だと思うので、ぜひ習得しましょう! Procオブジェクトとは 処理をオブジェクトとして抽象化したもの。 これを使うことで、処理を使い回すことが可能です。 基本的な使い方 Proc.new { 処理 }で処理を作成して、.call()で実行出来ます。 sample = Proc.new do |name| puts "Hello, #{name}" # 最後に評価される式の値が戻り値となる end sample.call("Tanaka") #=> "Hello, Tanaka" lambdaとは? lambdaとはProcオブジェクトを作る方法の一つで、Procと比べて引数チェックとreturnの挙動、breakの挙動に違いがあります。 sample = lambda { |name| puts "Hello, #{name}" } sample.call('Tanaka') #=> 'Hello, Tanaka' # 省略系 sample = ->(name) { puts "Hello, #{name}" } sample.call('Tanaka') #=> 'Hello, Tanaka' 引数チェックの相違 <Proc.newの場合> 引数が多い場合は、先頭から必要な数分だけ取って残りは無視する。 少ない場合は、足りない部分にnilを割り当てるます。 proc_sample = lambda do |a, b, c| p [a, b, c] end proc_sample.call(1, 2) #=> [1, 2, nil] <lambdaの場合> lambdaの場合は、引数の数が違うとArgumentErrorが発生します。 lambda_sample = lambda do |a, b, c| p [a, b, c] end lambda_sample.call(1, 2) => ArgumentError: wrong number of arguments (2 for 3) returnの挙動 <Proc.newの場合> return後は、メソッド自体を抜け出します。 def proc_method proc_sample = Proc.new { return p "return proc"} proc_sample.call p "proc method" end proc_method #=> "return proc" <lambdaの場合> lambdaの場合はreturnした後にメソッドに戻り、メソッドを最後まで実行します。 def lambda_method lambda_sample = lambda { return p "return lambda"} lambda_sample.call p "lambda method" end lambda_method #=> "return lambda" #=> "lambda method" breakの挙動 <Proc.newの場合> 例外が発生する。 def proc_method proc_sample = Proc.new do break 1 puts :unreachable end proc_sample.call p 'proc method' end proc_method #=> LocalJumpError: break from proc-closure <lambdaの場合> lambdaの場合はbreakした後にメソッドに戻り、メソッドを最後まで実行します。 def lambda_method lambda_sample = lambda do break 1 puts :unreachable end lambda_sample.call p "lambda method" end lambda_method #=> "lambda method" おわりに Procとlambdaの違いを理解して利用することで、現場での開発でも再利用可能で綺麗なコードを書くことが出来そうですね!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】文字列 (paizaランク C 相当)【解答】

はじめに paizaの問題集をRubyで解いてみて、回答が見当たらない?ので備忘録を兼ねて記載してみます。 問題文はこちらから 解答 n = gets.to_i n.times do a, b, c = gets.split(" ") b = b.to_i c = c.to_i t1, t2 = a.split(":").map(&:to_i) t1 = t1 + b t2 = t2 + c if t2 > 59 t1 = t1 + 1 t2 = t2 - 60 if t1 > 23 t1 = t1 - 24 puts format("%02d:%02d", t1, t2) else puts format("%02d:%02d", t1, t2) end else if t1 > 23 t1 = t1 - 24 puts format("%02d:%02d", t1, t2) else puts format("%02d:%02d", t1, t2) end end end 24時以降になったら、0時にする処理が思いつかずゴリ押ししてしまった。。。 流れとしては、 1、変数nに繰り返す回数を代入してあげる 2、timesメソッドで繰り返す 3、変数aには開始時刻、変数bには何時間続くか、変数cには何分続くかを代入 4、更に変数aをt1、t2に分割して代入 5、それぞれを足し算 6、1つめの条件式「t2 > 59」何分を足した際に時間が繰り上がる場合の処理 7、更に24時以降になったら0時にする処理をそれぞれに記載 7つめがゴリ押し処理部分です。。。 が、これでクリアはできます!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】数字の文字列操作(時刻2) (paizaランク D 相当)【解答】

はじめに paizaの問題集をRubyで解いてみて、回答が見当たらない?ので備忘録を兼ねて記載してみます。 問題文はこちらから 解答 a, b = gets.split(":") c = b.to_i + 30 if c > 59 d = a.to_i + 1 e = c - 60 puts format("%02d:%02d", d, e) else puts format("%02d:%02d", a, c) end format(=sprintf)を使ってゼロ埋めしてあげることがミソな気がします。 format(=sprintf) とは 与えられた引数を指定したフォーマットの文字列として返してくれるメソッド。 今回使用した「%02d」は、"整数値2桁の余った空白をゼロで埋めるよ"と指定しています。 dはdecimal(10進数)のことです。 2の部分を変更してあげることによって、桁数が変わります。 例:5桁の場合 a = 12 format("%05d", a) => "00012"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

db接続のエラー - PG::ConnectionBad: could not connect to server: No such file or directory -

1, 環境 macOS catalina 10.15.7 Ruby 2.6.5p114 Rails 6.0.3.7 2, はじめに エラーにハマって自身でしらべ、解消できたのですが今後も起きた時のためにも残しておきます。 また、同じエラーで困った人の助けになれば。 3, エラー内容 deviseの導入を行なっており、rails db:migrateを実行すると、 kanta@fukazawakantanoMacBook-Pro insta-app-daytra % rails db:migrate rails aborted! PG::ConnectionBad: 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"? DBの接続に関してのエラーっぽいですね。 4, 試したこと エラー文をDeepLにて翻訳。 PG::ConnectionBad: サーバーに接続できませんでした。No such file or directory サーバーはローカルで動作していて、以下を受け付けています。 Unixドメインソケット「/tmp/.s.PGSQL.5432」で接続を受け付けていますか? なんとなくの意味は分かったが根本的な問題は分からず。 そこでエラー文の Is the server running locally and accepting connections on Unix domain socket "/tmp/.s.PGSQL.5432"? をググると、以下の記事がヒット →https://qiita.com/knxrvb/items/72d88fe5364561214e52 ターミナルでそこにあるコードを実行しDBを起動しようとすると postgres -D /usr/local/var/postgres 2021-05-11 15:22:39.356 JST [31540] FATAL: database files are incompatible with server 2021-05-11 15:22:39.356 JST [31540] DETAIL: The data directory was initialized by PostgreSQL version 12, which is not compatible with this version 13.2.   とログが表示。 翻訳すると、 データベースファイルがサーバーと互換性がない データディレクトリはPostgreSQLバージョン12で初期化されており、このバージョン13.2とは互換性がありません。 と、postgresのバージョンが古いみたい。 記事にもあるアップグレードさせるコードを実行。 brew postgresql-upgrade-database いろいろコードが走り、 ==> brew install postgresql@12 ==> Downloading https://ghcr.io/v2/homebrew/core/postgresql/12/manifests/12.6_2 ######################################################################## 100.0% ・    ・    ・ 一件落着かに思われたが、、、 Error: Upgrading postgresql data from 12 to 13 failed! ==> Removing empty postgresql initdb database... ==> Moving postgresql data back from /usr/local/var/postgres.old to /usr/local/var/postgres... Error: Failure while executing; `/usr/local/opt/postgresql/bin/pg_upgrade -r -b /usr/local/Cellar/postgresql@12/12.6_2/bin -B /usr/local/opt/postgresql/bin -d /usr/local/var/postgres.old -D /usr/local/var/postgres -j 4` exited with 1. アップグレードできず。。。 そのままエラー文の pgrading postgresql data from 12 to 13 failed! をググると →https://twin-t.com/postgressql%E3%82%92%E3%82%A2%E3%83%83%E3%83%97%E3%83%87%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%E9%9A%9B%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC/ がヒット。 どうやらPostgresSQLを起動したままアップデートを行ったことがまずかったみたい。 記事に従って、PostgresSQLを停止させ、 brew services stop postgresql brew postgresql-upgrade-database . . . ==> Upgraded postgresql data from 12 to 13! ==> Your postgresql 12 data remains at /usr/local/var/postgres.old 無事アップグレード完了!! 試しにDBを起動させると、 brew services start postgresql ==> Successfully started `postgresql` (label: homebrew.mxcl.postgresql) 成功ですね!! rails db:migrateも実行できました!!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby] pluckメソッド/mapメソッドでテーブルから配列を抽出/加工する

記事の概要  Railsアプリでデータを取扱っていると、テーブルから特定のカラムデータだけを配列にして抽出したい、抽出した配列データを加工して新しい配列にしたい、といった場面に逢います。そうしたときに便利なpluckメソッド、mapメソッドを試してみました。  1. pluckメソッド  2. mapメソッド 1. pluckメソッド  1つのモデルで使用されているテーブルについて、引数に指定したカラムの値を配列で返すメソッド。カラムの指定は一つでも複数でも可。  今、下表のような、出品された家電製品のテーブルがあるとする(Itemモデルのitemsテーブル)。  pluckメソッドを使ってみると、下のように配列が帰ってくる。 names = Item.pluck(:item_name) # 引数にカラムを一つ指定 # => ["掃除機", "冷蔵庫", "空気清浄機", "扇風機", "アイロン", "洗濯機", "電子レンジ", "プリンター", "ヒーター"] nameprices = Item.pluck(:item_name,:price) # 引数にカラムを二つ指定 # => [["掃除機", 5000], ["冷蔵庫", 20000], ["空気清浄機", 10000], ["扇風機", 1000], ["アイロン", 3000], ["洗濯機", 9000], ["電子レンジ", 2000], ["プリンター", 6000], ["ヒーター", 4000]]  pluckメソッドに引数を渡さない場合は、全てのカラムのデータが二次元配列に格納されて返ってくる。 2. mapメソッド  配列の各要素に対して、ブロックを評価した後に新しい配列にして返してくれる。  例として、mapメソッドを使って、上記のitemsテーブルについて全品10%割引を適用させてみる。 prices = Item.pluck(:price) # => [5000, 20000, 10000, 1000, 3000, 9000, 2000, 6000, 4000] discounted_prices = prices.map{|n|n*0.9} # => [4500.0, 18000.0, 9000.0, 900.0, 2700.0, 8100.0, 1800.0, 5400.0, 3600.0]  新たな配列に格納されて返ってきた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】標準入出力 (paizaランク C 相当)【解答】

はじめに paizaの問題集をRubyで解いてみて、回答が見当たらない?ので備忘録を兼ねて記載してみます。 問題文はこちらから 解答 a = gets.to_i a.times do b, c = gets.split(" ") puts "#{b} #{c.to_i + 1}" end mapメソッドでcをintefer型にできそう。。。?
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】数字の文字列操作(基本) (paizaランク D 相当)【解答】

はじめに paizaの問題集をRubyで解いてみて、回答が見当たらない?ので備忘録を兼ねて記載してみます。 問題文はこちらから 解答 a = gets.split("").map(&:to_i) print a[0] + a[3], a[1] + a[2] aに出力値を一文字ずつ分割して、mapメソッドでinteger型に変換します。 改行せず横一列で出力値を表示するため、printで表示させてあげればOK!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NameErrorが出た!

はじめに フリマアプリを作成中、NameErrorが出ました。 私の場合だいたい誤字の可能性があるので確認したのですが、誤字・脱字はなく別で原因がありました。 エラー箇所確認 商品出品機能の実装で商品を出品する際に必要なものをAcitiveHashを使って表示させようとしました。 app>models>shopping_date.rb class shopping_date < ActiveHash::Base self.data = [ { id: 1, name: '--'}, { id: 2, name: '1~2日で発送'}, { id: 3, name: '2~3日で発送'}, { id: 4, name: '4~7で発送'} ] include ActiveHash::Associations has_many :items end views>items>new.html.erb <div class="weight-bold-text"> 発送までの日数 <span class="indispensable">必須</span> </div> <%= f.collection_select(:shopping_date_id, shopping_date.all, :id, :name, {}, {class:"select-box", id:"item-scheduled-delivery"}) %> </div> </div> データをプルダウン形式で表示させたかったのでcollection_selectメソッドを使用しました。 結論:モデルの命名規則を忘れいていました モデルに命名規則がある事を忘れていました。 shopping_date.rbを確認するとモデルクラスが小文字でアンダースコア使用してました。 訂正をすると以下になります、 app>models>shopping_date.rb #訂正 class ShoppingDate < ActiveHash::Base self.data = [ { id: 1, name: '--'}, { id: 2, name: '1~2日で発送'}, { id: 3, name: '2~3日で発送'}, { id: 4, name: '4~7で発送'} ] include ActiveHash::Associations has_many :items end views>items>new.html.erb <div class="weight-bold-text"> 発送までの日数 <span class="indispensable">必須</span> </div> #訂正 <%= f.collection_select(:ShoppingDate_id, shopping_date.all, :id, :name, {}, {class:"select-box", id:"item-scheduled-delivery"}) %> </div> </div> 上手く反映されました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyで解くAtCoder ABC 194 (B,C問題のみ)

B - Job Assignment こう考えました 従業員に0から番号を割り振って,仕事A,B(変数名は1,2でつけてしまったけど・・・)の時間を従業員番号をキーとしたハッシュに入れる。 それぞれで早くできる順に2名を選抜。 もし,それぞれのトップが別々の従業員の場合 →2つの時間のうち,大きいものを出力。 それぞれトップが同じ従業員の場合 →どちらか片方を2番目の従業員にした場合の時間,トップが両方やる時間のうち,小さいものを出力。 提出コード もっと簡単に出せる手法はありそうだけど・・・ ABC194_B.rb N = gets.to_i t_1 = {} t_2 = {} N.times do |i| w_1, w_2 = gets.split.map(&:to_i) t_1.store(i, w_1) t_2.store(i, w_2) end rank_1 = t_1.min(2){|x, y| x[1] <=> y[1]} rank_2 = t_2.min(2){|x, y| x[1] <=> y[1]} first_1, second_1 = rank_1[0], rank_1[1] first_2, second_2 = rank_2[0], rank_2[1] if first_1[0] != first_2[0] puts [first_1[1], first_2[1]].max else puts [[first_1[1], second_2[1]].max , [second_1[1], first_2[1]].max , first_1[1] + first_2[1]].min end C - Squared Error 愚直にやったらTLE・・・ 全部の組み合わせを配列にして,それぞれで計算した和を計算すれば・・・ (ちょうど教えてもらったsumにブロックを与える形が使える!) →TLEでした。計算回数を減らさなきゃいけない・・・ ABC194_C.rb gets num = gets.split.map(&:to_i) puts num.combination(2).to_a.sum {|i,j| (i-j)*(i-j) } 解説を少し見た 数列の長さはかなり大きいけど,与えられる数値は -200〜200 なので,数値ごとの個数を配列にすればいい! (ちょうど教えてもらったtallyが使える!) ハッシュにまとめてからkeyもvalueも別々に配列化し,あとは全部の組み合わせについて計算しました。 (係数としてそれぞれの数の個数をかければいいので,計算回数が大幅に減りました) 提出コード ABC194_C.rb gets arr = gets.split.map(&:to_i) hash = arr.tally num = hash.keys cnt = hash.values n = num.size sum = 0 (1..n-1).each do |i| (0..i).each do |j| sum += (num[i] - num[j]) * (num[i] - num[j]) * cnt[i] * cnt[j] end end puts sum
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CSVの基礎(特異メソッドとインスタンスメソッド)

CSVを学んだのでリファレンスを参照して整理しておきます CSVとは  CSVファイルやデータに対する完全なインターフェースを提供するクラス。  開発現場では大量のデータを扱うためにExcelでCSVデータを作成して、それをデータベースに一気に投入するという方法がよく利用されるらしい。 読み込みの例 require "csv" csv_text = <<~CSV_TEXT Ruby,1995 Rust,2010 CSV_TEXT IO.write "sample.csv", csv_text # ファイルから一行ずつ CSV.foreach("sample.csv") do |row| p row end # => ["Ruby", "1995"] # ["Rust", "2010"] # ファイルから一度に p CSV.read("sample.csv") # => [["Ruby", "1995"], ["Rust", "2010"]] # 文字列から一行ずつ CSV.parse(csv_text) do |row| p row end # => ["Ruby", "1995"] # ["Rust", "2010"] # 文字列から一度に p CSV.parse(csv_text) # => [["Ruby", "1995"], ["Rust", "2010"]] 特異メソッド(読み込み) require "csv" 外部ファイルの読み込みを行うメソッド "CSV"(ライブラリ名)を渡して指定する IO.write(path, string) path で指定されるファイルを開き、string を書き込み閉じる。 パラメータ 説明 path: ファイル名文字列を指定 string: 書き込む文字列を指定 CSV.foreach(path, options) CSVファイルを読むための主要なインターフェース 各行が与えられたブロックに渡される パラメータ 説明 path:  CSVファイルパスの指定 options:  CSV.new のオプションと同じオプションを指定できる CSV.read(path, options)  CSVファイルを二次元配列にするために使う  headersオプションに偽でない値を指定した場合はCSV::Table オブジェクトを返す パラメータ 説明 path:  CSVファイルパスの指定 options:  CSV.new のオプションと同じオプションを指定できる CSV.parse(str, options ) 文字列を簡単にパースすることができる。 ブロックを与えた場合は、ブロックにそれぞれの行を渡す。 ブロックを省略した場合は、二次元配列を返す。 パラメータ 説明 str: 文字列を指定 options: CSV.new のオプションと同じオプションを指定できる 書き込みの例 require 'csv' # ファイルへ書き込み CSV.open("path/to/file.csv", "wb") do |csv| csv << ["row", "of", "CSV", "data"] csv << ["another", "row"] # ... end # 文字列へ書き込み csv_string = CSV.generate do |csv| csv << ["row", "of", "CSV", "data"] csv << ["another", "row"] # ... end 特異メソッド(書き込み) CSV.open(filename, options )  IOオブジェクトをオープンしてCSVでラップする。  CSVファイルを書くための主要なインターフェース。  ブロックが与えられた場合はブロックにCSVオブジェクトを渡し、ブロック終了時にクローズする。  ブロックが与えられなかった場合はCSVオブジェクトを返す。 パラメータ 説明 filename: ファイル名を指定 options: CSV.new のオプションと同じオプションを指定できる CSV.generate(str = "", options )  与えられた文字列をラップしてCSVのオブジェクトとしてブロックに渡す。 ブロック内でCSVオブジェクトに行を追加できるブロックを評価した結果は文字列を返す。  このメソッドに与えられた文字列は変更されるので、新しい文字列オブジェクトが必要な場合は Object#dupで複製すること。 パラメータ 説明 str: 文字列を指定。デフォルトは空文字列。 options: CSV.new のオプションと同じオプションを指定できる。 CSV.new(data, options)  CSV ファイルを読み込んだり、書き出したりするために String か IO のインスタンスをラップする。  ラップされた文字列の先頭から読み込む。文字列に追記したい場合は CSV.generate を使用。他の位置から処理したい場合はあらかじめそのように設定した StringIO を渡す。 パラメータ 説明 data: String か IO のインスタンスを指定。 String のインスタンスを指定した場合、CSV#string を使用して後からデータを取り出す。 options: CSV をパースするためのオプションをハッシュで指定。インスタンスメソッドではオプションを上書きすることが出来ない。上書きしたい場合は必ずここで上書きする。 オプション 説明 :col_sep フィールドの区切り文字列を指定。 :row_sep 行区切りの文字列を指定。:auto という特別な値をセットすることができる。 :quote_char フィールドをクオートする文字を指定。長さ 1 の文字列でなければいけない。 :field_size_limit 制限を使用してDos攻撃を防ぐ。 :converters CSV::Converters から取り出した名前の配列。変換器が一つだけの場合は配列に格納する必要はない。 :unconverted_fields 真をセットすると CSV::Row#unconverted_fields という変換前のフィールドを返すメソッドを全ての行に追加する。 :headers :first_row というシンボルか真を指定すると、CSV ファイルの一行目をヘッダとして扱う。配列を指定するとそれをヘッダとして扱う。文字列を指定すると CSV.parse_line を使用してパースした結果をヘッダとして扱う。 :return_headers 偽を指定すると、ヘッダ行を無視。真を指定すると、ヘッダ行をヘッダと値が同一の CSV::Row のインスタンスとして返す。 :write_headers 真を指定して :headers にも値をセットすると、ヘッダを出力する。 :header_converters ヘッダ専用の変換器を定義。 :skip_blanks 真を指定すると空行を読み飛ばす。 :force_quotes 真を指定すると全てのフィールドを作成時にクオートする。 :skip_lines 指定した正規表現にマッチしたそれぞれの行をコメントとして読み飛ばす。 クラスインスタンス headers nil を返した場合は、ヘッダは使用使用されない。 真を返した場合は、ヘッダを使用するがまだ読み込まれない。 配列を返した場合は、ヘッダは既に読み込まれている。 self << row 自身に row を追加。 データソースは書き込み用にオープンされていなければならない。 パラメータ 説明 row: 配列か CSV::Row のインスタンスを指定。 CSV::Row のインスタンスが指定された場合は、CSV::Row#fields の値のみが追加される。 参考もと RRuby 3.0.0 リファレンスマニュアル>ライブラリ一覧>csvライブラリ >CSVクラス
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

test

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

フラットなファイル構成のディレクトリでguardを使ってrspecを自動実行する

やりたいこと 下記のように、rubyソースコード、specファイル、Guardfileが全て一つのディレクトリにフラットに配置されている環境で、guardによる自動テスト実行を行いたい。 root_dir ├── Guardfile ├── gilded_rose.rb └── gilded_rose_spec.rb 設定方法 guard, guard-rspecをインストールする 上記のような配置の場合、bundleを使っていることは考えにくいのでシステムにインストールしておく。 gem install guard guard-rspec Guardfileを作成 root_dirにGuardfileを作成し、下記を記述する。 guard :rspec, cmd: 'rspec', spec_paths: ["./"] do watch(%r{.+_spec\.rb$}) { |m| "./#{m[0]}" } watch(%r{(.+)(?!_spec)\.rb$}) { |m| "./#{m[1]}_spec.rb" } end guardを実行 guard guardを実行してから、rubyファイルかspecファイルを更新すれば、自動的にspecが実行される。 上記のように設定する理由 デフォルトの設定だと自動実行されないため。 デフォルトでは、実行ファイルはlibディレクトリ配下、specファイルはspecディレクトリに配置されていることが想定されている。したがって、カレントディレクトリ配下でも動くように設定を変えてやる必要がある。 ポイント spec_pathsにカレントディレクトリを設定する guardはこれをテスト用のファイルが入っているディレクトリとみなす。ここに入っていないテストの実行は防止する仕組みになっている。 watchのブロックの返り値に./がつくようにする ファイルの変更を検出すると、watchのブロックを評価した結果のパスで指定されるspecファイルを実行するが、これがspec_pathsに入っているか確認している。spec_pathsに./と指定しているので、ブロックの返り値のパスが./で始まっていないと対象のフォルダに入っていないとみなしてしまう。 実行するファイルのフィルタは下記のソースコードを参照。 https://github.com/guard/guard-rspec/blob/master/lib/guard/rspec/inspectors/base_inspector.rb#L48-L50
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails] chart.jsでRailsアプリにグラフを描画する [chart.js]

記事の概要  アプリで取り扱われるデータを可視化できればと思い、chart.jsを使ってRailsアプリにグラフを描いてみます。  1. chart.jsの導入手順  2. 記事投稿数の推移グラフを描いてみる chart.jsとは?  JavaScriptで実装されたグラフをRailsアプリに組込むことができるライブラリです。  公式  https://www.chartjs.org/docs/latest/ 1. chart.jsの導入手順  Gemfileに記述する。 Gemfile gem 'chart-js-rails', '~> 0.1.4'  そしてターミナルでbundle installを実行する。 % bundle install  package.jsonに以下の通り追記。 package.json { # 省略 "dependencies": { #省略 "chart.js": "^2.7.1" # ←ここに追記 } }  そしてターミナルでyarn installを実行。 % yarn install 2. 記事投稿数推移グラフを描いてみる  ここでは、とあるArticleモデルの投稿数推移について、Articlesコントローラーでデータを加工してarticles#indexにグラフ描画することをゴールとします。  横軸が日付、縦軸が投稿数です。なお、日時データを扱う"groupdate" gemは導入済みとして進めます。  まず、グラフ描画の基本構成は下記のようになります。公式ページのサンプル参照。 app/views/articles/index.html.erb <canvas id="myChart" width="200" height="100"> </canvas> <script> var ctx = document.getElementById("myChart").getContext('2d'); var myChart = new Chart(ctx, { type: 'bar', # 'bar'でグラフタイプを縦棒グラフに指定  data: { labels: <%= @chartlabels %>, # 横軸にとるデータ(今回は投稿日付)を埋め込む datasets: [{ label: "投稿数", data: <%= @chartdatas %>, # 縦軸にとるデータ(今回は投稿数)を埋め込む backgroundColor: 'rgba(255, 80, 120, 1.0)', borderColor: 'rgba(255, 80, 120, 1.0)', fill: false }] }, }); </script>  グラフに渡すデータをarticles_controllerで用意しましょう。インスタンス変数を定義します。 app/controllers/articles_controller class ArticlesController < ApplicationController def index @articles = Article.all @article_by_day = @articles.group_by_day(:created_at).size # groupdateのgroup_by_dayメソッドで投稿日(created_at)に基づくグルーピングして個数計上。 # => {Wed, 05 May 2021=>23, Thu, 06 May 2021=>20, Fri, 07 May 2021=>3, Sat, 08 May 2021=>0, Sun, 09 May 2021=>12, Mon, 10 May 2021=>2} @chartlabels = @article_by_day.map(&:first).to_json.html_safe # 投稿日付の配列を格納。文字列を含んでいると正しく表示されないので.to_json.html_safeでjsonに変換。 # => "[\"2021-05-05\",\"2021-05-06\",\"2021-05-07\",\"2021-05-08\",\"2021-05-09\",\"2021-05-10\"]" @chartdatas = @article_by_day.map(&:second) # 日別投稿数の配列を格納。 # => [23, 20, 3, 0, 12, 2] end end  Railsアプリを起動し/indexへアクセスすると縦棒グラフが描画されている。  次に、累計投稿数を折れ線グラフにして、先ほどのグラフに重ねてみます。 app/views/articles/index.html.erb <canvas id="myChart" width="200" height="100"> </canvas> <script> var ctx = document.getElementById("myChart").getContext('2d'); var myChart = new Chart(ctx, { type: 'bar',   data: { labels: <%= @chartlabels %>, datasets: [{ label: "日別投稿数", data: <%= @chartdatas %>, backgroundColor: 'rgba(255, 80, 120, 1.0)', borderColor: 'rgba(255, 80, 120, 1.0)', fill: false },{ //ここから追記 label: "累積投稿数", data: <%= @cumulative %>, // 縦軸にとる累積投稿数データを埋め込む backgroundColor: 'rgba(255, 80, 120, 0.2)', borderColor: 'rgba(255, 80, 120, 1.0)', type: 'line', // 'line'でグラフタイプを折線グラフに指定 }] }, }); </script>  累積投稿数データを配列にして、インスタンス変数として用意します。 app/controllers/articles_controller class ArticlesController < ApplicationController def index @articles = Article.all @article_by_day = @articles.group_by_day(:created_at).size @chartlabels = @article_by_day.map(&:first).to_json.html_safe @chartdatas = @article_by_day.map(&:second) # ここから追記 @cumulative = [] sum=0 @chartdatas.each do |a| sum = sum + a @cumulative<<sum end end end  アプリを起動し/indexへアクセスすると、線グラフも表示されました。 まとめ  chart.jsを活用し、記事投稿数推移グラフを縦棒+折れ線グラフで表現できました。データベースから加工したデータをグラフで表現することができるので、アプリの管理者機能、可視化など幅広く活用できそうです。カスタマイズも柔軟にできそうなので、今後も記事で取扱いたいと思います。  Rubyでのデータ加工(もっと簡潔にできそう)とJavaScript記述の良いトレーニングにもなりました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む