20210815のRubyに関する記事は14件です。

ActiveRecord(アクティブレコード)について

ActiveRecordとは DBには様々な種類があり、MySQL、PostgreSQL、SQLite、SQL Server、Oracleなどが良く使われています。 DBによって記述のルールが違うため、それに伴って学習コストが高くなる可能性があります。 ActiveRecordを用いるとRuby言語でDBの操作が可能になり、SQL等よりも短いコードでDBを呼び出す(追加)ことが可能です。 命名規則について ActiveRecordはクラス名に関する命名規約があります 例えば、クラス名がBookの場合、booksというテーブルで対応します。 Railsでは、開発者が名付けたモデルクラス名を複数形にしDBのテーブルを探してくれます。 ActiveRecordメソッド まずは下準備として、Railsアプリ(blog_app)を作成 rails new blog_app -d postgresql rails db:create rails db:migrate rails c  メソッド一覧 createメソッド(レコードの新規作成) Blog.create(title: 'タイトルA', content: '内容A')) newメソッド(モデルオブジェクトをインスタンス化) @blog = Blog.new(title: 'タイトルB', content: '内容B') findメソッド(idを引数にし、そのレコードをオブジェクトとして取得) Blog.find(3) updateメソッド(レコードを更新) @blog = Blog.find(2) @blog.update(title: 'タイトルBB') destroyメソッド(レコードを削除) @blog = Blog.find(1) @blog.destroy allメソッド(テーブル内の全レコードを取得) Blog.all firstメソッド(テーブルの最初のレコードを取得) Blog.first lastメソッド(テーブルの最後のレコードを取得) Blog.last whereメソッド(引数に条件を指定し、それに合ったレコードを取得) Blog.where(title: 'タイトルD') find_byメソッド(引数に指定した条件に最初に一致するレコードを取得) Blog.find_by(title: 'タイトルD') orderメソッド(レコードを並び替えを行う) Blog.order(content: :desc) where.notメソッド(whereメソッドの後ろに.notをつけることで引数に指定した条件に合致しないレコードを取得) Blog.where.not(title: 'タイトルD') orメソッド(2つのOR条件でレコードを取得したいときに使用する) Blog.where(title: "タイトルA").or(Blog.where(title: "タイトルE")) selectメソッド(引数にカラム名を指定することで特定のカラムのみの情報を取り出すことができる) Blog.select("id", "title") limitメソッド(取得するレコード数を制限) Blog.limit(3) offsetメソッド(limitメソッドと合わせて使用し、引数に指定した数のレコード分をスキップしてその次のレコードから取得できます。以下の例では、7レコード目から4レコード分取得) Blog.limit(4).offset(6) メソッドチェイン whereメソッドやorderメソッドは下記のようにメソッドチェインを構成できます。 以下の例ではtitleがタイトルAのレコードを作成日が新しい順で5レコード取得しています。 Blog.where(title: 'タイトルB').order(created_at: :desc).limit(5) groupメソッド(引数で指定したカラムの値が同一のものをグループ化) Blog.group(:title).count havingメソッド(groupメソッドでグループ化された対象に条件を付与できます。 以下の例では、レコード数が5より多いタイトルのレコード数のみを出力) Blog.group(:title).having('COUNT(*) > 5').count ActiveRecordのメソッド公式
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby クイズ】スペルミスで SyntaxError が出る?

