- 投稿日:2022-01-27T21:17:45+09:00
RailsとVue.js3のSPAアプリにDeepL apiを導入する
ポートフォリオ作りの過程でRails×Vue.js3のSPAアプリにDeepL apiを導入したので過程を初学者視点で紹介します。 開発環境にはdockerを使用しています。 #version Ruby 3.0.2 Rails 6.0.4 Vue.js3 #開発環境 Docker docker-compose APIで実現したいこと 上記の画像の「AI翻訳の結果を表示する」ボタンを押すと上部に表示された日本語文を英訳して表示する。 DeepL apiの登録 こちらから登録します。 50,000文字/1ヶ月の制約はありますが無料プランもあります。 登録すると自身のアカウントに認証キーが表示されるのでそれをコピーしておきます。 Rails側の実装 gem httpclient 上記gemをインストールします。DeepL apiは"https://api-free.deepl.com/v2/translate" というurlにget(もしくはpost)リクエストを認証キー、翻訳したいテキスト、変換結果の言語の3点をパラメーターとして含んだ上で送信する必要があります。httpclientはrailsのcontrollerからそのリクエストを送信するための記述を提供してくれるgemになります。 $ docker-compose build --no-cache 今回はdockerを使用しているので上記コマンドでgemをインストールします。 $ rails g controller api/translations apiを叩くためのコントローラーを用意します。既存のコントローラーを使用しても問題ありません。 $ EDITOR="vi" bin/rails credentials:edit deepl_api: api_key: DeepL apiの認証キーを貼り付け 認証キーを直打ちしなくて済むようにcredentials.ymlに秘匿します。 translations_controller.rb class Api::TranslationsController < ApplicationController require 'httpclient' #httpclientを使用できるようにします def translate @question = Question.find(params[:id]) api_key = Rails.application.credentials.deepl[:api_key] uri = "https://api-free.deepl.com/v2/translate" client = HTTPClient.new params = { auth_key: api_key, text: @question.content, target_lang: "EN" } @response = client.get(uri, query: params) render json: @response.body end end 前述の「実現したいこと」の画像に表示されている翻訳したい文章はQuestio モデルのcontentカラムに保存されているものになるのでparamsのtextには@question.contentを代入しています。 routes.rb namespace :api, format: 'json' do get '/translate/:id', to: 'translations#translate' end questionモデルのidをパラメーターとして送信するため/:idを付け加えていますが'/translate'の部分は自由に書き換えてください(例えば'/aaa/:id'でも'translations#translate'によってapi/translations_controllerのtranslateアクションを実行してくれます)。 Vue側の実装 <template> <button @click="translateWithDeepL"> AI翻訳の結果を確認する </button> <h1>翻訳結果: {{result}}</h1> </template> <script> methods: { translateWithDeepL: function() { const question_id = this.question.id axios.get('/api/translate/'+ question_id) .then(response => { this.result = response.data.translations[0].text }) } } </script> axios.get('/api/translate/' + question_id)でroute.rbに設定したget '/translate/:id'にアクセスし、translations_controllerのtranslateアクションを実行という流れになります。 具体的には仮に翻訳したいテキストが[hello]で翻訳結果の言語を日本語に設定すると https://api-free.deepl.com/v2/translate?auth_key=認証キー&text=hello&target_lang=JA というURLにgetリクエストが送信され、 { "translations": [{ "detected_source_language":"JA", "text":"こんにちは" }] } というresponseがjson形式でかえってきます。 このレスポンスのtextの部分だけ表示したいので response.data.translations[0].text という形でフロントエンド上では受け取っているわけです。
- 投稿日:2022-01-27T20:53:12+09:00
splitメソッドとそれに関連するメソッドの解説
ruby silverの勉強をしていく中で間違えたところがあったのでその解説記事を挙げていきます。 splitメソッド 指定した文字列で分割し、それを配列で返すメソッドです。 基本構文は、 "文字列".split(区切り文字, 分割数) 論より証拠ということで、実際にコードを見ていきましょう 'Yamada, Satou, Itou, Suzuki'.split(',') => ["Yamada", " Satou", " Itou", " Suzuki"] 'Yamada, Satou, Itou, Suzuki'.split('u') => ["Yamada, Sato", ", Ito", ", S", "z", "ki"] 1個目の例でいえば、対象の文字列には、「,」があるので、,を目印に区切っていくメソッドなんですね 2個目の例でいえば、「u」を目印に文字列を区切っていくようなメソッドです。 分割数の指定 分割数を指定することもできます。 'Yamada, Satou, Itou, Suzuki'.split(',', 2) => ["Yamada", " Satou, Itou, Suzuki"] 'Yamada, Satou, Itou, Suzuki'.split('u', 2) => ["Yamada, Sato", ", Itou, Suzuki"] また、分割数を制限することもできるんです。 'Yamada, Satou, Itou, Suzuki'.split(',').first => "Yamada" 正規表現とも組み合わせることが可能 'Yamada, Satou, Itou, Suzuki'.split(/[a | u ]/) => ["Y", "m", "d", ",", "S", "to", ",", "Ito", ",", "S", "z", "ki"] 正規表現に関しては、こちらのサイトを参照してみてください! 1バイトの空白文字がある場合 1バイトの空白文字とは、文字列の半角スペースのことをいいます。 この場合、その文字列の先頭と末尾の空白文字を除いてくれて、さらに、空白文字に一致する部分で分割します。 補足でいうと、改行(\n)、タブ(\t)、nilも対象になります。 'Yama da Sat ou It ou Su zuki'.split(' ') => ["Yama", "da", "Sat", "ou", "It", "ou", "Su", "zuki"] 今回の問題の正解 ()で囲われたものを含んだ結果を返すんですね。なので、 ["Apple", "-", "Banana", "-", "Lemon"] が正解ですね ちなみに、以下のようにすると答えはまた変わりますね p "Apple-Banana-Lemon".split('-') => ["Apple", "Banana", "Lemon"] 類似メソッド String#partitionメソッド [最初のセパレータより前の部分, セパレータ, それ以降の部分] の 3 要素の配列を返します。 by公式ドキュメント セパレータって何?って方は、こちらの記事を読んでみてください 要は、[最初にヒットした場所より前の場所、最初にヒットした場所、それ以降の部分]ってことです。 実際にコードを見ていきましょう p 'Ishida Keisuke'.partition('s') => ["I", "s", "hida Keisuke"] p 'Ishida Keisuke'.partition('x') => ["Ishida Keisuke", "", ""] ヒットしなかった場合は、第2要素、第3要素は空文字になる。 あまり、partitionメソッドは使われていないような気がしますね 今回はこの辺で終わりにします! 何か間違いがございましたら、ご教示いただけますと幸いです。 【参考文献】
- 投稿日:2022-01-27T20:00:14+09:00
Rails7でspring起因でrails consoleが立ち上がらなかった問題の解決方法
はじめに 現在個人プロジェクトで M1 Mac Ruby3.1.0 Rails7.0.1 という環境での開発を試しています。今までは Intel Core i7 Ruby2.x Rails6.x という環境だったので、やはり動くところ、動かないところが出てきます。 (特に、Docker周りは変なバグを踏まないか戦々恐々としています) 今回はRails7のプロジェクトにて、springのバージョンのせいでrails consoleの実行が失敗した件についてです。 事象 発生したエラーはこんな感じで、 bundle exec rails c を実行した時に発生しました。 /usr/local/bundle/gems/spring-2.1.1/lib/spring/application.rb:103:in `block in preload': undefined method `mechanism=' for ActiveSupport::Dependencies:Module ActiveSupport::Dependencies.mechanism = :load ^^^^^^^^^^^^ (NoMethodError) 原因 rails newをした時にはspring 4.0.0でプロジェクトが作成されていたのですが、gemを整理してbundleし直した時にspringのバージョンが2.1.1に巻き戻っていたようです。 ↓該当の差分 対処方法 ググってたらRails Guideにてそのものズバリな記事を見つけました。 ここに「springは最低でも3.0.0にしてね!」と書いてあったおかげで差分があることに気づけました。 新規でプロジェクトを立ち上げた時には問題なくrails consoleが使えていたので、原因を見失っていましたが、springのバージョンを戻したことで問題なく動いています。 デフォルトでrails newした時には4.0.0でプロジェクトが作成されるため滅多に踏むバグではないかも知れませんが、 他のgemとの依存関係でたまたま自分のようにバージョンが巻き戻ったケース Rails6以前のプロジェクトをRails7に上げた際、springのバージョンを上げ忘れたケース で引っかかる可能性があります。 rails consoleだけでなく、rspecなどのspringを使うコマンド実行でも発生する可能性があるため、 Rails7プロジェクトで undefined method 'mechanism=' for ActiveSupport::Dependencies:Module というエラーを発見したらspringがバージョン2系以前になってないか確認してみてください。
- 投稿日:2022-01-27T17:51:02+09:00
【Jbuilder】部分テンプレートでハッシュのオブジェクトを使いたい
前提 @book_managerが配列ではなくハッシュのため、json.array!が使えない。 今まで ファイル名とインスタンス変数名が同じだと Railsが部分テンプレートを自動的に予測してレンダリングしてくれていたので、 ファイル名など指定しなくても機能していた。 api/v1/book_managers/show.json.jbuilder json.book_manager do json.partial! @book_manager end 訳あってファイル名変更 ファイル名を変更した際、下記の様に部分テンプレートを指定してみたがうまく行かない... api/v1/book_infos/show.json.jbuilder json.book_info do json.partial! 'api/v1/book_infos/book_info', collection: @book_manager, as: :book_info end うまく行った例 ローカル変数book_infoとして@book_managerを渡す。 api/v1/book_infos/show.json.jbuilder json.book_info do json.partial! 'api/v1/book_infos/book_info', book_info: @book_manager end
- 投稿日:2022-01-27T17:07:54+09:00
Hamlの基本
はじめに RailsでWebアプリにPay.jpを用いた決済機能を実装しようとしていました。 実装フローを検索していたところ、Hamlを使ってビューが実装されているドキュメントが多く、興味本位で学習しました。 これから学習しようとしている方の参考になればと学習したことをまとめてみました。 TL;DL ・RubyをベースとしたHTMLのテンプレートエンジンのこと ・HTMLよりもシンプルに記述できる ・Ruby / Ruby on Railsでも使われている 前提知識 ・HTML ・Ruby(Rubyがベースになった記法だから) ・Ruby on Rails(Railsで使いたい場合) 大枠の使い方 ① 拡張子がhamlのファイルを作成する(Ex.index.haml) ② 作成した①をhamlコマンドに通す(Ex. haml index.haml index.html ) ③ htmlファイルが生成される(Ex.index.html) ※ hamlのコマンドオプション(よく使うもの) -f format → アウトプットのフォーマットを指定(html5) -q → ダブルクオーテーションを出力 具体的な記述の仕方 【POINT】hamlの記法 1. 接頭辞でコンテンツの内容を表現 2. インデントで階層構造を表現 この二つの概念と接頭辞の種類さえ抑えれば、基本的な表現であれば、hamlで表現できないことはなくなるはずです。 接頭辞 接頭辞 接頭辞の意味 !!! DOCTYPE % 開始タグと終了タグ {:属性 => 値} タグに属性を追加する(Rubyっぽい) (属性 = 値) タグに属性を追加する(HTMLっぽい) %p テキスト pタグに囲われたテキスト < タグ内部の改行を除去 > タグ外部の改行を除去 %p{:id=>"id", :class=>"class"} <p id="id" class="class"></p> %p(id="id" class="class") <p id="id" class="class"></p> %p.class <p class="class名"></p> %p#id <p id="id名"></p> #id.class <div id="id" class="class"></div> :css styleタグ :javascript scriptタグ #{〜} 〜にRubyのコードを実行して表示 %p=〜 〜のRubyのコードを実行して表示 - 〜 〜のRubyのコードを実行して表示しない / HTMLとHaml両方に残したいコメント -# Hamlにだけ残したいコメント インデント HTMLの入れ子構造を作るために使用する ※ 同じ階層の要素は同じインデントの数に統一すること コメント / → HTMLでも残したいコメント -# → Hamlにだけ残したいコメント フォーマット HTMLと同様、最初に記載する型は決まっているので、自分用に念の為記載します。 ①hamlファイルを作成する !!! %html{:lang => "ja"} %head %meta(charset="UTF-8") %body / 一般的なタグの生成 %p hellow world! / ul, liタグの生成 %ul %li< item / divの生成 %div#id.class %div{:id=>"id", :class=>"class"} %div(id="id" class="class") #id.class / Rubyの実行と表示 #{ 3 + 5 } %p= 3 + 5 - 3 + 5 ②作成したファイルをhamlコマンドに通す haml index.haml index.html ③htmlファイルが生成される <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> </head> <body> <!-- 一般的なタグの生成 --> <p>hellow world!</p> <!-- ul, liタグの生成 --> <ul> <li>item</li> </ul> <!-- divの生成 --> <div id="id" class="class"></div> <div id="id" class="class"></div> <div id="id" class="class"></div> <div id="id" class="class"></div> <!-- Rubyの実行と表示 --> 8 <p>8</p> </body> </html> 上のhamlファイルをhtmlに変換すると、下のhtmlファイルのような記載になります。 参考文献 ドットインストール haml入門(全8回) ※ hamlをRailsで使う方法は以下の記事が参考になります。 - 【rails】htmlからhamlに一括で変換するコマンド - Railsでhamlを使う
- 投稿日:2022-01-27T16:00:44+09:00
rails 7.00における "cannot load such file --sassc"の解決法
rails7.0.0の影響によるcssの読み込みができなくなるというエラーに遭遇したので、同じ症状で悩まされている方のためになるかと思い、この記事を執筆しています。 railsの7.0.0が昨年に公開されましたが、以前のようにcssを適用させようとすると書き画像のようなエラーが出ることがあります。 このエラーの解決方法は Gemfile 46 # gem "sassc-rails" のコメントアウトを削除して、bundle installをすることで解決することができます。 rails7.00以前はこのgemが環境構築の際に自動でinstallされていましたが、7.00以降では標準でインストールされないようです.
- 投稿日:2022-01-27T12:04:49+09:00
大量データ加工処理の高速化
はじめに 今まで一般的なWeb開発はしてきたけど高速化についてあまり考慮せずに実装してきたエンジニアの方に向けて、筆者の大量データ ( 7億-8億レコード ) 加工処理高速化の経験を基に、本番実行で何を目指すかということと、それまでに実際にどのようなアプローチがあるのかを提案できればと思います。 あくまで提案なので、「こうしたらもっと高速になるよ」的な箇所は多々あるかと思います。 コメントなどでご指摘いただければ幸いです。 本記事における前提条件 本記事における前提条件を筆者の経験した環境を参考に記載します。 本プロジェクトの背景及び要件 既存サービスで蓄積されたデータを外部のシステムに連携して有用活用するにあたってのPoVを実施する。 既存サービスで蓄積されたデータの一部を匿名化 (ハッシュ化) したものをCSVに書き出し、外部のシステムにPOSTする。 本番実行までの実装及び検証は短期間 (2-4週間程度) である。 加工処理はできるだけ早くする完了させる 採用したテクノロジー Ruby on Rails API mode AWS EC2, RDS, Elasticache Redis, CloudWatch データ加工処理高速化のアプローチ 本対応における極意 塵も積もれば山となる 加工処理は要件を満たす範囲内で最速のロジックを追求する 外部接続回数は最小限に抑える 使用するデータサイズをできるだけ小さくする 使いまわせるデータは使いまわす マシンスペックを最大限活用する 実装レベル 計測 高速化実装は実行時間を計測してロジックをチューニングしながら進めます。 今回はRuby標準の benchmark というライブラリを採用しました。 benchmarkの使用方法については細かく解説しないので、以下のような記事を参考にしていただければと思います。 https://qiita.com/scivola/items/c5b2aeaf7d67a9ef310a https://nishinatoshiharu.com/usage-benchmark/ 並列実行 今回のようなデータ量を直列で加工していてはいつまでたっても処理が完了しません。 複数スレッド/プロセスに作業を分担して並列実行します。 今回はRuby Gemsの Parallel を採用しました。 # Parallel.processor_countでCPUのコア数が取得できる csv_data += Parallel.map(records, in_processes: Parallel.processor_count) do |record| # some process end このような記述にすると、 records の要素が record としてブロックに渡され、各プロセスで加工処理できるようになります。 今回のケースにおいて in_thread と in_processes は計測の結果、プロセスに処理させる方が多少高速だったため in_processes を採用しました。 in_thread を使用し、 #some_process 内でDB接続する部分がある場合は、コネクションプールを使用して高速化することも検討できます。 加工処理の高速化 分割抽出 大量なデータを一度にDBから取得しようとするのは非常に非効率です。 find_in_bataches で細切れにデータを取得して高速化を図ります。 SomeModel.find_in_batches(batch_size: Constants::Batch::BATCH_SIZE) do |records| # some process csv_data += Parallel.map(records, in_processes: Parallel.processor_count) do |record| # some process end # some process end *Constants::Batch::BATCH_SIZE は独自に宣言した定数です。最終的に 100_000 で設定しました。 必要な属性のみ抽出 今回CSVには必要な属性のみ書き出すため、抽出する属性も最小限に絞ります。 また、加工対象のテーブルがパーティショニングされている場合は、 SomeModel の部分にパーティションが渡されるような実装になるかと思います。 SomeModel.select_csv_columns.find_in_batches(batch_size: Constants::Batch::BATCH_SIZE) do |records| # some process csv_data += Parallel.map(records, in_processes: Parallel.processor_count) do |record| # some process end # some process end scope :select_csv_columns, -> do select([ :some_colum, ... ]) end 加工に使用されるアルゴリズムなどのチューニング 今回特定の属性を匿名化するため、最初は SHA-512 でハッシュ化していました。 Digest::SHA512.hexdigest("#{string}") 今回ハッシュ化のセキュリティレベルに関して特段指定がなかったため、より高速な SHA-1 に変更しました。 Digest::SHA1.hexdigest("#{string}") 処理速度の比較.1 処理速度の比較.2 インフラレベル 全体像 全体のシーケンス図を描いてみました。 各EC2インスタンスにssh接続し、それぞれのインスタンス内でrakeタスクを実行する形で構成されています。(ここは正直時間が足りず...改善点は多々あると思っています) Rakeタスクのパラメータにデータ抽出のオフセット値を渡し、処理対象を分散するようになっています。 対象テーブルの加工時に、他テーブルへの参照が必要な場合ループ単位で外部参照のSQLが発行されてしまいます。 できる限りDB接続を減少させるため、一度参照したKVはRedisにストアし、値がセットされている場合はそちらを使用します。 また、rakeタスク実行時にはCloudWatchでメモリ使用率やIOPSを監視し、異常が発生したらすぐに対応できる体制を整えます。 さいごに 今回全体での処理経過時間は9時間程度でした。 (EC2 a1.4xlarge:8台, RDS db.t3.medium:1台, Elasticache t2.small:1台) 実行方法に関しての検討はタイムアップで脳筋実行になってしましたが、 処理単位を分割したタスクをキューイングし、各インスタンスがタスクを拾いにくる、という形を作ると処理効率を最大化できそう というアドバイスをいただいたので、次回このような機会があったときには試してみたいと思っています。 その他より良い方法がある方はご意見いただけると幸いです。
- 投稿日:2022-01-27T10:56:27+09:00
[Rails] 自分流のrspec(API向け)テンプレート
「APIのテスト書きたいけど、どんな感じでかけばいいのか忘れちゃった!」というときに、とりあえずこのテンプレをコピペしてからコーディングを始めることで超絶時短を狙う。 テンプレート 前提 FactoryBot利用し、Factoryのクラスメソッド実行時にFactory.を省略できるような設定をrails_helperでしている spec/requests/【対象リソース名(スネークケース、複数形)】.rb require 'rails_helper' RSpec.describe "/<対象リソース名(スネークケース、複数形)>", type: :request do # xxx_xxxテーブルのレコード設定 ## <レコードの説明> let!(:xxx_xxx1) { create(:<xxx_xxx>, :<trait>,...) } ## <レコードの説明> let!(:xxx_xxx2) { create(:<xxx_xxx>, :<trait>,...) } ... # yyy_yyyテーブルのレコード設定 ## <レコードの説明> let!(:yyy_yyy1) { create(:<yyy_yyy>, :<trait>,...) } ## <レコードの説明> let!(:yyy_yyy2) { create(:<yyy_yyy>, :<trait>,...) } ... # APIリクエスト関連 ## 認証トークン let!(:token) do <認証処理> end ## リクエストヘッダ(認証OK) let!(:valid_headers) { { 'Content-Type' => 'application/json', 'Authorization' => "Token #{token}" } } ## リクエストヘッダ(認証NG) let!(:valid_headers) { { 'Content-Type' => 'application/json', 'Authorization' => "Token #{token}a" } } ## ステータスコード let(:res_status) { response.status } ## レスポンスボディ(のJSON文字列をパースして、キーがシンボルであるハッシュとして受け取ったもの) let(:res_body) { JSON.parse(response.body, { symbolize_names: true }) } ## 認証エラー時のレスポンスボディ let!(:res_body_unauthorized) { { error: 'unauthorized' } } describe '<HTTPメソッド> /<アクション>' do context '正常系' do # リクエストパラメータ let!(:params) { { a: 1, b: 2,... }.to_json } # リクエストヘッダ let!(:headers) { valid_headers } # リクエスト(GET /index時) subject { get <リソース名(スネークケース,複数形)>_url, headers: headers } # リクエスト(GET /show時) # subject { get <リソース名(スネークケース,単数形)>_url(<表示対象のリソースのモデルインスタンス(ActiveRecord)>), params: params, headers: headers } # リクエスト(POST /create時) # subject { post <リソース名(スネークケース,複数形)>_url, params: params, headers: headers } # リクエスト(PUT /update時) # subject { put <リソース名(スネークケース,単数形)>_url(<更新対象のリソースのモデルインスタンス(ActiveRecord)>), params: params, headers: headers } # リクエスト(DELETE /delete時) # subject { delete <リソース名(スネークケース,単数形)>_url(<削除対象のリソースのモデルインスタンス(ActiveRecord)>), headers: headers } let(:expected_body) do { <期待するレスポンスボディの内容> } end it 'ステータスコード: <ステータスコード>, ボディ: <レスポンスボディの概要>, DB: <DBデータの変化概要>' do # リクエスト実行 expect(subject).to change(<リソースのクラス名>, :size).by(<変化したレコード数>) # ステータスコードチェック expect(res_status).to eq(<ステータスコード>) # レスポンスボディチェック expect(res_body).to eq(expected_body) end end context '異常系: 認証エラー' do # リクエストパラメータ let!(:params) { { a: 1, b: 2,... }.to_json } # リクエストヘッダ let!(:headers) { invalid_headers } # リクエスト(GET /index時) subject { get <リソース名(スネークケース,複数形)>_url, headers: headers } it 'ステータスコード: <ステータスコード>, ボディ: <レスポンスボディの概要>, DB: レコードが作成されない' do # リクエスト実行 expect(subject).to change(<リソースのクラス名>, :size).by(0) # ステータスコードチェック expect(res_status).to eq(401) # レスポンスボディチェック expect(res_body).to eq(res_body_unauthorized) end end context '異常系: リクエストパラメータ不備' do end ... end end 補足 コードの構造にルールを設け、シンプルに保つことを心がける。 ①階層構造(describe, context, it) 「チェック対象はdescribe, 条件はcontext, 期待結果はit」と階層化する。 DBのデータやリクエスト、レスポンスに関する定義など、準備はdescribe, contextで済ませておく itでは、リクエストを投げる → それによる結果をチェックするに注力する ②準備系の設定(let!, let, before) 後の階層で変数的に使いまわしたい設定は、let!での定義を基本とし、時間差が必要な場合のみletを使う ※letは、遅延評価をしっかり意識しないと期待しない挙動をしてしまい、泥沼にハマる可能性が高いため ※後から参照しなくてよい設定は、beforeで定義する慣習らしい。・・・が、コード書いてる内に後から「やっぱり必要でした!」というケースもあるし、let!でなくbeforeを使うメリットはさほどないと判断 ③リクエストのスローとレスポンスのチェック(subject, response) subjectに、実際にリクエストを投げる処理を記述する subject内で記述するAPIのパスは、<bundle exec rails routeで表示されるパスの省略系>_urlでベタ書きせず書く 2.について、show, update, delete系のAPIは、その引数に操作対象リソースのモデルインスタンスを記述(xxx_url(<インスタンス>))してやるとidをベタ書きせずに書ける API実行結果であるレスポンスボディ、ステータスコードはresponseから参照する(response.status, response.body) ※subjectを使用してリクエストをスローすると、responseでその結果を受け取れる、というrspecの機能があるのでこれを利用 レスポンスボディ(response.body)は、JSON文字列でありチェック時に扱いづらいため、キーはシンボルでハッシュ化する処理を定義しておく 期待するレスポンスボディの定義も、キーがシンボルなハッシュで記述して、3.と突き合わせる形でチェックする ステータスコードのチェックは、数値でベタ書きする(be_successとか書くと、200でも201でもチェック通過してしまい、曖昧性が排除できない) レスポンスのチェックは、「ステータスコード」「レスポンスボディ」「DBのレコード数変化」の3点とする。 ※レコードの内容がなにかしら変化する系のアクション(create, update, delete)は、「DBの中身的にもホントに期待する結果になっているのか?」まで見たほうが良い気もするが、個数だけチェックしている記事が多いっぽいのでそうする(腑に落ちてはいない)。 メモ ホントはheaderの定義もキーがシンボルのハッシュで書きたい。 しかし、なぜかContent-type:がうまくかけない。 なので、渋々キーが文字列のハッシュにした。
- 投稿日:2022-01-27T08:41:36+09:00
binding.pryが止まらない!
railsのデバッグのために binding.pry を使ったが、ループの中に入れてしまったので exit をしてもずっと止まらない! こんな時に使えるコマンドがこちらです!↓ $ exit! $ !!! 上記のどちらかで止まります! 試してみてください^^
- 投稿日:2022-01-27T02:15:38+09:00
[JS]アロー関数を少しだけ深掘りしてみた
アウトプットとして 関数を簡略化して記述できるアロー関数、調べてみるとちょっとしたテクニックがあるみたいだったのでまとめてみました。 ちなみにいろんな関数の定義の仕方や特徴はこちらにまとめています。 JavaScriptの関数 アロー関数とは functionの記述を省略し、その代わりに()=>という記述によって関数を定義する構文です。より短い記述で関数定義をできるという点がメリット。 // 無名関数 const 変数名 = function(){ 処理 } // アロー関数 const 変数名 = () => { 処理 } 引数が1つの場合は丸括弧が省略できる 定義の際に引数が1つしかない場合は丸括弧を省略できる。 ただし、スプレッド構文...を使用する場合は省略できません。 // 省略しない var hoge = (a) => { 処理 } // 省略できる var hoge = a => { 処理 } // スプレッド構文の場合 var hoge = (...args) => { 処理 } return文やブロック{}を省略できる 関数内の処理が1行として読めるコードでreturn文で値を返している場合は、return文とブロック{}を省略することができます。 // 省略しない var hoge = (a, b) => { return a + b; }; // 省略する var hoge = (a, b) => a + b; 以上のことを活用するともっとシンプルなコードが書けそうな気がします…!! ※補足等ありましたらコメントいただけると幸いです。