20210513のRailsに関する記事は21件です。

知らない人に勝手に出品した商品を編集させない!

はじめに 現在フリマアプリを作成中です。 商品の出品者ではない人が編集できるURLを直接打ち込み、編集できるという問題を解決していきます。 想像してみて下さい。 自分が30,000円で出品した商品が勝手に1,000円に編集されて売れてしまった場合... そんな事にならないように利用して下さるユーザーが安心して使えるように記述していきましょう! 現在のコントローラの状況 itemテーブルには出品された商品情報が入っています。 (名前・値段・商品説明・商品状態など) 編集できるeditアクションと更新ができるpdateアクションを見ていきます。 def edit @item = Item.find(params[:id]) end def update if @item.update(item_params) redirect_to item_path else render :edit end editアクションでは編集したいレコードを@itemに代入し、ビューに受け渡すことで編集画面で利用できるようにします。 findはデータベースからデータを取り出したり、検索したりするためのメソッドです。 idを取得して編集ページは/items/[:id]/editとなります。 今のままでは直接上記のURLを打ち込むと出品者ではない人が編集できてしまいます。 unless文とdeviseのヘルパーメソッド! まずはunless文の紹介. if文が条件式がtrueの時に実行したのに対し、unless文は条件式がfalseの時に実行する構文です。 そしてdeviseメソッド current_user #deviseのヘルパーメソッドde"現在ログインしているユーザー"という意味 current_user == @item.user #現在ログインしているユーザーは商品を出品ユーザーと同じという意味 この2つを用いて記述すると以下になります def edit @item = Item.find(params[:id]) #もし、現在ログインしているユーザーは商品を出品ユーザーではなかった時、トップページに遷移する unless current_user == @item.user redirect_to root_path end end def update if @item.update(item_params) redirect_to item_path else render :edit end このような記述になります。 もちろんこれはupdateアクションにも使うのでbefore_actionでまとめて記述するとより可読性が上がります。 before_action :contributor_confirmation, only: [:edit, :update] def edit end def update if @item.update(item_params) redirect_to item_path else render :edit end end private def contributor_confirmation redirect_to root_path unless @item.user == current_user end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

総合振込の全銀フォーマットファイルを作成する方法(Ruby)