Ruby についてのクイズです。 ある正しいプログラムの一箇所をスペルミスして SyntaxError が発生することはあるでしょうか。 ここで「スペルミス」とは,英単語の綴りの中のアルファベットを別のアルファベットに間違えること,とします。 なお,eval などの「文字列をスクリプトとして実行する」系のメソッドを使うと簡単に作れてしまうので,その手のメソッドは使わないという制約を設けます。 答えはスクロールで ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ こんなコードで SyntaxError が起きます。 def refined?(mod, hoge) # 定義は省略 end p defined?(String, :gsub) refined? は,あるモジュールのあるメソッドが refinements で置き換えられているかどうかを判定するメソッドのつもりです。そういうメソッドは原理的に可能ですが,中身は略します。 さて,最終行でそのメソッドを使おうとしたのですが,「R」のキーを押すつもりで斜め下の「D」を押してしまい,refined? が defined? になってしまいました。 メソッド名をスペルミスすると,NameError か NoMethodError のどちらかが出るはずですよね1。なぜ SyntaxError になるのでしょうか? 述語メソッドのような見た目の defined? は,実は演算子なのです。 そりゃ,こいつがもしメソッドだったら辻褄が合わないでしょ。 defnined? は,与えられた式がローカル変数なのか定数なのか代入式なのか(等々),はたまた未定義のものなのか,といった「種別」を返すものです。 もしメソッドだったら,defined? の呼び出しに際して,まずは与えられた式を「評価」しなくちゃなりません。評価しちゃうとオブジェクトになっちゃいますよね。それに,未定義だったら呼び出しが起こる前にエラーが出ちゃいます。 話を元に戻しましょう。 defined?(String, :gsub) の defined? は,refined? をタイポしちゃったためにメソッドではなく演算子になっちゃいました。 defined? に与える式は ( ) で囲っても構わないのですが,二つの式をカンマで区切って併記することを認めていません。だから構文エラー(SyntaxError)になる,というわけです。 復習しておくと,ローカル変数の参照とも解釈しうる名前なら NameError になり,そう解釈しえないメソッド呼び出しなら NoMethodError になる。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby クイズ】スペルミスで SyntaxError が出るか?

Ruby についてのクイズです。 ある正しいプログラムの一箇所をスペルミスして SyntaxError が発生することはあるでしょうか。 ここで「スペルミス」とは,英単語の綴りの中のアルファベットを別のアルファベットに間違えること,とします。 なお,eval などの「文字列をスクリプトとして実行する」系のメソッドを使うと簡単に作れてしまうので,その手のメソッドは使わないという制約を設けます。 答えはスクロールで ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ ⏬ こんなコードで SyntaxError が起きます。 def refined?(mod, hoge) # 定義は省略 end p defined?(String, :gsub) refined? は,あるモジュールのあるメソッドが refinements で置き換えられているかどうかを判定するメソッドのつもりです。そういうメソッドは原理的に可能ですが,中身は略します。 さて,最終行でそのメソッドを使おうとしたのですが,「R」のキーを押すつもりで斜め下の「D」を押してしまい,refined? が defined? になってしまいました。 メソッド名をスペルミスすると,NameError か NoMethodError のどちらかが出るはずですよね1。なぜ SyntaxError になるのでしょうか? 述語メソッドのような見た目の defined? は,実は演算子なのです。 そりゃ,こいつがもしメソッドだったら辻褄が合わないでしょ。 defnined? は,与えられた式がローカル変数なのか定数なのか代入式なのか(等々),はたまた未定義のものなのか,といった「種別」を返すものです。 もしメソッドだったら,defined? の呼び出しに際して,まずは与えられた式を「評価」しなくちゃなりません。評価しちゃうとオブジェクトになっちゃいますよね。それに,未定義だったら呼び出しが起こる前にエラーが出ちゃいます。 話を元に戻しましょう。 defined?(String, :gsub) の defined? は,refined? をタイポしちゃったためにメソッドではなく演算子になっちゃいました。 defined? に与える式は ( ) で囲っても構わないのですが,二つの式をカンマで区切って併記することを認めていません。だから構文エラー(SyntaxError)になる,というわけです。 復習しておくと,ローカル変数の参照とも解釈しうる名前なら NameError になり,そう解釈しえないメソッド呼び出しなら NoMethodError になる。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RubyのFiberクラス

定義  Fiber クラスは、他の言語で coroutine や semicoroutine と呼ばれる軽量スレッドであるファイバーを提供するクラスです。明示的に指定しない限りコンテキスが切り替わらないことや親子関係を持つなど、Thread クラスを提供するスレッドとは異なる挙動と持ちます。  Fiber.new メソッドにブロックを渡すと、Fiber クラスのオブジェクトであるファイバーが生成されます。このファイバーはインスタンスメソッドである resume メソッドでコンテキストがファイバーに切り替わります。また Fiber.yield メソッドで親である呼び出し元へコンテキストが切り替わります。 事例 fiber_sample.rb f = Fiber.new { print "A " Fiber.yield "B " print "C " } print "D " print f.resume print "E " 結果 [3] pry(main)> f = Fiber.new { print "A " Fiber.yield "B " print "C " } print "D " print f.resume print "E " D A B E => nil 解析  Fiber のブロック内は f.resume が呼び出された時に評価され、 Fiber.yield まで実行します。 Fiber.yield が呼ばれると、引数の"B"と共に元のコンテキストに処理を戻します。もし再び f.resumeが呼ばれると Fiber.yield の次の行から実行します。 [4] pry(main)> print f.resume C => nil
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Macbook AirにHomebrewをインストールしようとすると「/opt/homebrew/bin is not in your PATH」が発生した場合