総合振込で使用する「全銀フォーマット(全銀協規定形式)」のファイルを作成する方法を雑にまとめてました。 全銀フォーマットはどの銀行も似通っているかと思いますが、実装する際は必ず該当銀行の資料を読み込む事をお勧めします。 ※ 下記は GMOあおぞらネット銀行 のフォーマットになります。だいぶ愚直に書いた例です。 File.open("payout-example.txt", "w", encoding: "Shift_JIS") { |f| # 1. ヘッダー・レコード h_01 = 1 # データ区分(固定値) h_02 = 21 # 種別コード(固定値) h_03 = 0 # コード区分(固定値) h_04 = 9999999999 # 振込依頼人コード(固定値) h_05 = "#{振込依頼人名}".ljust(40) # 振込依頼人名 h_06 = Date.today.strftime("%m%d") # 振込実施日 h_07 = "0310" # 仕向銀行番号(固定値) h_08 = "ジーエムオーアオゾラネツト" # 仕向銀行名(固定値) h_09 = "#{仕向支店番号}" # 仕向支店番号 h_10 = "#{仕向支店名}".ljust(15) # 仕向支店名 h_11 = 1 # 預金種目(依頼人)(固定値) h_12 = "#{口座番号}" # 口座番号(依頼人) h_13 = "".ljust(17) # ダミー f.write("#{h_01}#{h_02}#{h_03}#{h_04}#{h_05}#{h_06}#{h_07}#{h_08}#{h_09}#{h_10}#{h_11}#{h_12}#{h_13}\r\n") # 2. データ・レコード payouts = ... payouts.each do |payout| d_01 = 2 # データ区分(固定値) d_02 = "#{payout.被仕向銀行番号}".rjust(4, "0") # 被仕向銀行番号 d_03 = "".ljust(15) # 被仕向銀行名 d_04 = "#{payout.被仕向支店番号}".rjust(3, "0") # 被仕向支店番号 d_05 = "".ljust(15) # 被仕向支店名 d_06 = "".ljust(4) # 統一手形交換所番号(固定値) d_07 = 1 # 預金種目 d_08 = "#{payout.口座番号}".rjust(7, "0") # 口座番号 d_09 = "#{payout.受取人名}".ljust(30) # 受取人名 d_10 = "#{payout.振込金額}".rjust(10, "0") # 振込金額 d_11 = 1 # 新規コード d_12 = "".ljust(10) # 顧客コード1 d_13 = "".ljust(10) # 顧客コード2 d_14 = "".ljust(1) # 振込指定区分 d_15 = "".ljust(1) # 識別表示 d_16 = "".ljust(7) # ダミー f.write("#{d_01}#{d_02}#{d_03}#{d_04}#{d_05}#{d_06}#{d_07}#{d_08}#{d_09}#{d_10}#{d_11}#{d_12}#{d_13}#{d_14}#{d_15}#{d_16}\r\n") end # 3. トレーラ・レコード t_01 = 8 # データ区分(固定値) t_02 = payouts.count.to_s.rjust(6, "0") # 合計件数 t_03 = payouts.sum(:振込金額).to_s.rjust(12, "0") # 合計金額 t_04 = "".ljust(101) # ダミー f.write("#{t_01}#{t_02}#{t_03}#{t_04}\r\n") # 4. エンド・レコード e_01 = 9 # データ区分(固定値) e_02 = "".ljust(119) # ダミー f.write("#{e_01}#{e_02}\r\n") } 参照 総合振込 -アップロードファイル作成ガイド - Ver 1.0.4 | GMOあおぞらネット銀行 全銀協規定形式(振込ファイル)| 住信SBIネット銀行
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

deviseを使った新規登録で、sign upはできるがloginができない時の解決法

deviseパッケージには、デフォルトでemailとpasswordでログインしてくださいよってゆう設定がされている db/migrate/(年月日時分秒)_devise_create_users.rb ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" sign inの時には、名前、メール、パスワードを入力して、サインイン後の画面を一覧ページにしておけば、遷移できた。(ここでデータベースには名前も保存されている) しかし、一度ログアウトして、もう一度ログインするときにログインできなかったのは、Viewでは入力フォームをnameとpasswordとしていたが、実際バックエンドの処理でdeviseパッケージがログインに必要としていた値は、emailとpasswordのままになっていたため、ログインできなかった。 ここを変更しないといけない 行った変更は 「application_controller.rb」の以下の部分のkeyに:emailを追加 def configure_permitted_parameters     devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :email])   end 次に config/initializers/devise.rbの49行目あたりの[:email]を[:name]に変換 config.authentication_keys = [:name] これでサーバーを再起動させてログインしてみたら成功した たぶん認証に使うkeyをemailからnameに変更したからいけたんだと思う
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】郵便番号にバリデーションをかけたい!【正規表現】

はじめに Ruby on Railsの学習中です。携帯番号は下記の参考文献と出会えたので解決しましたが、正規表現で郵便番号にいい感じのバリデーションをかけたいと思ったのですが、なかなかベストな文献が見当たりませんでした。そこでこちらの文献を参考に郵便番号正規表現を作成しました。 参考文献 テストするならココ 今回の理想 郵便番号は以下ならOKとします。 000-0000(数字7桁と間にハイフンが含まれる) 0000000(数字7ケタのみ) テスト環境 Rails 5.2.5 ruby 2.6.3 ①正規表現を作る 郵便番号の正規表現 \A\d{3}[-]?\d{4}\z これで\Aから始まり\zに終わる\d{3}3桁と\d{4}4桁の数字で[-]?間にハイフンが入っていても入ってなくてもOK という意味になります。 ②正規表現を試す rubular.comに移動 ①Your regular expression:に先ほどの正規表現を記載する ②Your test string:にテストしたい文字列を入れる ③Match result: マッチするか確認する ③モデルに実装する models/user.rb VALID_POSTAL_CODE_REGEX = /\A\d{3}[-]?\d{4}\z/ #正規表現を//で/正規表現/とサンドすることを忘れないよう validates :postal_code, presence: true, format: { with: VALID_POSTAL_CODE_REGEX } 以上で実装できました。 正規表現はPHP: preg_match() で何回か触れたことはありましたが、すぐ忘れるし、まだまだゼロから手書きはできません... 何かから見て学び、応用を効かせて、rubular.comで試すというルーティンで今後も正規表現と向き合って行こうと思います! ちなみにハイフンの有り無しはDB上では統一したいのでjavascriptのinputイベントで足すという方法を考えています。(ということはハイフンありの完全一致のバリデーションでもいいのでは?)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails6】新・JavaScriptによる「入力フォームの内容のリアルタイムチェック機能」の実装例

以前、【Rails6】JavaScriptによる「入力フォームの内容のリアルタイムチェック機能」の実装例という記事で、入力フォームのリアルタイムチェック機能の実装方法を紹介しましたが、この実装方法には以下の問題がありました。 エラーメッセージのタグをhiddenで隠しているので、フォームの中に不自然な空白がある 複数のタイプのエラーメッセージを表示しようとすると空白がさらに大きくなってしまう 今回はこれを改善し、しかもパワーアップしました。 前回と同様にjQueryのようなライブラリは使用せず、そのままのJavaScriptで実装したことが今回もポイントです。 実行環境 Rails 6.0.3.6 動作確認 今回のリアルタイムチェック機能の仕様は以下の通りです。 入力された値によって以下のエラーメッセージが表示される 半角数字以外の場合→「価格は半角数字で入力してください」 300〜9,999,999の範囲外の場合→「価格は300〜9,999,999の範囲で設定してください」 正しい値を入力するとメッセージが非表示になる Javascriptのコード メインとなるJavaScriptのコードは以下の通りです。 app/javascript/validation.js //validationイベントを定義 const validation = () => { //エラーメッセージを表示するための要素を取得して変数化 const priceErrorElement = document.getElementById("price-error"); //フォームの値が入る要素を取得して変数化 const itemPrice = document.getElementById("item-price"); //ここから半角数字での入力を促すイベント //半角数字でないものにマッチする正規表現を変数化 const pricePattern = /^\d+$/; //入力フォームでキーが離されたときにイベントが発生 itemPrice.addEventListener("keyup", e => { //idがprice-character-errorの要素(エラーメッセージ)を取得して変数化 const errorMessageCharacter = document.getElementById("price-character-error"); //入力された値が正規表現にマッチしている or 空白のとき if (pricePattern.test(itemPrice.value) || itemPrice.value == "") { //エラーメッセージが存在しているとき if (errorMessageCharacter != null) { //エラーメッセージを削除 errorMessageCharacter.remove(); } //入力された値が正規表現にマッチしていないとき } else { //エラーメッセージが存在していないとき if (errorMessageCharacter === null) { //エラーメッセージを挿入 priceErrorElement.insertAdjacentHTML('afterend', '<div id="price-character-error" class="price-error">価格は半角数字で入力してください</div>' ); } } }); //ここまで半角数字での入力を促すイベント //ここから300〜9,999,999の範囲での入力を促すイベント //最小値と最大値を変数化 const minimumPrice = 300; const maximumPrice = 9999999; //入力フォームでキーが離されたときにイベントが発生 itemPrice.addEventListener("keyup", e => { //idがprice-range-errorの要素(エラーメッセージ)を取得して変数化 const rangeErrorMessage = document.getElementById("price-range-error"); //入力された値が300より小さい or 9,999,999より大きいとき if (itemPrice.value < minimumPrice || itemPrice.value > maximumPrice ) { //エラーメッセージが存在していないとき if (rangeErrorMessage === null) { //エラーメッセージを挿入 priceErrorElement.insertAdjacentHTML('afterend', '<div id="price-range-error" class="price-error">価格は300〜9,999,999の範囲で設定してください</div>' ); } //入力された値が300以上 or 9,999,999以下のとき } else { //エラーメッセージの要素が存在しているとき if (rangeErrorMessage != null) { //エラーメッセージを削除 rangeErrorMessage.remove(); } } }); //ここまで300〜9,999,999の範囲での入力を促すイベント } //ページが読み込まれた(load)ときに、validationイベントを実行 window.addEventListener("load", validation) 上記validation.jsをapplication.jsで読み込むことを忘れないようにしましょう。 app/javascript/packs/application.js require("../validation") Viewのコード エラーメッセージを入れたい箇所に以下の要素を記述します。 new.html.erb <div id="price-error"></div>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

新method追加

member 「member」とは、「resources以外のメソッドを追加したい」且つ「id情報を伴うURIを生成したい」時に使用します。使い方は以下の通りです。 memberの使い方① member do HTTPメソッド ‘アクション名’ end ただ、追加したいアクションが1つだけの時は以下のように記述出来ます。 memberの使い方② HTTPメソッド ‘アクション名’ , on: :member 今回は「orderメソッド(購入機能のメソッド)」に対してmemberを使います。 それではルーティングを設定しましょう。 ルーティングを設定しましょう ルーティングを以下のように設定してください。 config/routes.rb Rails.application.routes.draw do devise_for :users root to: "items#index" resources :items do resources :purchases, only: [:index, :create] end end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Errno::ENOSPCが表示された時

rails sでサーバーを立ち上げようとすると、Errno::ENOSPCの表示が。 エラー内容 まずこのエラーの内容を確認すると、「No space left on device」の文字が確認でき、これは容量不足を示しています。 こいつが起きると何も操作ができなくなってしまい、だいぶやっかいです。 この容量不足には、ディスクの容量不足とinodeの容量不足の2パターンがあります。 解決に向けて  ※出力結果は例となります。 まずは以下コマンドにて、現在の使用容量を確認します。 ターミナル $ df >ファイルシス 1K-ブロック 使用 使用可 使用% マウント位置 devtmpfs 492676 0 492676 0% /dev tmpfs 503448 0 503448 0% /dev/shm tmpfs 503448 472 502976 1% /run tmpfs 503448 0 503448 0% /sys/fs/cgroup /dev/xvda1 8376300 5655364 2720936 68% / tmpfs 100692 0 100692 0% /run/user/1000 ここでは使用%という部分が、現在のディスク使用率を表示しています。 ここが100%になっていれば、ディスク容量が一杯になっています。 ※ここでは容量不足解消後の出力結果なので、100%のものはありません。 続いてinodeの容量確認ですが、こちらは先ほどのコマンドに-iを追加します。 ターミナル $ df -i >ファイルシス Iノード I使用 I残り I使用% マウント位置 devtmpfs 123169 284 122885 1% /dev tmpfs 125862 2 125860 1% /dev/shm tmpfs 125862 373 125489 1% /run tmpfs 125862 16 125846 1% /sys/fs/cgroup /dev/xvda1 4193216 127452 406576 4% / tmpfs 125862 1 125861 1% /run/user/1000 こちらもI使用%という部分を確認して、ここが100%になっていれば、inodeの容量不足となります。 上記コマンドで容量不足の確認ができたところで、不要なファイルを削除していきます。 まず、どのファイルが容量を圧迫しているか確認する必要があるので、以下コマンドで確認します。 ターミナル $ find / -xdev -type f | cut -d "/" -f 2 | sort | uniq -c | sort -nr > 59177 usr 33328 home 4025 var 526 etc 16 opt 13 boot 1 swapfile1 1 .autorelabel こんな感じで、左側にファイル数、右側にディレクトリが表示されるかと思います。 ファイル数が多いものが容量を圧迫しているので、更にその中で圧迫の原因となっているものを探っていきます。 先ほどの出力結果だと、usrディレクトリのファイル数が多かったので、これを更に深めていきます。(findの後に確認したいディレクトリ名を記載します。) ターミナル $ find /usr -xdev -type f | cut -d "/" -f 3 | sort | uniq -c | sort -nr > 28277 share 17869 lib 7387 lib64 3676 include 929 bin 526 local 377 sbin 136 libexec ここではディレクトリ別のファイルが表示されています。この操作によって、ファイル数が多く、不要なディレクトリを探します。 上記コマンドでディレクトリを特定できれば、次はそれを削除していきます。 削除する時は、以下コマンドを使用します。 ターミナル $ sudo rm -rf ディレクトリ名 例えば先ほどの出力結果だと、usr/shareが多かったので、これを削除する場合、 「$ sudo rm -rf usr/share」となります。 このコマンドは-rfがついているため、コマンドを実行すると強制的に削除が実施されるので、必要なファイルを削除しないようにご注意ください。 不要なファイルを削除したらもう一度、「df (-i)」コマンドにて使用率を確認して、使用容量が減っているか確認してみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vite Ruby で 爆速で Rails + Vue3 + TypeScript 環境を作成する!

Introduction みなさん、Vitejs というのはご存知でしょうか? https://vitejs.dev/ 手間のかかるフロントエンド環境の構築をまとめてやってくれる優れものです。 お好みのフレームワークと開発言語(js or ts)を選択すれば爆速で構築してくれます。 こちらの Ruby統合環境 (Vite Ruby) を作成されている方がいるようでしたので 早速試していこうと思います♪ (個人的には Rails + Vue3 環境が素早く構築できると 嬉C) 初期リリースは2021年1月のようですね。 ? Commits on Jan 19, 2021 https://github.com/ElMassimo/vite_ruby/releases/tag/v1.0.0 Getting Started 早速、試そうとドキュメントを漁ります。 https://vite-ruby.netlify.app/guide/ これ見た限り、既存のRailsプロジェクトにインストールするスタイルみたいですね とりあえず、通常の Rails + Vue 構成でセットアップしてみますか Railsプロジェクトの作成 # 個人の環境に合わせてください $ mkdir -p ~/projects/vite_ruby_sample $ cd ~/projects/vite_ruby_sample # オプションはお好みで... (今回は Rails + Mysql + Vue) $ bundle exec rails new . --database=mysql --webpack=vue --skip-turbolinks --skip-test-unit --skip-coffee --skip-test --skip-active-storage # とりあえずDBのセットアップもやっておく $ mysql.start $ bin/rails db:prepare ViteRubyのインストール vite-rubyのinstallationに従います。 https://vite-ruby.netlify.app/guide/#installation-%F0%9F%92%BF Gemfile gem 'vite_rails' $ bundle $ bundle exec vite install Creating binstub Check that your vite.json configuration file is available in the load path: No such file or directory @ rb_sysopen - ~/projects/vite_ruby_sample/config/vite.json Creating configuration files Installing sample files Installing js dependencies yarn add v1.22.10 [1/4] Resolving packages... [2/4] Fetching packages... [3/4] Linking dependencies... [4/4] Building fresh packages... success Saved lockfile. success Saved 14 new dependencies. info Direct dependencies ├─ vite-plugin-ruby@2.0.4 └─ vite@2.3.2 info All dependencies ├─ @nodelib/fs.scandir@2.1.4 ├─ @nodelib/fs.stat@2.0.4 ├─ @nodelib/fs.walk@1.2.6 ├─ esbuild@0.11.20 ├─ fast-glob@3.2.5 ├─ fastq@1.11.0 ├─ merge2@1.4.1 ├─ nanoid@3.1.23 ├─ queue-microtask@1.2.3 ├─ reusify@1.0.4 ├─ rollup@2.47.0 ├─ run-parallel@1.2.0 ├─ vite-plugin-ruby@2.0.4 └─ vite@2.3.2 Done in 12.04s. Could not install JS dependencies. npx: 1個のパッケージを3.803秒でインストールしました。 warning " > vue-loader@15.9.7" has unmet peer dependency "css-loader@*". Adding files to .gitignore Vite ⚡️ Ruby successfully installed! ? これで vitejs もインストールされるようですね。 【追加されたファイル】 bin/vite vite.config.ts config/vite.json 【変更があったファイル】 app/javascript/entrypoints/application.js // To see this message, add the following to the `<head>` section in your // views/layouts/application.html.erb // // <%= vite_client_tag %> // <%= vite_javascript_tag 'application' %> console.log('Vite ⚡️ Rails') // If using a TypeScript entrypoint file: // <%= vite_typescript_tag 'application.jsx' %> // // If you want to use .jsx or .tsx, add the extension: // <%= vite_javascript_tag 'application.jsx' %> console.log('Visit the guide for more information: ', 'https://vite-ruby.netlify.app/guide/rails') // Example: Load Rails libraries in Vite. // // import '@rails/ujs' // // import Turbolinks from 'turbolinks' // import ActiveStorage from '@rails/activestorage' // // // Import all channels. // import.meta.globEager('./**/*_channel.js') // // Turbolinks.start() // ActiveStorage.start() // Example: Import a stylesheet in app/frontend/index.css // import '~/index.css' app/views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title>ViteRubySample</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all' %> <%= javascript_pack_tag 'application' %> <%= vite_client_tag %> <%= vite_javascript_tag 'application' %> <!-- If using a TypeScript entrypoint file: vite_typescript_tag 'application' If using a .jsx or .tsx entrypoint, add the extension: vite_javascript_tag 'application.jsx' Visit the guide for more information: https://vite-ruby.netlify.app/guide/rails --> </head> <body> <%= yield %> </body> </html> Viteのセットアップ とのことで、上記からプラグインを選んでインストールします 今回は Vue3 を利用するので下記を選択しました $ yarn add -D @vitejs/plugin-vue その他依存関係もインストールします $ yarn add -D @vue/compiler-sfc $ yarn add -D typescript # Rails作成時のvueが2系なのでアップデート $ yarn add vue@next # vue3 vite.config.ts import { defineConfig } from 'vite' import RubyPlugin from 'vite-plugin-ruby' import vue from '@vitejs/plugin-vue' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ RubyPlugin(), vue() ], }) とりあえず実行してみる 下記によると bin/vite でviteサーバーを起動できるようなので試してみましょう! https://vite-ruby.netlify.app/guide/development.html#developing-with-vite $ bin/vite Commands: vite build # Bundle all entrypoints using Vite. vite clobber # Clear the Vite cache, temp files, and builds vite dev # Start the Vite development server. vite install # Performs the initial configuration setup to get started with Vite Ruby. vite version # Print version っと、さらにオプションがある模様ですね $ bin/vite dev vite v2.3.2 dev server running at: > Local: http://localhost:3036/vite-dev/ > Network: use `--host` to expose ready in 404ms. 起動したみたいですが、よくわからないですね? (webpack-dev-serverみたいなものと思っておきましょう) 気にせず、いつものRails&Vueのようにアクション作成しましょうか... layouts/application.html.erbでコンパイルしたjsが返るようになってますので、下記だけでいいですね。 $ bin/rails g controller vue index とりあえず、これだけ。 さっそく、実行してみましょう! $ bin/rails server -b 0.0.0.0 -p 3000 => Booting Puma => Rails 6.1.3.2 application starting in development => Run `bin/rails server --help` for more startup options Puma starting in single mode... * Puma version: 5.3.1 (ruby 2.7.2-p137) ("Sweetnighter") * Min threads: 5 * Max threads: 5 * Environment: development * PID: 49577 * Listening on http://0.0.0.0:3000 Use Ctrl-C to stop $ open 'http://0.0.0.0:3000/vue/index' 下記のように表示されました! ちゃんと 'Vite ⚡️ Rails' と表示されてます 接続は大丈夫そうですね! Vueを表示してみる いよいよ本番と、vue3 + ts で記述して表示できるか試してみましょう! app/views/vue/index.html.erb <div id="app"></div> app/javascript/entrypoints/application.js import { createApp } from 'vue' import App from '../app.vue' document.addEventListener('DOMContentLoaded', () => { createApp(App).mount('#app') }) app/javascript/app.vue <template> <p>{{ state.message }}</p> </template> <script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ name: 'App', setup() { return { state: { message: "Hello Vue3 + TypeScript!" } } } }) </script> <style scoped> p { font-size: 2em; text-align: center; } </style> ページを更新して、いざ、表示! おぉー、表示されましたね。 これで気軽に Rails + Vue3 + TypeScript 環境で開発できますね! まとめ 今回は、爆速で Rails + Vue3 + TypeScript 環境 を構築してみました Vite Ruby を利用することで Rails 環境でも vitejs が気軽に導入できるようになりました 移り変わりの早いフロントエンドに対応していくためにも Vite Ruby で Rails環境を構築してみてはいかがでしょうか? ではでは ? LINKS vitejs https://vitejs.dev/ vite ruby https://vite-ruby.netlify.app/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails in Docker × Rspec with Capybara × selenium_driver

概要 これらの記事を参考にCapybaraのテスト実行環境を :rack_test → :seluniumへ変更致しました。(とても参考になりました。ありがとうございました!) この記事では変更点だけを羅列しますが、注意点としましては、gem 'rspec-rails', '>= 4.0.2'こいつだけバージョンの指定が必要である、という事です。 これは2個目の記事に参考にさせていただきました! 動作環境とバージョンについて ruby 2.6.6 Rails 6.1.3 rspec-rails 5.0.1 selenium-webdriver 3.142.7 capybara 3.35.3 結論 Gemfile + gem 'rspec-rails', '>= 4.0.2' + gem 'capybara' + gem 'selenium-webdriver' docker-compose.yml version: '3' services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: password ports: - '3306:3306' command: --default-authentication-plugin=mysql_native_password volumes: - mysql-data:/var/lib/mysql web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp ports: - "3000:3000" depends_on: - db + - chrome stdin_open: true tty: true + chrome: + image: selenium/standalone-chrome:latest + ports: + - 4444:4444 stdin_open: true tty: true chrome: image: selenium/standalone-chrome:latest ports: - 4444:4444 volumes: mysql-data: driver: local rails_helper.rb -# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } +Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } : +Capybara.register_driver :remote_chrome do |app| + url = "http://chrome:4444/wd/hub" + caps = ::Selenium::WebDriver::Remote::Capabilities.chrome( + "goog:chromeOptions" => { + "args" => [ + "no-sandbox", + "headless", + "disable-gpu", + "window-size=1680,1050", + ], + } + ) + Capybara::Selenium::Driver.new(app, browser: :remote, url: url, desired_capabilities: caps) +end RSpec.configure do |config| + config.before(:each, type: :system) do + driven_by :rack_test + end + + config.before(:each, type: :system, js: true) do + driven_by :remote_chrome + Capybara.server_host = IPSocket.getaddress(Socket.gethostname) + Capybara.server_port = 3000 + Capybara.app_host = "http://#{Capybara.server_host}:#{Capybara.server_port}" + end config.include FactoryBot::Syntax::Methods # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" .rspec ---require spec_helper +--require rails_helper --format documentation 最後まで目を通していただきありがとうございました!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

フォームからパラメータとしてコントローラーに値を送る方法

プルダウンで選択したユーザーの情報をparamsで扱えるようにパラメーターを送ります。 <select name="room[user_ids][]"> <option value="">チャットするユーザーを選択してください</option> <% User.where.not(id: current_user.id).each do |user| %> <option value=<%= user.id %>><%= user.name %></option> <% end %> </select> select要素のname属性に"room[user_ids][]"を指定し、option要素のvalue属性にuser.idを指定しました。このように記述することでparamsは以下のようになります。 {"room" => {"user_ids" => ["選択したユーザーのid"]}} room[user_ids]という記述は値としてハッシュをさらに入れ子にすることを示しています。 room[user_ids]で送られるparamsの中身↓ {"room" => {"user_ids" => "値"}} 次に、末尾の[]の記述はキーに対する値を配列として格納することを示しています。これにより1つのキーに対して、複数の値を受け取ることができます。 room[user_ids][]で送られるparamsの中身↓ {"room" => {"user_ids" => ["値"]}} 以上の仕組みを利用して、選択したユーザーの情報をコントローラーへ送信できました。 しかし、現状のままですと現在ログインしているユーザーのidをparamsで送信することができていません。 (User.where.not(id: current_user.id)としているためです。) 現在ログイン中のユーザーのidも一緒にparamsでコントローラーへ送信できるように以下の記述を追加しました。 <select name="room[user_ids][]"> <option value="">チャットするユーザーを選択してください</option> <% User.where.not(id: current_user.id).each do |user| %> <option value=<%=user.id%>><%= user.name %></option> <% end %> </select> <input name="room[user_ids][]" type="hidden" value=<%= current_user.id %>> type属性に"hidden"を指定することで画面上には表示されないinput要素を作成できます。 name属性に"room[user_ids][]"を指定し、value属性にはcurrent_user.idを指定しています。 この記述でparamsは以下のようになります。 {"room" => {"user_ids" => ["選択したユーザーのid", "現在ログインしているユーザーのid"]}} room[user_ids]に2種類のユーザーidを格納することができました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

An error has occurred, all later migrations canceled: Mysql2::Error: Table 'users' already exists というエラーの対処法

問題 Rails s を実行するとマイグレーションをしろというエラーが出た後に、マイグレーションを実行した後 以下のエラーが発生しました。 An error has occurred, all later migrations canceled: Mysql2::Error: Table 'users' already exists エラー内容は「usersテーブルはすでにある」ということみたいです。 つまりusersテーブルが邪魔でエラーが発生しているということでしょうか。 そこで、usersテーブルを削除すればこのエラーは消えるのではと考えました。 解決策 Mysql を起動して以下のコマンドでusersテーブルを削除します。 drop table users; 予想通りusers テーブルを削除したら解決しました。 解決できて良かったです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Headless CMSのContentfulをRailsで使ってみる~概要~

本記事の趣旨 ContentfulをRailsで使用することを検討中の方に、 「この先はイバラの道だ、引き返すなら今だ。」と伝えるための記事です。 ただ、使用感を後述していますが、 いくつか制限に対して、問題ないという場合には使用する判断もアリかと思います。 実際の使い方に関しては別記事へのリンクを末尾に記載しますので、 そちらを参考にされると良いかと思います。 Contentfulとは Headless CMS(Content Management System)と言われていますが、いまいちピンと来ないかと思います。 簡単に言うと、「ブログのデータのみを扱うサービス」というくらいのイメージです。 具体的にすると、 データモデル定義して・・・ 実際のデータを作って・・・ 登録したデータをAPIで受け取ることができるというものです。 response_sample.json { "metadata": {"tags": []}, "sys": { "space": { "sys": {"type": "Link", "linkType": "Space", "id": "xxxxxxxxxxx"} }, "id": "XXXXXXXXXXXXXXXXXXX", "type": "Entry", "createdAt": "2021-02-19T04:33:30.532Z", "updatedAt": "2021-02-19T04:33:30.532Z", "environment": { "sys": {"id": "master", "type": "Link", "linkType": "Environment"} }, "revision": 1, "contentType": { "sys": {"type": "Link", "linkType": "ContentType", "id": "blog"} }, "locale": "ja-JP" }, "fields": { "title": "きょうのにっき", "body": { "data": {}, "content": [ { "data": {}, "content": [ { "data": {}, "marks": [], "value": "なにもないすばらしい1日でした。", "nodeType": "text"} ], "nodeType": "paragraph" } ], "nodeType": "document" }, "thumbnail": { "sys": { "type": "Link", "linkType": "Asset", "id": "XXXXXXXXXXXXXXXXX"} } } } 用途 用途を考えると、 ブログサイトのフロントエンドを構築して、APIでContentfulから記事の情報を取得する といったことに向いているかと思います。 ただこういう使い方もできると考えられます。 バックエンドのデータモデルで管理画面が必要なモデルは、 Contentfulで定義すれば管理画面を開発する必要がなくて工数が浮くのではないか? そしてRubyで扱えるGemも存在しているのです。 contentful https://github.com/contentful/contentful.rb contentful-management https://github.com/contentful/contentful-management.rb そういった発想からRailsでContentfulを使用することになり、 開発を通して得た知見をここにまとめていこうと思います。 (先に言っておくと、個人的にはお勧めしません。) ContentfulのAPIについて 公式のドキュメント https://www.contentful.com/developers/docs/references/ いくつかAPIが存在しますが、先述したGemで使用されている主要なAPIの3つを紹介します。 Contentful Delivery API (CDA) 基本となる読み取り専用のAPI。 Contentfulにはデータに対して、Publish/Unpublish/Archiveといった公開・非公開・アーカイブなどの状態を持つことができ、 このAPIでは公開されている情報のみを取得できます。 Contentful Preview API (CPA) 非公開のデータも読み取ることができるAPI。 主にプレビュー・テスト環境での使用などが想定されている、と思います。 Contentful Management API (CMA) Contentfulの環境自体の管理や、データの読み込み・書き込みも可能なAPI。 ContentfulのGemについて 先述のGem「contentful」は"CDA"と"CPA"、「contentful management」は"CMA"を扱うGemとなっているようです。 Githubに記載の内容から、 「contentful」はクライアントにマッピングしておくことで、APIで受け取ったデータ(JSON)を、Rails上のモデルに変換してくれる機能があるようです。 Rails上で扱うにはモデルへの変換ができるとかなり便利なので、読み取りには「contentful」を使用し、 データの書き込みは唯一「contentful management」しかできないので、こちらを使用することにしました。 使用感 実際に使用してみて、キビシイなと感じた点を主に記載していきます。 Contentfulで扱うモデルの定義の難易度が高い Githubに書いていませんが、ContentfulのデータモデルをRailsのモデルに変換する機能を使う場合、 initializerのパラメータをContentful::Entryの形式に合わせないといけないとか、制限が出てきます。 具体的になりますが、こんなかんじになります。 blog.rb # Contentful::Entryを継承する class Blog < Contentful::Entry # アクセサを定義する attr_accessor :id, :title, :body, :thumbnail # initializerをこの形にする def initialize(item = {}, _configuration = {}, localized = false, includes = [], entries = {}, depth = 0, errors = []) # itemsにデータが入ってくるので、データ項目のマッピングは自分で書く self.id = item.dig('sys', 'id') self.title = item.dig('fields', 'title') ... super end end この辺はお作法が分かれば問題ないかと思いますが、 要するにGithubの説明だけ見れば実装できる代物ではないということです。 リレーション項目や画像項目、リッチテキスト項目は実際にAPIからデータを受けとり、 そのJSONを見てRailsのモデルに落とし込むような処理を実装する必要があるので、難易度が高いと感じました。 結局そこに工数が嵩むなら、管理画面を作ったほうが早いと思ったら、使用しない判断もありだと思います。 OR条件検索ができない 複数回クエリを発行して、その結果を合わせれば実質OR検索になるのですが、 ページングなどの制御を入れることができなくなるので、クリティカルな制限になっています。 複雑なクエリを発行する必要がある場合は、使用を諦めた方が良さそうです。 クエリの指定が難しい 下記がContentfulからデータを取得するためのクエリです。 ContentfulのJSON形式に合う形でフィールドを指定しなければいけないので、 一つの条件を書くのが長くなります。 client.entries( content_type: 'blog', 'fields.title[eq]' => 'きょうのにっき', ... ) 別の記事で、クエリをRailsライクに記述できるようにした共通処理を記載するので、 多少の癖は残りますが乗り越えられる壁かと思います。 トランザクション機能がない APIなので当然と言えば当然ですが、 複数のモデルにわたって更新を行う場合など、整合性を担保する必要があるには、自前でトランザクション的な処理を実装する必要があります。 CMAでデータを書き込んでからCDAで読み取る場合に、反映までタイムラグがある contentful-managementのClientを使用してデータを更新すると、 その結果を受け取ることはできますが、JSON形式です。 モデルへ変換するにはcontentfulのGemを通す必要があります。 なので、CDAで再度読み取るクエリを発行すると、帰ってくるデータが更新前の場合があります。 幸いバージョン番号があるので、それがインクリメントされるまで再ロードを繰り返せば良いのですが、 実際に反映されたデータを受け取るまで時間がかかり、レスポンスが遅くなるなど、パフォーマンスに影響が出てきます。 これを回避したい場合はCMAで受け取ったJSONをモデルにマッピングして変換する処理を自前で実装する必要があります。(じゃあもうCDAいらないじゃないか、と思いますが、もう戻る道がなく私の場合はパフォーマンスが犠牲になりました。) 以上をふまえて・・・ 下記のような用途であればRailsで扱っても良いかも。 複雑なクエリは発行しない 頻繁に書き込みをしない 複数モデルの同時更新しない 詳細 難易度が高いとか書いた後でなんですが、それでもRailsでContentful使おうという開発者向けに、 Contentful Gemを自分なりに使いやすくする共通処理を作ったりしたので、下記の記事に記載します。 (近々更新します。)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsで全ユーザーにメールを送信する

はじめに メールの送信機能を初めて実装したので、躓いたところや実装方法をメモとして残しておきます。 質問回答アプリで新規質問が投稿された際に、全員に対して質問があった旨をメールで通知する。 Action Mailer Action Mailerを使うと、アプリケーションのメイラークラスやビューでメールを送信することができる。メイラーの動作はコントローラときわめて似通っている。メイラーはActionMailer::Baseを継承し、app/mailersに配置され、app/viewsにあるビューと結び付けられる。 Mailer作成手順 メイラーを作成 rails g mailer QuestionMailer app/mailers/application_mailer.rb class ApplicationMailer < ActionMailer::Base default from: "from@example.com" layout 'mailer' end 開発環境でメール送信を確認する方法 mailcatcher シンプルなsmtpサーバを立てて、送信されたメールをブラウザ上で確認できるようにしてくれる。 (cloud9でmailcatcherを実行しようとしたら、うまく実行出来ず原因はcloud9ではないかと考えられる。なので、メール確認のために代わりにletter_opener_webを使用しました。) letter_opener_web ローカル開発環境で送信したメールをブラウザ上で確認することができる http://localhost:3000/letter_openerにアクセスすることで送信されたメールを確認できる cloud9で使う方法 gemを追加 Gemfile group :development do gem 'letter_opener_web' end ルーティング config/routes.rb mount LetterOpenerWeb::Engine, at: '/letter_opener' if Rails.env.development? config デフォルトURLを指定(cloud9バージョン) config/environments/development.rb config.action_mailer.default_url_options = { host: 'myapp.c9users.io/', port: $PORT, protocol: 'https' } config.action_mailer.delivery_method = :letter_opener_web 質問があった際に全員に対して質問があった旨をメールで通知する app/mailers/question_mailer.rb class QuestionMailer < ApplicationMailer default from: 'qanda@example.com' def creation_email(user) @user = user mail(subject: '新規質問です',to: user.email, from: "qanda@example.com") end def self.creation_email_questions @users = User.all @users.each do |user| QuestionMailer.creation_email(user).deliver_now end end end app/controllers/questions_controller.rb def create @question = current_user.questions.new(question_params) if @question.save QuestionMailer.creation_email_questions redirect_to questions_url, notice: "質問を「#{@question.title}」投稿しました。" else render :new end end 躓いたところ これでも、全ユーザーにメールを送信することは可能だが、考え方が少し複雑な上にメイラーのビューで質問のタイトルや内容を表示するために@question使えない。あと、メーラにクラスメソッドを定義するやり方はあまりやらない。 改善するには メーラのクラスメソッドで定義されている全ユーザーを取り出す処理をquestions_controllerで定義すれば、メーラにクラスメソッドを定義しなくても良くなる! app/controllers/questions_controller.rb def create @question = current_user.questions.new(question_params) if @question.save User.all.each do |user| QuestionMailer.with(user: user, question: @question).creation_email.deliver_now end redirect_to questions_url, notice: "質問を「#{@question.title}」投稿しました。" else app/mailers/question_mailer.rb def creation_email @user = params[:user] @question = params[:question] mail(subject: '新規質問',to: @user.email, from: "qanda@example.com") end このようにwith(question: @question)と書くことでメイラーのアクションでparams[:question]が使えるようになり、ビューでも@questionが使えるのでメールの内容を表示することができるようになる。あとはビューを編集して完成。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

M1 mac book airを購入後インストールしたもの

M1 Mac book airを購入したので、購入後すぐにやったこと。ハマったことも一緒に掲載 GUI系ソフトウェアをインストール GUI系は何の問題もなくインストール完了 公式ページ、App storeからからダウンロードするだけ。 - sequel pro - google chrome - VS code - atom - sourse tree - fork - docker for mac - adobe(Ai, Ps など) - Jetbrains(RubyMine) - slack - evernote - monosnap - goodnote - xcode - Dispaly Menu - Magnet CUI系ソフトウェア homebrew ターミナルの設定を 「Rossetaを使用して開く」 に変更して、インストール、、はNG NG な方法 $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" homebrew公式通りに行う homebrew公式 mkdir homebrew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew ~/.zshrc export PATH=$HOME/.nodebrew/current/bin:$PATH 動作確認 sh $ brew help パスを通す homebrew系のインストール rbenv $ brew install rbenv mysql@5.7 $ brew install mysql@5.7 $ brew services start mysql@5.7 redis $ brew install redis $ brew services start redis imagemagick $ brew install imagemagick yarn $ brew install yarn nodebrew $ brew install nodebrew rbenv, Ruby3.0 $ ruby upgrade ruby-build $ rbenv install 3.0.0 パスを通す ~/.zshrc export PATH="$HOME/.rbenv/bin:$PATH" eval "$(rbenv init - zsh)" AWS CLI 2 $ curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg" $ sudo installer -pkg AWSCLIV2.pkg -target / Jupyter Lab $ pip3 install jupyterlab ※pip3とpython3は標準でインストール済み yarn brewでいれると安定版をいれるのがすこしめんどくさいので、npmでインストール $ node -v v14.17.0 $ npm install -g yarn
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails Dateカラムから年単位で値を絞り込み

会計情報機能に、2020や2021など、選択した年の収支合計を出すページを作りたく、いろいろと調べていたところ、画期的なGemを見つけました! Dateモデルの絞り込みができます。 GitHub : by_star 1.Gemをインストール gemfile gem 'by_star', git: "git://github.com/radar/by_star" bundle install 2.使い方  例1:カラム'created_at'が2020年のPostテーブルの値を取得  Post.by_year(2020) 例2:Date型カラム'processed_date'(登録日)が2020年のPostテーブルの値を取得  Post.by_year(2020, field: : processed_date)  ※field: :カラム名でDate型カラムを指定 支払日や受領日をDate型カラムとして登録し、選択した年分のみの一覧・集計ができるようになりました。 丸二日かけて調べてはDB操作をしてましたが、初心者には少し難しかったです…
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

bundle install 時にmysql2のインストールがエラーになる

bundle install時にだいたいmysql2のインストールがエラーになるのでメモ ※M1 mac book airにて動作 大体こんなエラーが出る Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling. open sslの設定が必要なので、以下の順番に調べて設定 $ brew info openssl openssl@1.1: stable 1.1.1k (bottled) [keg-only] Cryptography and SSL/TLS Toolkit https://openssl.org/ /opt/homebrew/Cellar/openssl@1.1/1.1.1k (8,071 files, 18MB) Poured from bottle on 2021-05-12 at 21:01:47 From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/openssl@1.1.rb License: OpenSSL ==> Caveats A CA file has been bootstrapped using certificates from the system keychain. To add additional certificates, place .pem files in /opt/homebrew/etc/openssl@1.1/certs and run /opt/homebrew/opt/openssl@1.1/bin/c_rehash openssl@1.1 is keg-only, which means it was not symlinked into /opt/homebrew, because macOS provides LibreSSL. If you need to have openssl@1.1 first in your PATH, run: echo 'export PATH="/opt/homebrew/opt/openssl@1.1/bin:$PATH"' >> ~/.zshrc For compilers to find openssl@1.1 you may need to set: export LDFLAGS="-L/opt/homebrew/opt/openssl@1.1/lib" ← ここが重要 export CPPFLAGS="-I/opt/homebrew/opt/openssl@1.1/include". ← ここが重要 For pkg-config to find openssl@1.1 you may need to set: export PKG_CONFIG_PATH="/opt/homebrew/opt/openssl@1.1/lib/pkgconfig" ==> Analytics install: 803,075 (30 days), 2,624,782 (90 days), 8,822,713 (365 days) install-on-request: 62,439 (30 days), 260,077 (90 days), 1,146,614 (365 days) build-error: 0 (30 days) 上の調べた結果を設定して解決 $ bundle config --local build.mysql2 "--with-cppflags=-I/opt/homebrew/opt/openssl@1.1/include" $ bundle config --local build.mysql2 "--with-ldflags=-L/opt/homebrew/opt/openssl@1.1/lib"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Railsの開発環境手順(Windows10、バージョン6)

始めに参考にしたもの ・Rubyの環境構築 https://prog-8.com/docs/ruby-env-win ・Railsの環境構築 https://prog-8.com/docs/rails-env-win 必要なもの Ruby SQLite3 Node.js Yarn Rubyのインストール Ruby公式から推薦バージョンをインストール 推奨バージョン「=>」つきのもの 今回はこれ「=>Ruby+Devkit 2.7.3-1 (x64)」 バージョン確認 ruby -v バージョンが表示されればOK SQLite3のインストール SQLite公式からインストール DownloadからSQLite Download Pageへ移動し 「Precompiled Binaries for Windows」下 自分のPCのbitに合わせて「SQLite version 3.35.5.」をダウンロード ※今回は64bit 「sqlite-tools-win32-x86-3350500.zip」もダウンロード 展開し「sqlite3.dll」「sqlite3.exe」を「C:\Ruby27-x64\bin」へ配置 Ruby on Railsのインストール バージョンを指定してインストール gem install rails -v "5.2.3" エラー発生 ERROR: Error installing rails: ERROR: Failed to build gem native extension. 色々試してみる https://dannex.jp/rails%E3%82%A8%E3%83%A9%E3%83%BC%E3%80%8Cerror-failed-to-build-gem-native-extension%E3%80%8D https://commte.net/7162 やっぱり同じエラーになるのでRailsガイドを参考にしバージョン指定なしで実行 gem install rails インストールできた... バージョン確認 ruby -v バージョンが表示されればOK Node.jsのインストール Node.jsのサイトからインストール 「Windows Installer」をクリックしダウンロード バージョン確認 node --version バージョンが表示されればOK yarnのインストール npm install --global yarn バージョン確認 yarn --version バージョンが表示されればOK 動作確認 アプリケーションを作成する rails new "アプリケーション名" my_appの作成 rails new my_app C:\を確認 Railsサーバを立ちあげる アプリケーションのディレクトリに移動 cd sample_app Railsサーバー起動 rails s ブラウザでページにアクセス localhost:3000 成功! 終了 control + c
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】カラムの設定を変更する方法

目的 適用済みのマイグレーションファイルに記載されたカラムの型を変更すること 手順 ■ 実行予定の手順 1.既存のマイグレーションファイルをロールバックする 2.変更したいマイグレーションファイルのステータスを確認 3.対象のマイグレーションファイルを書き換える 4.マイグレーションコマンドの実行 5.マイグレーションファイルのステータスがupになっているか確認 1.既存のマイグレーションファイルをロールバックする 前提として適用済みのマイグレーションを編集してはいけません。 必ずロールバックをしてから編集する必要があります。 ターミナル rails db:rollback 2.変更したいマイグレーションファイルのステータスを確認 変更したいマイグレーションファイルのステータスがdownになっているか確認します。 ターミナル rails db:migrate:status 実行すると以下のようにターミナルにマイグレーションファイルのステータスが表示されます。 ターミナル Status Migration ID Migration Name -------------------------------------------------- up 222222222222 Devise create users down 222222222222 Create items rails db:rollbackコマンドでは直近のマイグレーションのみロールバックがされます。 変更したいマイグレーションファイルをdownにしたい場合は、複数回rails db:rollbackコマンドを実行してください。 マイグレーションファイルを一度に複数ロールバックする方法はこちらの記事をご参考ください。 3.対象のマイグレーションファイルを書き換える 対象のマイグレーションファイルのステータスがdownになっていることが確認できましたら、マイグレーションファイルのカラムの型を変更していきます。 例: integer → float に変更 元の記述 t.integer :time, null: false 変更後の記述 t.float :time, null: false 4.マイグレーションコマンドの実行 変更したいカラムの型を書き換えたらマイグレーションコマンドを実行します。 ターミナル rails db:migrate マイグレーションコマンドはdownになっているマイグレーションファイルをすべてupにしてくれます。 5.マイグレーションファイルのステータスがupになっているか確認 念の為マイグレーションファイルのステータスを確認します。 ターミナル rails db:migrate:status ステータスがupになっていることが確認できたら終了です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails6】1対多のアソシエーションが組まれている場合に子モデルが多い順にソートする

前提 以下のような1対多のアソシエーションを組んだモデルを使ってRailsアプリを実装しています。 booksテーブル Column Type Options isbn string null: false, unique: true title string null: false author string null: false author_kana string null: false publisher_name string null: false sales_date string null: false item_price integer null: false item_url text null: false image_url text null: false Associations - has_many :awarenesses awarenessesテーブル Column Type Options content string null: false user references null: false, foreign_key: true book references null: false, foreign_key: true Associations - belongs_to :book Bookモデルが書籍情報で、Awarenessesモデルが書籍を読んでの気付きの情報を持っています。 カラムの中身を個別に解説することは今回はしません。 このような場合にBookモデルのデータをAwarenessesモデルのデータが紐付いている数が多い順にソートしたい。 結論 以下のコードでいけました。 Book.left_joins(:awarenesses).group(:id).order('count(book_id) DESC') ポイント ポイントはleft_joinsを使う点です。 left_joinsは関連するモデルデータを同時に引っ張ってくれるメソッドですが、joinsと異なり関連モデルのデータ存在しない レコードも引っ張ってきてくれます。 joinsとleft_joinsの違いは以下の記事がわかりやすかったです。 僕が説明するよりこっちをみてもらったほうがわかりやすいと思います。(~解説がめんどくさい~) https://pikawaka.com/rails/left_joins 感想 単純な一覧表示でしたが案外難しかったです。 SQLもっと勉強したいな〜と思いました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Mysql2::Error: Specified key was too long; max key length is 767 bytes

概要 ユーザ管理機能実装のため、deviseによるテーブルの作成時に発生した下記エラーを解消します。 Mysql2::Error: Specified key was too long; max key length is 767 bytes 結論 下記コマンドを実行する。 rails db:migrate:reset 詳細 コマンド rails db:migrate:reset は、テーブル削除、再作成、マイグレートを実施します。 処理内容としては、下記と同じです。 rails db:drop rails db:create rails db:migrate database.ymlのencoding :utf8mb4をencoding :utf8に変更することでエラー解消できない場合に試してみましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsにおけるリクエストからレスポンスの流れ

はじめに  Webページを表示したり、タスクの新規作成をする際にrailsのなかでどのような処理が行われているのかをまとめました。 ユーザーの一覧ページを表示する(GETメソッド) /usersというパスに対してGETリクエストがWebサーバに送られる。 (POSTではなくGETを使う理由は、一覧表示ではデータの書き換えは必要ではなく、データを取得したいだけなのでGETを使う) WebサーバがGETリクエストを受け取りroutes.rbのresources :usersにより、それに対応するコントローラのアクションが呼び出される。 コントローラのindexアクションで全ユーザーのデータを取得する。 def index @users = User.all end (この記述だけでデータベースからデータを取得できる理由は、RailsにはモデルにActiveRecordが継承されているので、Rubyを用いてデータベースからデータを探したり、持ってくることができる。) indexアクションに紐づくindex.html.erbを編集する @users.eachでuserオブジェクトを一つずつ取り出し、その情報がHTMLタグの中に動的に埋め込まれ、HTMLを組み立てる。 <% @users.each do |user| %> <li> <%= user.name, user %> </li> <% end %> (データベースに検索されるタイミングはindexアクションでUser.allされたときではなく、検索結果が必要なタイミングで行われるので、今回の場合は@users.eachが呼ばれた時) Webサーバからindex.html.erbで組み立てたHTMLをHTTPのレスポンスボディにのせてレスポンスを返す。 Webブラウザがレスポンスを受け取り、処理して画面にユーザー一覧が表示される。 タスクを新規作成する(POSTメソッド) 新規作成ページを表示する /tasks/newというパスに対してGETリクエストがWebサーバに送られる。 WebサーバがGETリクエストを受け取りroutes.rbのresources :tasksにより、それに対応するコントローラのアクションが呼び出される。 コントローラのnewアクションで新しいオブジェクトを作成 def new @task = Task.new end タスク名(name)を入力する 入力フォームのHTMLを生成するためnewアクションに紐づくnew.heml.slimを編集する。 = form_with model: @task, local: true do |f| .form-group = f.label :name = f.text_field :name, class: 'form-cotrol' = f.submit nil, class: 'btn btn-primary' form_withによってこのようなHTMLが生成される。 <form action="/tasks" accept-charset="UTF-8" method="post">      <input name="utf8" type="hidden" value="✓">      <input type="hidden"name="authenticity_token"value="0/MwK3LxN24WXfQNV5cFYZkbRSoRsL9QEomdh2h+Hr2BpWQqeW95LO7MM4ZZGoz56y+mHx0hMETSwAW18fqKvw==">   <div class="form-group">      <label for="task_name">Name</label>   <input class="form-cotrol" type="text" name="task[name]" id="task_name"> </div> <input type="submit" name="commit" value="登録" class="btn btn-primary" data-disable-with="登録"></form> 作成ボタンを押す form_withで生成されるmethod: postによって、フォーム内容を送信するときにPOSTメソッド指定される。/tasksに対してPOSTリクエストが送られるとroutes.rbのresources :tasksで対応するtasks_controllerのcreateアクションが実行される。 task_paramsで取得したデータをTask.newの引数にしてインスタンスを作成 def create @task = Task.new(task_params) if @task.save redirect_to @task else render :new end end private def task_params # require(:task)は生成されたHTMLのname="task[name]"のtaskと関連している。 # permit(:name)で指定したカラムのみ取得する。 # リクエストボディの「入力されたタスク名」がRailsによりparamsオブジェクトの中にハッシュのような構造で入る params.require(:task).permit(:name) end タスク詳細ページに遷移する データベースへの保存が成功した場合、リダイレクト先を@taskとすることで詳細ページに遷移する(redirect_to @taskはredirect_to task_url(task.id)と同じ意味を持つ)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む