はじめに 初めてMacを購入して、rubyの開発環境を整えようとしている中で遭遇したエラーです。 自分の記事を書く練習として、記録に残します。 progate:Rubyの開発環境を用意しよう! 結論 この方の記事で解決できました。 ありがとうございました。 Homebrewインストール時に「/opt/homebrew/bin is not in your PATH」が発生した際の解決方法 内容 rubyの開発環境を整えようと思い、ターミナルで↓を実行すると、 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" まず、macにログインするときのパスワードを入力を求められるので、入力しました。 スクリーンショット 2021-08-09 21.40.07) 入力すると ここで一度止まるのでEnterを押すと、 成功したかなと思いましたが、途中でWarningが出ていました。 brew -v をしても、 zshにコマンドないよということだったので、書き込みます。 解決 これでファイルを開いて、書き込みます。 vi ~/.zshrc #開いた後に下記を入力し、保存する。 export PATH=/opt/homebrew/bin:$PATH #保存の仕方は、;wq(shift押しながら;でwq入力する。) + ENTER 参考: viコマンド(vimコマンド)リファレンス ターミナルに戻ってきたら、 source ~/.zshrc これで環境設定終了。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RSpec内で実装しているAPIリクエストのヘッダーどうする

RSpec内で実装しているAPIリクエストのヘッダーってどうする チーム開発でRSpecでリクエストスペックを書いていたときに人によってRSpec内で定義しているAPIリクエストのヘッダーの書き方がまちまちだったので、ちょっと調べてみた話 具体的にはJSONを受け取って、JSONを返すAPIのRSpecの話 人によっては Content-Type: application/json, Accept: application/json を両方つけたり、片方だけ、またはつけていないといったケースがあった そもそもRSpecで定義したリクエストでヘッダーつけるか 細かい話ですが、下記の理由からつけたほうが良さそうかと思います テストコードを書くからにはテストコードからある程度仕様を読み取れたほうが良い クライアントがどんな形式のデータを渡すことを期待しているかは仕様としてわかったほうが良い 実装を読めばどんなデータを受け取っているかはわかるものかもしれないですが、ヘッダーはクライアントとやりとりするデータ形式を記載する場所なのでそれに従うならば書いておくべきかなぁと思いました 何をつけるべきか 今回はJSONを受け取って、JSONを返すシンプルなAPIなのでヘッダーのフィールド値は少なくとも Content-Type と Accept が必要そうです それぞれの具体的な役割を一応記載しておきます ヘッダー名 送信(クライアント側で指定可能) 受信(サーバーサイド側で指定可能) 説明 Accept ○ ブラウザが、画像の種類など扱えるメディアの種類の候補を送信する。サーバーはこのリストと自分が対応可能な種類を比較し、返すファイルの種類を決める Content-Type ○ ○ 送受信するファイル情報のMIMEタイプを指定する。 text/html, image/png など。(今回の場合は「フロントから送信するデータはJSONですよ」ということを示す情報) Content-Type と Accept どっちをつけるべきだろうか どちらもつけておいたほうが良さそうかなぁと思いました というのも今回の場合については JSONを受け取って、JSONを返すAPIをテストしているのでクライアントから受け取るデータ、サーバーから返すデータについてデータ形式を正しく指定したほうがテストとしては再現性高そうと思ったからです おまけ)RSpecでの指定のheader指定の仕方 フロントへ返すデータにJSONを指定する require "rails_helper" RSpec.describe "Widget management", :type => :request do it "creates a Widget" do headers = { "ACCEPT" => "application/json" } post "/widgets", :params => { :widget => {:name => "My Widget"} }, :headers => headers expect(response.content_type).to eq("application/json") expect(response).to have_http_status(:created) end end フロントから渡すデータにJSONを指定する require "rails_helper" RSpec.describe "Widget management", :type => :request do it "creates a Widget and redirects to the Widget's page" do headers = { "CONTENT_TYPE" => "application/json" } post "/widgets", :params => '{ "widget": { "name":"My Widget" } }', :headers => headers expect(response).to redirect_to(assigns(:widget)) end end 参考) Real World HTTP 第2版 ―歴史とコードに学ぶインターネットとウェブ技術
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

更新するべきパッケージ一覧をCSVで出力(ruby, js)

メモ Ruby $ bundle outdated --strict | sed -n "/^Gem /,\$p" | sed -e "s/ \+/,/g" 出力例 i18n-js,3.8.0,3.8.4,~> 3.8.0,default js-routes,1.4.9,2.0.8,>= 0,default json,2.3.1,2.5.1 jwt,2.2.2,2.2.3 JavaScript jqを利用する package-lock.json $ npm outdated --json | jq -r "to_entries | .[] | [.key, .value.current, .value.wanted, .value.latest] | @csv" 出力例 "i18next","19.8.7","19.9.2","20.4.0" "jest","26.6.3","26.6.3","27.0.6" ... yarn.lock $ npx yarn outdated --json | tail -n 1 | jq -r ".data.body[] | [.[0], .[1], .[2], .[3]] | @csv" 出力例 "@babel/plugin-transform-runtime","7.13.10","7.15.0","7.15.0" "@babel/preset-typescript","7.13.0","7.15.0","7.15.0" ... 1つのプロジェクト以下に複数のpackage-lock.jsonやyarn.lockがある時 $ find . -type d -name node_modules -prune -o -type f -name 'package-lock.json' -print -o -type f -name 'yarn.lock' -print | xargs -I{} dirname {} | uniq | xargs -I{} bash -c 'echo {} && cd {} && (if [ -e ./package-lock.json ]; then (npm outdated --json | jq -r "to_entries | .[] | [.key, .value.current, .value.wanted, .value.latest] | @csv"); else (npx yarn outdated --json 2>/dev/null | tail -n 1 | jq -r ".data.body[] | [.[0], .[1], .[2], .[3]] | @csv"); fi)', .value.wanted, .value.latest] | @csv"); else (npx yarn outdated --json 2>/dev/null | tail -n 1 | jq -r ".data.body[] | [.[0], .[1], .[2], .[3]] | @csv"); fi)' 出力例 ./hoge #<= ディレクトリパス "@babel/plugin-transform-runtime","7.13.10","7.15.0","7.15.0" "@babel/preset-typescript","7.13.0","7.15.0","7.15.0" ... ./hoge/foo "i18next","19.8.7","19.9.2","20.4.0" "jest","26.6.3","26.6.3","27.0.6" ... ./fuga "jest","26.6.3","26.6.3","27.0.6" ... 参考 https://bundler.io/man/bundle-outdated.1.html https://docs.npmjs.com/cli/v7/commands/npm-outdated https://classic.yarnpkg.com/en/docs/cli/outdated/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【就活】階層分析で最高の就職先を算出するアプリをつくりました【転職】

はじめに 複数の就職先候補で迷っている就活生・転職希望者の方、たくさんいらっしゃると思います。 そうした方々に向けて、選択肢の中から最高の就職先を算出するアプリをつくりました。 後悔なく意思決定するための少しでも足しになればと。 JobHunter's Choice(ジョブハンターズチョイス) https://jobhunters-choice.com サービス概要 AHP(階層分析法)という分析法を用いて複数の就職先の選択肢の中からベストなものを算出する、という手法を採用しました。 階層分析とは 複数ある選択肢のうちから最良のものを選択するための意思決定法です。 概要 例えばお部屋探しという目標に対して、評価基準(どの条件で選ぶか)と代替案(候補物件)があるとします。それらについて、 評価基準同士の重要性を比較する(ex:家賃と間取りのどちらをどの程度重視するか) 評価基準ごとに代替案同士を比較する(ex:家賃に関して物件Aと物件Bのどちらがどの程度すぐれているか) 以上をすべての組み合わせで行い、いろいろ計算すると、その人がどの評価基準をどの程度重視するかを加味した上で、それらの基準を最も満たす代替案を算出することができるわけです。 実績 工場の建設地の選定 大学教授の選抜 ソフトウェアシステムの品質の数量化 etc.. 企業活動、公共事業における幅広い分野で利用されているようです サービスの目的 で、この作業には前述の通りいろいろな計算が伴うので、表計算ソフトとかでやると相当面倒です。そもそも分析のノウハウどころか階層分析の存在すら知らない人のほうが多いですよね。 というわけで、 就職先選びにおいて、定量的なデータを提供し、かつその手間を最小限まで削減する これを目的として、サービス作成に至りました。 使い方 トップページのSTARTボタンを押すと分析開始。 STEP1 選択肢の記入 就職先の選択肢を入力します。 入力欄はデフォルトで3つですが、必要に応じて増やすことが可能。 STEP2 評価基準の選択 就職先選びの上で考慮する条件にチェックを付けます。 基準はデフォルトで出ているものの他に追加することが可能。 STEP3 評価基準の重要度評価 STEP2で選んだ基準がそれぞれペアになっており、全ての組み合わせが表示されています。 7段階評価のボタンが用意されているので、以下の基準でどちらを重視するか選びます。 1 = 左側の基準を重視する 4 = 両方同じくらい 7 = 右側の基準を重視する STEP4 選択肢の評価 評価基準ごとに、STEP1入力した選択肢がそれぞれペアになって表示されています。 その基準においてどちらの選択肢が優れている(と思う)かをSTEP4と同様に7段階評価ボタンで評価します。 結果 全て評価し終えてボタンを押すと、結果が表示されました! 階層分析によって企業ごとの評点が算出されており、総合評点が最も高い企業がベストチョイスになります。 各企業に各評価基準での評点が加算されていますが、重視する基準ほど多めに加算されているのがわかりますね。 その他の機能 分析結果はTwitterでシェア可能。 また、アカウント作成しログイン状態で使うと分析結果を保存したり過去の入力データを再利用してより作業を簡略化できます。 ↓ログイン時。過去の入力値がボタンで表示されます。 使用技術 Backend - Ruby on Rails 6.0.3 Frontend - Vue.js 2.6.12 UI - Vuetify 2.5.6, vue-chartjs 3.5.1, bootstrap 5.0.2 Infra' - AWS(EC2, RDS, Route53) WebServer - nginx 1.20.0 AppServer - unicorn 6.0.0 DB - PostgreSQL 13.x 段階評価ボタン Vuetifyのv-btn-toggleで作成。 評点は$emitで上位のコンポーネントに渡し、表示順通りに配列に格納する形で集計。 [Vue.js+Vuetify]段階評価ボタン ~評価項目の数と評価対象の数に応じて動的に表示する~ ボタンのレスポンシブ対応 [Vuetify]v-btn-toggle内のボタン幅をレスポンシブ対応 自動スクロール window.scrollByでボタン間のy座標の差分だけ自動スクロールさせます。 ボタン間の距離が固定値でなかったので、両者のy座標を毎回取得するようにしました。 // ボタンを押したら次のボタンへと自動スクロール autoScroll() { const cur = event.currentTarget.getBoundingClientRect().top // そのボタンの上端のy座標 const nxtItem = document.getElementById(`${次のボタンのID}`) // 自身の次のボタン(ターゲット) const nxt = nxtItem.getBoundingClientRect().top // ターゲットの上端のy座標 window.scrollBy(0, nxt-cur) //ターゲットと自身のy座標の差分だけスクロール } フォームの追加 フォームでバインドしているalternativesの初期値を長さ3のnullの配列にしているためデフォルトでフォームが3つイテレートされています。 この配列に新たにnullを加えるとフォームが追加され、過去の入力値を再利用するときはこの配列にその入力値を追加しています。 <template> ... <input v-for="(item, index) in alternatives" :key="index" v-model="alternatives[index]" > ... </template> <script> ... data() { return { alternatives: [null, null, null], ... </script> チェックボックスの追加 criteriaの要素がデフォルトで表示されている項目で、チェックされた要素はselectedCriteriaに格納されます。 項目を追加したり、過去のチェック項目を再利用するときは、criteriaとselectedCriteriaの両方にその項目が追加されることでチェックが入った状態で項目が追加されます。 <template> ... <v-checkbox v-for="(item, index) in criteria" :key="item" v-model="selectedCriteria" :value="item" :label="item" /> ... </template> <script> ... data() { return { criteria: [ '労働時間', '通勤時間', '雇用の安定', '仕事の裁量権', '社会への貢献度', ... ], selectedCriteria: [], ... おわりに できる限りユーザーの手数を減らすことを意識しました。このアプリでかなり時短になるはずです(当社比) まあ就職先の優先順位つけるだけっちゃつけるだけですが、わりと楽しくポチポチできるんじゃないでしょうか。 ジョブハンターの皆さんぜひ使ってみてください! 引用文献 [Vue.js+Vuetify]段階評価ボタン ~評価項目の数と評価対象の数に応じて動的に表示する~ [Vuetify]v-btn-toggle内のボタン幅をレスポンシブ対応 階層分析法
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

満経過月数を計算するロジック(Ruby)

経過月数(満月)を計算するロジックについて解説します。(あまり記事がなかった) 具体的に言うと以下のようなロジック。 start:2021年01月15日 end:2021年02月14日 →経過月数0を返す start:2021年01月15日 end:2021年02月15日 →経過月数1を返す start:2021年01月15日 end:2022年03月15日 →経過月数14を返す コード IN:開始日(start),終了日(end) :data型 OUT:満経過月数 def calculation_diff_months(start,end) (end.year - start.year) * 12 + end.month - start.month - (end.day >= start.day ? 0 : 1) end コードの解説 ■年の計算 (end.year - start.year) * 12 → 年の差分を求めて月変換 ■月の計算 end.month - start.month  → そのまま月の差分を求める ここまではシンプル。 ■日付の計算 (end.day >= start.day ? 0 : 1) 終了の日付>=開始の日付の場合はそのまま月数を出したいので0で計算 終了の日付<開始の日付の場合は月数をマイナス-1にしたいので1で計算 閏年のこととか考えて最初、戸惑いましたが以外とシンプルに実装できました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

has_one型のデータを表示させたくて

こんにちは!! ユーザー登録が完了したら、ライブ情報を 投稿できるアプリを作成中です。 今回はhas_one型のデータの表示方法について 自分のメモ用としてアウトプットしていきたいです。 アソシエーション 作成中のアプリには3つのエンティティが存在します。 deviseを使って実装したユーザー登録をするadmin_usersテーブル、 ユーザーの詳細なプロフィールを保存するadmin_profilesテーブル、 ライブ情報を投稿できるeventsテーブルが存在します。 3つのテーブルのアソシエーションは以下の通りです。 Admin_user has_one admin_profiles. Admin_user has_many events. Admin_profile belongs_to admin_user. Event belongs_to admin_user. ユーザー登録はウィザード形式で保存する為、 AdminProfileモデルに belongs_to :admin_user, optional: true has_one_attached :admin_image と記述しました。 また、ライブハウスの画像を保存したかったので、 Active Strageを利用してadmin_imageとしました。 実装したいこと 訪れたユーザーが、ライブハウスの詳細ページ(admin_users/show)にいくと ユーザーの詳細な情報(admin_profilesテーブルに保存された情報)を 見ることができるように試みました。 admin_users_controllerには以下のように記述 class AdminUsersController < ApplicationController def show admin_user = AdminUser.find(params[:id]) @store_name = admin_user.store_name @admin_profile = admin_user.admin_profile end end NoMethodError ウキウキでブラウザを更新してみると以下の表示が。 ふざけやがって。 ナンジャそりゃ。 NoMethodErrorですって。 悩みすぎてrubyが嫌いになったのでやめてしまおうかと考えてました。 optional trueによる弊害 今回のエラーはウィザード形式でbelongs_toの外部キーのnilを許可する optional: trueを記述したことで起こったようです。 ターミナルでコンソールを立ち上げて pluckを確かめてみると [1] pry(main)> AdminUser.pluck(:id) (0.3ms) SELECT `admin_users`.`id` FROM `admin_users` => [5, 16, 7, 14, 12, 15, 6, 8, 13, 1, 11, 9, 4, 18, 3, 17, 2, 10] [2] pry(main)> AdminProfile.pluck(:admin_user_id) (0.3ms) SELECT `admin_profiles`.`admin_user_id` FROM `admin_profiles` => [4, 6, 7, 13, 14, 15, 17, 18] admin_userとadmin_profileで紐付けられていないidが いますねえ。 ぼっちを使う もう今更ユーザー登録をウィザード形式で実装してたのを やめて実装し直すとかめんどくさいんでやりたくなかったので ボッチ演算子を使用することにしました。 <div class="profile-contents"> <p class="shop-name"><%= @store_name %></p> <p class="postal-code"> 〒 <%= @admin_profile&.postal_code %> </p> <p class="prefecture-text"> <%= @admin_profile&.prefecture&.name %><%= @admin_profile&.municipality %> </p> <p class="address-text"> <%= @admin_profile&.address %><%= @admin_profile&.building_name %> </p> <%= link_to "Google mapで見る", "#", class:"map-link" %> <p class="tel"> TEL: <%= link_to @admin_profile&.phone_number, "#", class:"phone-number" %> </p> <p class="admin-profile"> <%= @admin_profile&.profile %> </p> </div> レシーバーであるオブジェクトに対してあるメソッドを実行する時にエラーを出さずにメソッドを 表示することができるぼっち演算子を使うことで解消できました。 rubyおもしろい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RubyでPayPayのAPIを呼んでみる

目的 PayPayのAPIをRubyで使いたいです。しかし公式のSDKはPython, Node, PHP, JavaしかないのでREST APIを叩くことにします。リファレンスはこちらです。APIキーの取得などはDeveloperサイトで確認してください。 プログラム プログラムはNodeのSDKのコードを参考に作りました。リファレンスもかなり詳細に書いてあるので助かります。APIはQRコードの作成だけ実装してあります。 Gemfile # frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem 'httpclient' paypay.rb require 'base64' require 'json' require 'openssl' require 'securerandom' require 'time' require 'httpclient' module PayPay PROD = 'api.paypay.ne.jp' STAGING = 'stg-api.sandbox.paypay.ne.jp' PERF_MODE = 'perf-api.paypay.ne.jp' class QrCodeCreateBuilder def initialize() @result = { amount: { amount: 0, currency: 'JPY', }, orderItems: [], metadata: {}, codeType: 'ORDER_QR', storeInfo: 'store', storeId: '1', terminalId: '1', requestedAt: Time.now.to_i, redirectUrl: 'https://paypay.ne.jp/', redirectType: 'WEB_LINK', isAuthorization: false, authorizationExpiry: Time.now.to_i + 60, } end def merchantPaymentId(uuid = nil) @result["merchantPaymentId"] = uuid.nil? ? SecureRandom::uuid : uuid end def addItem(name, category, quantity, product_id, unit_amount) item = { name: name, category: category, quantity: quantity, productId: product_id, unitPrice: { amound: unit_amount, currency: 'JPY', }, } @result[:orderItems] << item @result[:amount][:amount] = @result[:amount][:amount] + quantity * unit_amount end def finish() @result end end class Client def initialize(api_key, api_secret, merchant_id, production_flag = false, pref_flag = false) @api_key = api_key @api_secret = api_secret @merchant_id = merchant_id @host_name = 'https://' + if pref_flag PERF_MODE elsif production_flag PROD else STAGING end end def qr_code_create(params) method = 'POST' url = '/v2/codes' opa, content_type = PayPay.calc(@api_key, @api_secret, url, method, params) client = HTTPClient.new() #client.debug_dev = STDOUT client.post(@host_name + url, params.to_json, {"Authorization" => opa, "X-ASSUME-MERCHANT" => @merchant_id, 'Content-Type' => content_type}) end end def self.calc(api_key, api_secret, url, method, body) nonce = SecureRandom.alphanumeric(8) epoch = Time.now.to_i.to_s payload, content_type = if body.nil? || body == "" ['empty', 'empty'] else content_type = 'application/json;charset=UTF-8;' [ Base64.strict_encode64( OpenSSL::Digest::MD5.digest( content_type + body.to_json ) ), content_type ] end hashed64 = Base64.strict_encode64( OpenSSL::HMAC.digest( 'sha256', api_secret, [url, method, nonce, epoch, content_type, payload].join("\n") ) ) ["hmac OPA-Auth:#{[api_key, hashed64, nonce, epoch, payload].join(":")}", content_type] end end main.rb require './paypay' builder = PayPay::QrCodeCreateBuilder.new() builder.merchantPaymentId() builder.addItem("ame", "sugger", 1, "1", 1) client = PayPay::Client.new(ENV['API_KEY'], ENV['API_SECRET'], '12345') response = client.qr_code_create(builder.finish()) pp response まとめ 当初RubyとPayPayでぐぐったら誰かサンプルくらい書いてるかと思ったけど全然書いて無くて涙目でした。リファレンスがちゃんとしているので実装しやすいREST APIだと思います。もしお仕事でちゃんと使うなら他のSDKと同等くらいにしてgemで公開しようかと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】Time.currentメソッドを使って簡単に時間表示をする方法

対象者 時間の表示方法を知りたい方 目的 Time.currentメソッドを使って時間を表示する 実際の手順と実例 1.結論 Time.currentメソッドを使えば簡単に時間が表示できます。 rails cで確認すると $ rails c Running via Spring preloader in process 6425 Loading development environment (Rails 5.2.6) [1] pry(main)> Time.current => Sat, 14 Aug 2021 23:20:51 UTC +00:00 [2] pry(main)> 上記のように今日の時間が取得できます。 2.応用編 Time.current.all_month #今月 Time.current.all_week #今週 Time.current.all_day #今日 参照 時刻や日付を扱うメソッドの基本情報まとめ【Ruby】【Rails】 投稿者コメント 時間どのように表示すればいいんだろうって前に悩んでたんですけど、これで一発なんですね。。。勉強になりました。。。 My Profile プログラミング学習歴3ヶ月目のアカウントです! プログラミングスクールで学んだ内容や自分が躓いた箇所等のアウトプットの為に発信しています。 また、プログラミング初学者の方にわかりやすく、簡潔にまとめて情報共有できればと考えています。 もし、投稿した記事の中に誤り等ございましたら、コメント欄でご教授いただけると幸いです。 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]redirect_toとrenderの違いについて

はじめに 本記事では、redirectとrenderの違いについて記述しています。 私自身何気なく、コントローラーなどに記述しておりましたが、 改めて振り返りアウトプットしたいと思います。 redirectとrenderの違い redirect_to ↓ ルーティング ↓ コントローラー ↓ ビュー render ↓ ビュー 随分あっさり書きましたが、このような違いです。 redirect_to redirect_toは新しくリクエストが送られてきた時と同じ流れになります。 そのため、同様にルーティング→コントローラー→ビューの流れになります。 render renderは、特にリクエストをされることがなく、そのまま直接ビューにいきます。 redirect_toはコントローラーへ! renderはビューへ!ということですね。 例え class MessagesController < ApplicationController . . 省略 . . def create @room = Room.find(params[:room_id]) @message = @room.messages.new(message_params) if @message.save redirect_to room_messages_path(@room)        ←ここ else @messages = @room.messages.includes(:user) render :index        ←ここ end end . . "省略" . . end redirect_toは、 データを送信する時(例えば、記事を投稿できた時、記事を編集できた時) の場合などに使用されています。 今回の場合ですと、 メッセージが送れたら、ルーティング→コントローラー→ビューroom_messages_path(@room)ですね。 コントローラーへいくことでとモデルとも連携ができ、メッセージを情報として保存することもできます。(メッセージのテーブルがあれば) renderは、 データの送信に失敗した時(例えば、なんらかの項目が空白でログインができなかった時、記事が投稿できない時) の場合などに使用されています。 今回の場合ですと、 送信に失敗したら、ビューへindexですね。 メッセージ送信に失敗しているので、 イジワルな言い方をするともっかいやり直し〜(ビューへ)という感じですね? 終わりに インプットの段階では、???でしたが、 簡単なアプリケーションで試してみると理解は深まると思い、コードを記述してみました。 他に、図を用いて理解を深めてらっしゃる記事もありましたので、 こちらを参考にしながらだと、なお理解は深まると思います。 分かりやすい図がある記事 RailsGuide 明日は日曜日ですが、コツコツがんばります!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【小ネタ】Ruby で new するたびにクラスインスタンス変数をインクリメントして、インスタンス変数にぶち込む

class BankAccount @current_account_number = 0 class << self attr_reader :current_account_number end def self.new(name) super(name, @current_account_number += 1) end attr_accessor :name attr_reader :account_number def initialize(name, account_number) @account_number = account_number @name = name end end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む