- 投稿日:2020-01-14T23:26:12+09:00
ArgumentError in GroupsController#create ,wrong number of arguments (given 0, expected 1)の一例
1. どんなエラー?
「GroupsControllerのcreateの部分で引数が1つ返ってくると予想される(記述されている)のに、実行時には0件でしたよ」というエラーです
<エラーに関係したファイル>
groups_controller.rbclass GroupsController < ApplicationController def index end def new @group = Group.new @group.users << current_user end def create @group = Group.new(group_params) if @group.save redirect_to root_path, notice:'グループを作成しました' else render :new end end def edit @group = Group.find(params[:id]) end def update @group = Group.find(params[:id]) if @group.update(group_params) redirect_to root_path, notice: 'グループを更新しました' else render :edit end end private def group_params params.require.permit(:name,user_ids:[]) end end2.原因と解決方法
まず結論から言いますと、'require'の後ろにハッシュ指定がないため、'(:group)'をつけることにより解決します。
groups_controller.rbparams.require(:group).permit(:name,user_ids:[])3.原因の見つけ方
このエラーに対する正攻法として、引数の数がおかしいというエラーに対し、じゃあ〇〇行目(今回は35行目)では何を呼び出すことが可能な状態なのかを調べるという方法があります。(実践方法は下記に記載しますので必要な方はご覧いただければと思います。)
調べた内容より、間違いの確認と、呼び出したい内容がどのハッシュに格納されているか確認ができます。これにより'require'で呼び出すハッシュを決めることができます。
(※requireを使用するときは多重ハッシュとなっている場合となるため、値の直前のハッシュを指定します。これを使わないと値を格納してほしいところにハッシュ値が入ってしまいエラーとなります。今回の例がまさにそれに当たります。)
<実践方法>
①pry-rails(デバック(確認)用のツール)をインストールするため、Gemfileの最後の行に下記のコマンドを追記するgem 'pry-rails'②作業中のファイルのディレクトリで bundle installする(このコマンドがわからない方は検索をかけてもらえばいっぱい出てきます)
Neverland:chat-space-kai kontatomoya$ bundle install③指定の行を改行してその行に binding.pry を記述する(筆者の場合35行目を改行して、新しい35行目に書きます)
groups_controller.rb#1~32行目は上記の内容から変化がないので省略 33 private 34 def group_params 35 binding.pry 36 params.require.permit(:name,user_ids:[]) 37 end 38 end④rails s します
Neverland:chat-space-kai kontatomoya$ rails s⑤エラーを吐いてしまうページにつなげます。(筆者の場合は下記の写真の登録するボタンを押すとエラーページ繋がります。)すると、次のページに飛ばずに読み込み中のままとなります。
⑥この状態のままターミナルを確認します。すると下記のようになっています。
#上にもっと記述が出ますが直接関係ないので省略します From: /Users/kontatomoya/projects/chat-space-kai/app/controllers/groups_controller.rb @ line 35 GroupsController#group_params: 34: def group_params => 35: binding.pry 36: params.require.permit(:name,user_ids:[]) 37: end [1] pry(#<GroupsController>)>⑦ここで
[1] pry(#<GroupsController>)>の隣に params と打ちましょう。すると下記のような回答が返ってきます#続き [1] pry(#<GroupsController>)> params #paramsを打ちました => <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"/vrx3ZW1g+kcEgeh8V+FJlqUnBNEIR9jyvGeSl1r22IcMk+1F0I7zRhnKKXWpLNMtwjbmWxBBBaNR9phNk3KOg==", "group"=>{"name"=>"", "user_ids"=>["", "2"]}, ←この部分だけ{}で囲まれており、二重(多重)ハッシュとなっています "commit"=>"登録する", "controller"=>"groups", "action"=>"create"} permitted: false> [2] pry(#<GroupsController>)>まずこれを見ると呼び出すことができるハッシュがわかります。その中でハッシュ'group'のハッシュだけ2重ハッシュ(ActionController::Parametersに二回囲まれている状態)となっております。
今回筆者はその中の"name", "user_ids"がほしいと考えています。よって、こちらで'permit'したいハッシュ(:name,:user_ids[])の一つ上のハッシュ(今回は'group')を要求すれば良いとわかるいう流れとなります(※今回の場合そのほかの値が欲しければ'require'をつけずに'permit(:先ほど調べたハッシュ名)'とすればエラーは無くなります。)
- 投稿日:2020-01-14T23:21:37+09:00
【翻訳】Testing best practices - GitLab
GitLabのテストにおけるベストプラクティス記事を日本語訳したものです。
https://docs.gitlab.com/ee/development/testing_guide/best_practices.html
最終閲覧日時: 2020/01/06
途中、おかしな日本語があるかもしれませんので原文と照らし合わせてお読みください
Test Design
GitLabではテストは最優先事項[1]です。機能の設計と同様に、テストの設計を考慮することは重要と考えています。
機能を実装するとき、我々は適切な機能を適切な方法で開発することを検討します。これにより、範囲を管理可能なレベルに絞り込むことができます。機能のテストを実装する場合、適切なテスト実装を検討する必要がありますが、重要な箇所をすべてカバーするテストは難しく、すぐに管理困難な段階にまで拡大するでしょう。
テストヒューリスティック[2]は、この問題の解決に役立ちます。これは、我々のコードに潜むバグを明らかにし、簡潔に対処します。テストを設計する時、既知のテストヒューリスティックの確認に時間をかけ、我々のテスト設計手法を周知してください。Test Engineering sectionで有用なヒューリスティックのドキュメントが読めます。
Test speed
GitLabには大規模なテストスイートがあり、並列化しないと実行に数時間かかることがあります。正確で効果的かつ高速なテストを書く努力をすることが重要です。
テストのパフォーマンスに関する注意事項を次に示します。
doubleとspyはFactoryBot.build(...)より速いFactoryBot.build(...)と.build_stubbedは.createより速いbuild,build_stubbed,attributes_for,spy,doubleを使う時、createでオブジェクトを作成しないこと。DBの永続化は遅い。- 本当にテストする必要がある場合以外は、JavaScriptを必要とする機能のテスト(RSpecの
:jsのような)を行わないこと。ヘッドレスブラウザでのテストは遅い。RSpec
rspecでテストするには
# run all tests bundle exec rspec # run test for path bundle exec rspec spec/[path]/[to]/[spec].rbguardを使用して変更を継続的に監視し、変更されたテストのみを実行します。
bundle exec guardspringとguardを一緒に使用する場合は、代わりに
SPRING = 1 bundle exec guardとしてspringを使用してください。General guidelines
- トップレベルには
describe ClassNameを一つだけ定義することdescribe内では、クラスメソッドを.method、インスタンスメソッドを#methodと表記すること- ロジック的に分岐する場合は
contextを使うこと- テスト項目の順序はプロダクトコードクラス内の順序と一致させること
- 改行を使用してフェーズを分離し、4フェーズのテストパターンに従うこと
localhostのようなハードコーディングはせず、Gitlab.config.gitlab.hostのように設定変数を使うことsequenceによって生成された変数のような値に対してテストを行わないこと(落とし穴を参照)beforeやafterなどのフックの引数に:each(alias:example)与えてもデフォルトで効いているため引数に指定しないことbeforeとafterのフックは:allのスコープよりも:contextのスコープのほうが望ましい- 指定した要素に作用する
evaluate_script("$('.js-foo').testSomething()") (もしくはexecute_script)を使うときは、Capybaraのマッチャー(例えばfind('.js-foo'))であらかじめ要素が確実に存在することを確かめるfocus: trueを使ってテストしたい範囲を分離すること- テストに複数の期待値がある場合はaggregate_failuresを使用すること
System / Feature tests
Note: 新しいSystem / Feature testを書く前に一度、書かないことを検討してください
- feature specのファイル名は
user_changes_password_spec.rbのようにROLE_ACTION_spec.rbとすべき- シナリオタイトルには成功ケースと失敗ケースを記載すること
- 「successfully」など、情報がないようなシナリオタイトルは避けること
- 何がsuccessfullyなのか明記すること
- 機能のタイトルを繰り返すだけのシナリオタイトルは避けること
- データベースには必要なレコードのみを作成すること
- Happy path[3]とless happy pathだけをテストします。
- 可能な限り単体テストまたは統合テストでテストする必要がある
- ActiveRecord内部ではなくページに表示されるものを評価すること
- もしレコードが作成されたことを確認したかったら、
Model.count等でモデルが増えたことをテストするのではなく、その項目がページに表示されるというテストを追加すること。- DOM要素を探してもよいがテストをより脆弱にするため乱用はしないこと
Live debug
live_debugメソッド[4]を使えば、Capybaraを一時停止して、ブラウザでウェブサイトを表示できます。デフォルトブラウザで開きます。テストの実行を再開するには、任意のキーを押します。以下のような感じです。
$ bin/rspec spec/features/auto_deploy_spec.rb:34 Running via Spring preloader in process 8999 Run options: include {:locations=>{"./spec/features/auto_deploy_spec.rb"=>[34]}} Current example is paused for live debugging The current user credentials are: user2 / 12345678 Press any key to resume the execution of the example! Back to the example! . Finished in 34.51 seconds (files took 0.76702 seconds to load) 1 example, 0 failuresNote:
live_debugはJavaScriptが使える場合でのみ動きます。Run :js spec in a visible browser
以下のように
CHROME_HEADLESS=0を付けてspecを実行します。CHROME_HEADLESS=0 bundle exec rspec some_spec.rbこのテストはすぐに終わりますが、これにより何が起こっているのかわかります。
CHROME_HEADLESS=0を付けlive_debugを使って開いているブラウザを一時停止し、再び開くことができません。これは要素のデバッグと検査に使用できます。byebugまたはbinding.pryを追加して、実行を一時停止し、テストをステップ実行することもできます。
Screenshots
capybara-screenshotgemを使用して失敗時に自動的にスクリーンショットを撮ります。 CIでは、これらのファイルをジョブアーティファクトとしてダウンロードできます。また、以下のメソッドを追加することにより、テストの任意の時点でスクリーンショットを手動で取得できます。不要になったら削除してください!詳細については、ここを参照してください。
screenshot_and_save_page
- Capybaraが「見ているもの」のスクリーンショットを作成し、ページソース(htmlファイル等)を保存します。
screenshot_and_open_image
- Capybaraが「見ているも」のをスクリーンショット化し、画像を自動的に開きます。
これにより作成されたHTMLダンプにはCSSがありません。これにより、実際のアプリケーションとは大きく異なった外観になります。デバッグを容易にするCSSを追加するsmall hackがあります。
Fast unit tests
一部のクラスはRailsから十分に分離されており、RailsやBunlderの
:defaultグループのgem等によって追加されたオーバーヘッドなしでそれらをテストできるはずです。このような場合、テストファイルでspec_helperをreuqireする代わりにfast_spec_helperをreuqireできます。次の理由からテストは非常に高速に実行されるはずです。
- gemのロードをスキップ
- Railsアプリの起動をスキップ
- GitLab ShellとGitallyのスキップ
- テストリポジトリのセットアップをスキップ
fast_spec_helperはlibディレクトリ配下にある自動ロードクラスもサポートします。つまり、クラス/モジュールがlibディレクトリ配下のコードのみを使用している限り、依存関係を明示的にロードする必要はありません。fast_spec_helperは、Rails環境で一般的に使用されるコア拡張機能を含む、すべてのActiveSupport拡張機能もロードします。コードがgemを使用している場合、または依存関係がlibにない場合、require_dependencyを使用して依存関係をロードする必要があることに注意してください。
たとえば、
Gitlab::UntrustedRegexpクラスを呼び出しているコードをテストする場合は、内部でre2ライブラリを使用します。re2 gemを必要とするライブラリ内のファイルにrequire_dependency 're2'を追加して、この要件を作成する必要があります 明示的に指定するか、仕様自体に追加することもできますが、前者が優先されます。
spec_helperの場合に30秒以上かかるloadが、fast_spec_helperを使うことで1秒程度のロードですみます。let variables
GitLabのRSpecスイートでは、重複を減らすために
let(それに加えて、厳密な非遅延バージョンlet!)変数を広範囲に使用しています。しかしながらこれは時々コードを分かりにくくします。そのため、今後の使用に関するガイドラインを設定する必要があります。
let!はインスタンス変数よりも好ましい。letはlet!よりも好ましい。ローカル変数はletよりも望ましいletを使用してspecファイル全体の重複を減らせる- 単一のテストでのみ使用される変数は
letを使わずにitブロック内でローカル変数として定義すること- 最上位の記述ブロック内でlet変数を定義しないこと。これは、より深くネストされたコンテキストまたは記述ブロックでのみ使用される。定義は使用する場所にできるだけ近づけること。
- 解せない
- ある
let変数の定義を別のlet変数の定義で上書きしないようにする
- これもスコープが異なっていればいいのでは?
- 別で定義されている
let変数を定義するな(たぶん糸の異なる重複定義するなってことだと思われ)
- 代わりにヘルパーメソッドを使うべき
let!変数は定義された順序が重要な場合にのみ使用すること。それ以外はletで十分
letは遅延評価であり、参照されるまで評価されないことに注意してCommon test setup
場合によっては、各exampleでテスト用に同じオブジェクトを生成する必要はありません。たとえば、プロジェクトとのそのプロジェクトのゲストは、プロジェクトとゲストが関係するすべてのファイルに対してテストするために必要となります。これは、
test-profgemで導入できるlet_it_be変数とbefore_allフックを使うことで達成できます。let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } before_all do project.add_guest(user) endこれにより、このcontextに対して作成されるProject, User, ProjectMemberが一つだけになります。
let_it_beおよびbefore_allは、ネストされたcontext内でも使用できます。トランザクションロールバックにより、contextが処理された後に自動的にクリーンアップされます。
let_it_beブロック内で定義されたオブジェクトを変更する場合、必要に応じてオブジェクトをリロードするか、すべての例でリロードするリロードオプションを指定する必要があることに注意してください。let_it_be(:project, reload: true) { create(:project) }また、再検索オプションを指定して、新しいオブジェクトを完全にロードすることもできます。
let_it_be(:project, refind: true) { create(:project) }set variables
Note: Gitlabでは
let_it_beを支持しているため、setを削除しつつあります。詳細はこちら参照してください。場合によっては、各exampleでテスト用に同じオブジェクトを生成する必要はありません。たとえば、プロジェクトとのそのプロジェクトのゲストは、プロジェクトとゲストが関係するすべてのファイルに対してテストするために必要となります。これは、
letを使用するのと同じ方法でsetを使用することで実現できます。
rspec-setはActiveRecordオブジェクトでのみ機能し、新しいサンプルの前に必要な場合にのみモデルをリロードまたは再作成します。つまり、プロパティを変更したときまたはオブジェクトを破棄したときです。
setブロック内のletブロックで定義されたモデルを参照することはできませんので注意してください。また、
:jsスペックでは、各exampleの後にデータベースの状態をクリーンアップするためにトランザクションを使用しないため、setはサポートされていません。Time-sensitive tests
TimecopはRubyベースで利用でき、時間依存のテストケースに有効です。時間に依存するテストを実行・検証する場合、Timecopを使用して一時的なテストの失敗を防ぎます。
例えば、
it 'is overdue' do issue = build(:issue, due_date: Date.tomorrow) Timecop.freeze(3.days.from_now) do expect(issue).to be_overdue end endFeature flags in tests
すべての機能フラグはRubyベースのテストにおいて、デフォルトで有効になるようにスタブ化されています。
テストで機能フラグを無効にするには、
stub_feature_flagsヘルパーを使用します。たとえば、テストでci_live_trace機能フラグをグローバルに無効にするには、stub_feature_flags(ci_live_trace: false) Feature.enabled?(:ci_live_trace) # => false一部のアクターに対して機能フラグを無効にし、他のアクターに対しては無効にしないテストを設定する場合、ヘルパーに渡すオプションでこれを指定できます。たとえば、特定のプロジェクトの
ci_live_trace機能フラグを無効にするには、project1, project2 = build_list(:project, 2) # Feature will only be disabled for project1 stub_feature_flags(ci_live_trace: { enabled: false, thing: project1 }) Feature.enabled?(:ci_live_trace, project1) # => false Feature.enabled?(:ci_live_trace, project2) # => truePristine test environments
1つのGitLabテストで実行されるコードは、多くのデータにアクセスして変更する場合があります。テストを実行する前に慎重に準備し、その後クリーンアップしないと、データはテストによって変更され、次のテストの動作に影響を与える可能性があります。これは必ず避けてください。幸いなことに、既存のテストフレームワークのほとんどはこのようなケースを回避しています。
テスト環境が汚染されると、一般的には不安定なテストになります。テスト環境汚染の多くの場合は、スペックAの後にスペックBを実行すると確実に失敗するが、スペックBの後にスペックAを実行すると確実に成功するといった、順序の依存関係として現れます。このような場合、
rspec --bisect5を使用して、どのスペックに問題があるかを判断できます。問題を解決するには、テストスイートで環境がどのように維持されているかをある程度理解する必要があります。続きを読んで各データストアの詳細をご覧ください。SQL database
database_cleanergemによって管理しています。各スペックはトランザクションに囲まれ、テストが完了するとロールバックされます。特定のスペックでは、完了後にすべてのテーブルに対してDELETE FROMクエリが発行されます。これにより複数のデータベース接続(ブラウザからの操作やマイグレーションスペックなどのスペックにとって重要な)から作成された行を表示できます。よく知られている
TRUNCATE TABLESアプローチの代わりにこれらの戦略を使用した結果の1つに、主キーと他のシーケンスがスペック間でリセットされないことがあります。したがって、スペックAでプロジェクトを作成してからスペックBでプロジェクトを作成すると、最初のプロジェクトはid = 1になり、2番目のプロジェクトはid = 2になります。これは、スペックがIDの値またはその他のシーケンス生成列に依存しないことを意味します。偶発的な競合を避けるため、スペックではこれらの種類の列に値を手動で指定することも避けてください。代わりに、未指定のままにして、行の作成後に値を検索します。
Redis
GitLabではRedisに、キャッシュされたデータとSidekiqジョブの2つのデータカテゴリを保存します。殆どのスペックではRailsキャッシュはメモリ内に存在しています。これはスペック間で置き換えられるため、
Rails.cache.readとRails.cache.writeの呼び出しは安全です。ただし、スペックが直接Redis呼び出しを行う場合は、必要に応じて:clean_gitlab_redis_cache、:clean_gitlab_redis_shared_state、:clean_gitlab_redis_queuestraitを適切に使用する必要があります。Background jobs / Sidekiq
デフォルトでは、Sidekiqジョブはジョブ配列にキューイングされ、処理されません。テストがSidekiqジョブをキューに入れて処理する必要がある場合は、
:sidekiq_inlinetraitを使用できます。
:sidekiq_might_not_need_inlinetraitは、Sidekiqのインラインモードがフェイクモードに変更されたときに、Sidekiqが実際にジョブを処理するのに必要なすべてのテストに追加されました。このtraitを持つテストは、Sidekiq処理ジョブに依存しないように修正するか、バックグラウンドジョブの処理が必要/予想される場合、:sidekiq_might_not_need_inlinetraitを:sidekiq_inlineに更新する必要があります。Note: ワーカーは
ApplicationJob/ActiveJob::Baseを継承していないため、perform_enqueued_jobsは現在使用できません。Filesystem
ファイルシステムのデータは、「リポジトリ」と「その他すべて」に大まかに分けることができます。リポジトリは
tmp/tests/repositoriesに保存されます。このディレクトリは、テストが実行される前、およびテストが終了した後に空になります。スペック間では空にならないため、作成されたリポジトリはプロセスの存続期間中、このディレクトリ内に蓄積されます。それらを削除するのはコストがかかりますが、注意深く管理しないと汚染につながる可能性があります。これらを回避するには、テストスイートでハッシュストレージを有効にします。つまり、リポジトリにはプロジェクトのIDに依存する一意のパスが与えられます。プロジェクトIDはスペック間でリセットされないため、各スペックがディスク上の独自のリポジトリを取得することが保証され、スペック間で変更が表示されないようにします。
スペックでプロジェクトIDを手動で指定する場合、または
tmp/tests/repositories/ディレクトリの状態を直接検査する場合、実行の前後にディレクトリをクリーンアップする必要があります。一般的に、これらのパターンは完全に回避する必要があります。アップロードなど、データベースオブジェクトにリンクされた他のクラスのファイルは、通常同じ方法で管理されます。スペックでハッシュストレージが有効になっている場合、IDによって決定される場所のディスクに書き込まれるため、競合は発生しません。
一部のスペックでは、
projectsfactoryに:legacy_storagetraitを渡すことで、ハッシュストレージを無効にします。これを行うスペックは、プロジェクトまたはそのグループのパスをオーバーライドしてはなりません。デフォルトのパスにはプロジェクトIDが含まれているため、競合しません。ただし、2つの仕様が同じパスを持つ:legacy_storageプロジェクトを作成する場合、ディスク上の同じリポジトリを使用し、環境汚染をテストします。その他のファイルは、スペックによって手動で管理する必要があります。たとえば、
tmp/test-file.csvファイルを作成するコードを実行する場合、スペックでは、クリーンアップの一環としてファイルが削除されるようにする必要があります。Persistent in-memory application state
Rspecによるスペックはすべて同じRubyプロセスを共有します。つまり、スペック間でアクセス可能なRubyオブジェクトを変更することで、互いに影響を与えることができます。これはグローバル変数、および定数(クラス、モジュールなどを含む)であることを意味しています。
通常、グローバル変数は変更しないでください。どうしても必要な場合、以下のようなブロックを使用して、変更を後でロールバックできます。
around(:each) do |example| old_value = $0 begin $0 = "new-value" example.run ensure $0 = old_value end endスペックで定数を変更する必要がある場合は、
stub_constヘルパーを使用して、変更が確実にロールバックされるようにする必要があります。
ENV定数を変更する必要がある場合は、代わりにstub_envヘルパーメソッドを使用できます。ほとんどのRubyインスタンスはスペック感で共有されませんが、クラスとモジュールは一般的に共有されます。クラスおよびモジュールのインスタンス変数、アクセサー、クラス変数、およびその他のステートフルイディオムはグローバル変数と同じように扱われるべきです。必要がない限り変更しないでください。とくに、変更の必要性を排除するために、expectまたはstubに沿った依存関係の代入かを使うのことが望ましいです。他に選択肢がない場合は、上記のグローバル変数と同様に
aroundブロックが使用できますが、可能な限り回避する必要があります。Table-based / Parameterized tests
このスタイルのテストは、包括的な入力範囲で1つのコードを実行するために使用されます。テストケースを1回指定するだけで、入力のテーブルとそれぞれの予想出力とともに、テストを読みやすく、コンパクトにすることができます。
GitLabではrspec-parameterizedgemを使っています。テーブル構文を使用し、Rubyの入力範囲をチェックする短い例は、次のようになります。
describe "#==" do using RSpec::Parameterized::TableSyntax where(:a, :b, :result) do 1 | 1 | true 1 | 2 | false true | true | true true | false | false end with_them do it { expect(a == b).to eq(result) } it 'is isomorphic' do expect(b == a).to eq(result) end end endCaution: whereブロックの入力として単純な値のみを使用します。プロシージャ、ステートフルオブジェクト、FactoryBotで作成されたオブジェクトなどを使用すると、予期しない結果が生じる可能性があります。
Prometheus tests
Prometheusメトリクス[6]は、テストの実行ごとに保持される場合があります。各サンプルの前にメトリクスが確実にリセットされるようにするには、Rspecテストに
:prometheusタグを追加します。Matchers
カスタムマッチャーを作成して、意図を明確にし、RSpecの予想の複雑さを隠す必要があります。これは
spec/support/matchers/に配置する必要があります。マッチャーは、特定のタイプのスペック(機能スペック、リクエストスペックなど)にのみ適用される場合はサブフォルダーに配置できますが、複数のタイプの仕様に適用する場合は配置しないでください。be_like_time
データベースから返される時間は、Rubyの時間オブジェクトと精度が異なる場合があります。そのため、スペックを比較する際に柔軟な許容範囲が必要です。
be_like_timeを使用して、時間が1秒以内であることを比較できます。expect(metrics.merged_at).to be_like_time(time)have_gitlab_http_status
have_http_statusよりもhave_gitlab_http_statusをお勧めします。have_gitlab_http_statusは、ステータスが一致しない場合に常に応答本文も表示できるためです。これは、テストが落ちたときにソースコードを編集せず、テストを再実行せずとも落ちた原因を知るのに非常に役に立ちます。特に500サーバーエラーが表示されている場合に便利です。
Shared contexts
すべての
shared contextは、spec/support/shared_contexts/に配置する必要があります。shared contextは、特定のタイプのスペック(機能スペック、リクエストスペックなど)にのみ適用される場合サブフォルダーに配置できますが、複数のタイプの仕様に適用される場合はそうではありません。各ファイルにはコンテキストが1つだけ含まれ、わかりやすい名前を付ける必要があります。
(e.g.spec/support/shared_contexts/controllers/githubish_import_controller_shared_context.rb.)Shared examples
すべての
shared exampleは、spec/support/shared_exampless/に配置する必要があります。shared examplesは、特定のタイプのスペック(機能スペック、リクエストスペックなど)にのみ適用される場合サブフォルダーに配置できますが、複数のタイプの仕様に適用される場合はそうではありません。各ファイルにはコンテキストが1つだけ含まれ、わかりやすい名前を付ける必要があります。
(e.g.spec/support/shared_exampless/controllers/githubish_import_controller_shared_example.rb.)Helpers
ヘルパーは通常、特定のRSpecのexampleの複雑さを隠すためのメソッドを提供するモジュールです。他のスペックと共有することを意図していない場合、RSpecファイルでヘルパーを定義できます。それ以外の場合は、
spec/support/helpers/に配置する必要があります。特定のタイプのスペック(機能スペック、リクエストスペックなど)のみに適用される場合、ヘルパーはサブフォルダーに配置できます。
ヘルパーはRailsの命名規則/名前空間規則に従う必要があります。たとえば、
spec/support/helpers/cycle_analytics_helpers.rbは以下のように定義する必要があります。module Spec module Support module Helpers module CycleAnalyticsHelpers def create_commit_referencing_issue(issue, branch_name: random_git_name) project.repository.add_branch(user, branch_name, 'master') create_commit("Commit for ##{issue.iid}", issue.project, user, branch_name) end end end end endヘルパーでRSpecの設定を変更しないでください。たとえば、上記のヘルパーモジュールには以下を含めないでください。
RSpec.configure do |config| config.include Spec::Support::Helpers::CycleAnalyticsHelpers endFactories
GitLabはテスト用のFixture[7]の代替としてfactory_botを使用します。
- Factoryは
spec/factories/で定義し、対応するモデルの複数形を使用して命名します(Userのfactoryはusers.rb)。- ファイルごとにトップレベルのファクトリ定義は1つだけにする必要があります。
- FactoryBotメソッドは、すべてのRSpecグループに混在しています。つまり
Factory.create(...)の代わりにcreate(...)を呼び出すことができます(そして呼び出す必要があります)。- traitを使用して定義と使用方法をクリーンアップします。
- ファクトリを定義するとき、モデルに関係のないカラムを定義しないでください。
- ファクトリをインスタンス化するときは、不要なカラムを指定しないでください。
- ファクトリはActiveRecordオブジェクトに限定される必要はありません。例を参照してください。
Fixtures
すべてのFixtureは
spec/fixtures/の下に配置する必要があります。Repositories
マージリクエストのマージなどの一部の機能をテストするには、特定の状態のGitリポジトリがテスト環境に存在する必要があります。GitLabは、特定の一般的なケースに対してgitlab-testリポジトリを維持します。プロジェクトファクトリの
:repositoryトレイトでリポジトリのコピーが使用されていることを確認できますlet(:project) { create(:project, :repository) }可能な場合は、
:repositoryではなく:custom_repoトレイトの使用を検討してください。これにより、プロジェクトのリポジトリのmasterブランチに表示されるファイルを正確に指定できます。let(:project) do create( :project, :custom_repo, files: { 'README.md' => 'Content here', 'foo/bar/baz.txt' => 'More content here' } ) endこれにより、デフォルトの権限と指定されたコンテンツを持つ2つのファイルを含むリポジトリが作成されます。
Config
RSpecの設定ファイルは、RSpecのコンフィグ(すなわち
RSpec.configure do |config|ブロック)を変更するファイルです。これはspec/support/に配置する必要があります。各ファイルには特定のドメインに関連する必要があります。たとえば、
spec/support/capybara.rb,spec/support/carriewave.rbなどです。ヘルパーモジュールが特定の種類のスペックにのみ適用される場合、
config.include呼び出しに修飾子を追加する必要があります。たとえば、spec/support/helpers/cycle_analytics_helpers.rbが:libおよびtype: :modelスペックにのみ適用される場合、次のように記述します。RSpec.configure do |config| config.include Spec::Support::Helpers::CycleAnalyticsHelpers, :lib config.include Spec::Support::Helpers::CycleAnalyticsHelpers, type: :model end構成ファイルが
config.includeのみで構成されている場合、これらのconfig.includeをspec/spec_helper.rbに直接追加できます。汎用的なヘルパーについては、
spec/fast_spec_helper.rbファイルで使用されるspec/support/rspec.rbファイルに含めることを検討してください。spec/fast_spec_helper.rbファイルの詳細については、高速ユニットテストを参照してください。注釈
- [1] first class citizenの訳がふわっとしていた(一級市民 or 第一級オブジェクト)のでこの記事をみて「最優先事項」との訳にした
- [2] ヒューリスティック評価:経験則(ヒューリスティックス)に基づいてユーザビリティを評価し、UI上の問題を発見する手法。ここでは「テストにおける経験則・ナレッジ」の意味合いに近い
- [3] 最も使用頻度の高いユースケースのテストをハッピーテストっていうんですね。知らなんだ...
- [4]
live_debugなんてメソッドCapybaraにもRspecにもいないぞと思ったらこういうことでした- [5] rspec --bisect
- [6] https://qiita.com/sugitak/items/ff8f5ad845283c5915d2
- [7] 初期データを投入する(https://qiita.com/itkrt2y/items/ca34fea17fc7dde56b7a)
- 投稿日:2020-01-14T22:33:22+09:00
トランザクションとは
IT用語トランザクションについて
複数の処理を1つにまとめたもの。
ただし、これら「複数の処理」は分離させることはできないこと。具体例
- Aさんの口座から100円分差し引き、残高1,000 - 100 = 900円にする。
- Bさんの口座へ100円分プラスし、残高2,000 + 100 = 2100円にする。
1.の処理がうまくいって、2.の処理が何らかの原因で失敗したとする。そうなると、
Aさんの口座残高は5,000円になっているいる一方で、Bさんの口座残高は20,000円のままで、5000円が「消失」してしまうことになる。まとめ
トランザクションは成功か失敗かの二択
- 投稿日:2020-01-14T22:01:53+09:00
お名前.comを使い、独自ドメイン取得し、herokuデプロイする
こんにちは。
初学者の方で転職活動などの為にポートフォリオを作成している方も多いと思います。その際にherokuを使ってデプロイする人が多いと思うのですが、
URLが、
〜herokuapp.comとなってしまい、なんかカッコ悪いなあって思いまして、
AWSを使って色々やろうとしたのですが、ポートフォリオだからそこまで口数をかけたくないと思い
独自ドメインを使い、herokuで、デプロイすることにしました。
その手順を載せさせていただきます。
初学者の方への参考になれたら幸いです。※前提として
Herokuにアプリをデプロイ済みであることとします1.お名前.comで独自ドメインを取得する
にて
取得したいドメイン名を入れて検索する追加できるものを探し、
個人情報、クレジット情報を入力する
ここでは
test.work
を取得したことにして進めます。2.herokuの設定
herokuはhobbyプラン(無料の一つ上の7$のプラン)以上じゃないと独自ドメインが使えないためです。
ちなみにこちらは
7$/月の料金がかかってしまいます。Herokuのプランはアカウントごとではなく、アプリケーションごとに設定します。例えば、2つのアプリケーションをHerokuにデプロイしている場合、それぞれのアプリケーションに対して無料・有料プランにするかどうかを設定することになります。
herokuをhobbyプランにする
https://dashboard.heroku.com/apps
より、
デプロイするアプリを押下、詳細画面で、
Resources > [Change Dyno Type]を押下し、
[Hobby]を選択し[save]を押下します。heroku側のドメイン設定とSSL設定
[Settings]を押下し、[Add domain]を押下します。
お名前.comで取得したドメインに
www.
を追加し入力し、[Next]を押下します。DNS target
が表示されるので、コピーします。次に[Configure SSL]を押下し、
Automatic Certificate Management (ACM)
を選択し、[Next]を押下します。
確認画面になるので、もう一度[Next]を押下します。
最後に[Finish]を押下します。
3.お名前.comの設定
再びお名前.comにいき、
[ドメイン設定]を押下、
[DNS関連機能の設定]を押下、
[DNS設定/転送設定]を押下します。TYPE→CNAME
ホスト名→wwwを入力
VALUEには、先程herokuでコピーしたDNS Targetを貼り付け
[追加]を押下します。画面下部まで進み確認へ進み、
[確認内容へ進む]を押下します。これで、設定は完了です!!
※UI上でうまくいかない場合は
コマンドでの設定をおすすめします
こちらを参考に!
https://medium.com/@kjmczk/heroku-cdomain-ssl-1b4cae424e61反映まで数時間かかるようなので、
メールが来るまで待ちましょう!!ドメインが反映される前に取得したドメインにアクセスするとお名前.comのページに飛ばされ『このドメインは取得されています』と表示される思いますが、心配せず気長に待ってください。
24〜72時間の間でドメインが反映されるらしいのですが、
自分の場合は数十分で
反映されました!無事に公開されました!!
- 投稿日:2020-01-14T21:45:55+09:00
Rails エラーメッセージの表示と日本語化
エラーメッセージの表示
上記の画像のようにタイトルとブログ本文が空だった場合はエラー表示される様に実装する事。
モデルにバリデーションを設定
バリデーションを付けたいモデル(今回はpost.rb)に記載。
post.rbclass Post < ApplicationRecord validates :title, :content, presence: true endtitleカラムとcontentカラムが空を防ぐ。
エラーメッセージのファイルの作成
エラーメッセージはエラーが発生すると、_error_messages.html.erb内に格納される。
layouts/_error_messages.html.erb% if model.errors.any? %> <div class="alert alert-warning"> <ul> <% model.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %>フォーム(form_with)の中にrenderで挿入
posts/new.html.erb<%= form_with model: @post, class: :form, local: true do |form| %> #renderメソッドで_error_messages.html.erbを呼び出す。 <%= render 'layouts/error_messages', model: form.object %> <%= form.text_field :title, placeholder: :タイトル, class: :form__title %> <%= form.text_area :content, placeholder: :ブログ本文, class: :form__text %> <%= form.submit '投稿する', class: :form__btn %> <% end %>これで表示は完了。
次は日本語化実装へ。エラーメッセージの日本語化
Gemfilegem 'rails-i18n'Gemfileに以下の一文を追加して、bundle install。
日本語化の基となるファイルを作成する
Railsの多言語化対応は、ymlファイルで管理。
config/locales ディレクトリ直下に、ja.ymlを作成。ターミナル$ touch config/locales/ja.ymlカラム名の日本語化
config/locales/models/ja.ymlja: activerecord: attributes: post: title: 名前 content: ブログ本文ja.ymlの注意点
Railsはymlファイルの改行とインデントで日本語化のパスを参照している為、
attributes: => モデル名 => カラム名 の順に改行とインデントを入れる必要がある。config/locales/models/ja.ymlattributes: # attributes:の直下に post: # モデル名を指定し title: 名前 # カラム名を指定する。 content:ブログ本文 # カラム名を指定する。
- 投稿日:2020-01-14T21:40:17+09:00
次のunless文をif文に書き換えてください、という問題。
問題
1 if a + b > 0
2 puts "計算結果は0より大きいです"
3 end模範回答
1 unless a + b <= 0
2 puts "計算結果は0より大きいです"
3 end解説
unless 条件式 then
条件式が偽の時に実行する処理
end
上記が私の参考にしたunless文の使い方です。今回の場合でいうと、
aとbの合計値が0以下でない時 = aとbの合計値が0より大きい時
unless文 = if文
どちらも同じ条件の内容を示します。
※表現に誤りのある箇所があった為、訂正済みです。
間違った解釈の見える箇所がありましたら、コメントしていただきたいです。今後の参考にさせていただきたいと考えております。
- 投稿日:2020-01-14T21:29:51+09:00
次のif文をunless文に置き換えてください、という問題。
問題
1 if a + b > 0
2 puts "計算結果は0より大きいです"
3 end模範回答
1 unless a + b <= 0
2 puts "計算結果は0より大きいです"
3 end解説
unless 条件式 then
条件式が偽の時に実行する処理
end
上記が私の参考にしたunless文の使い方です。今回の場合でいうと、
aとbの合計値が0以下でない時 = aとbの合計値が0以上である時
unless文 = if文
どちらも同じ条件の内容を示します。
間違った解釈をしている箇所がありましたら、コメントしていただきたいです。今後の参考にさせていただきたいと考えております。
- 投稿日:2020-01-14T20:05:07+09:00
初心者によるプログラミング学習ログ 210日目
100日チャレンジの210日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
210日目は
おはようございます
— ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) January 13, 2020
210日目
udemyでRuby、javascript
前にRubyの環境構築やっておいたからよかった#100DaysOfCode #駆け出しエンジニアと繋がりたい #早起きチャレンジ
- 投稿日:2020-01-14T19:52:46+09:00
【Ruby】Seleniumで露骨な人間アピール
はじめに
seleniumを使用してサイト調査をしておりまして、
昨今のスクレイピング禁や例の図書館事件も含めビビり倒しながらの調査の私です。
問題が発生したわけではないのですが、
露骨に人間アピールをしようと思って下記のようなメソッドを作ってみました。
多分みんなやっていると思いますが。該当ソースコード
def rndSleep rnd = rand(5) + 1 sleep rnd.to_i end
rand(5) + 1で1~5のランダムな数字をrudに代入して、
動作を〇秒間停止するsleepメソッド、〇秒部分に当てています。人間アピールしたい箇所に
rndSleepを入れると1~5秒おいて実行してくれます。
私は繰り返し処理の、処理開始前に一息ついてもらう感じにしてます。while true do index = index + 1 rndSleep # <= ここで一息 begin news = driver.find_element(:xpath, "/html/body/div[3]/div[1]/div[2]/div[2]/div/table/tbody/tr[#{index}]/td[2]/a") href = news.attribute('href') newsUrl << href rescue Selenium::WebDriver::Error::NoSuchElementError break end endおわりに
実際にBANされたりとか、ブロックされたりはないのですが、
されたら怖いのでちょっとでも抗いたい。
中身の調査をして抜け漏れ予防したいので、負荷かけたいわけではない。
つまり共存したいのです。
なので、プログラム実行側でうまいこと負荷を分散させて、
「人間ですよ~いいコンテンツですね~たくさん回遊しちゃうな~」
的なアピールをして乗り切る必要があるのではないかと感じました。ちなみに、要素が表示されるまで待つことにsleepメソッドを使用するのは効率が悪いので、
下記の記事を参考にしていただいた方が良いかと思います。参考記事
- 投稿日:2020-01-14T18:47:04+09:00
超初心者がwebpackerについて調べてみたぞ
Ruby on Rails を使って開発を始めた今日この頃。
サーバーサイドはそれとなく出来てきたからそろそろフロントも固めて行こうかしら。なんて思っていた僕はBootstrapをRailsで使おうと考えた。Bootstrapを使うのはいたって簡単。htmlのhead内に以下のリンクをぶち込めばいいだけ。application.html.erb<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">なんて便利だこと。
しかし、Bootstrapを使うには他にも方法はある。それは以下のリンクにある通りだ。
https://qiita.com/rhistoba/items/f724dae231d7e28bf477
つまり、railsにBootstrapをインストールしてしまう方法である。
基本的には、リンクの記事通りに手順を踏めばインストールできるのであるが、超初心者の僕はいくつかのワカラナイ点があったので自分用のメモとして残すことにした。前提
僕のスペック
- プログラミング学習を始めて1ヶ月
- HTML/CSS/Javascript/Ruby/Railsをprogateで一応学習済
- Ruby on rails でポートフォリオを作成中
開発環境
- 端末 : LENOVO ideapad 530S-14ARR
- OS : Windows 10 Home ver.1809
- シェル : PowerShell 5.1.17763.771
- Ruby : 2.6.4
- rails : 5.2.4.1
そもそもwebpackerってなんだ?
webpackerとはwebpackをRubyで使えるようにしたものらしい。
僕「webpackかぁ~…聞いたことあるよ。…でもよく知らない。」webpackとは?
調べたところ、webpack というのは
Webpackとは、CSS、JavaScript、画像などを1つのファイルとしてまとめるためのモジュールバンドラーで、node.jsのモジュールの1つです。
とのこと。(引用元:https://www.sejuku.net/blog/68146)
僕「モジュールバンドラーってなんだよぉ(´;ω;`)」
僕「node.jsもよく分かんねーよぉ(´;ω;`)」
調べても分からないが続く。まさに分からないリレー状態。モジュールバンドラーとは?
次にモジュールバンドラーについて知らべてみた。
モジュールバンドラーとはその名の通り、モジュール(部品)をまとめたものをいうらしい。ここでモジュールとはあるプログラムと考えるのが良さげ。例えば、現在時刻を表示するプログラムを作るとしよう。ここで、現在時刻を取得するコードと、それを表示するコードと分けて作ったとする。これらのコードを合体させたいのだが、その方法として、表示するためのコードに現在時刻を取得するコードをインポートすることにしよう。この時、インポートされる側のコードをモジュールと呼ぶ。
このような便利なコード集をモジュールバンドラーというみたい。
(参考:https://note.com/billion_dollars/n/n596fecfdeb2e)node.jsとは?
node.jsとはサーバーサイドJavascriptである。
Javascriptは本来、ブラウザで動き見た目を作る(フロントで活躍する)言語なのだが、「この言語でサーバーサイドも作れたら嬉しくね?」という発想から作られたJavaScript 環境なんだとか。僕「なるほどぉ。すごいじゃんnode.js」
(参考:https://eng-entrance.com/what-is-nodejs#Nodejs-2)
改めてwebpackって何ぞや?
ここまで調べたことをまとめて、もう一度考えるとwebpackとは、
CSS、JavaScript、画像などの部品を上手にまとめて1つにするnode.js(Javascript環境の1つ)のモジュールだ!
ということですね。要するにまとめ上手なお兄さんみたいな(雑)
とはいえ、なんでそんなにまとめたがるのか?
なんとなくwebpackについて分かったけど、まとめることにどんなメリットがあるのかしら?調べてみると通信との関係があるみたいだ。
僕たちがwebサイトを閲覧する時は、自分のPCからサーバーにリクエストを送り、そのレスポンスとしてあるwebページ(htmlファイルとか)を返してくれる。
しかし、そのhtmlが様々なコード(モジュール)や画像、css、javascriptなどを引用してきている時には、それらも同時に送ってやらないと不完全なwebページしか閲覧できない。だからそういう関係するファイルも一緒に送ってやるのだが、これらがバラバラだとサーバーがPCに送るのに時間が掛かってしまうみたい。
ここでそれらのファイルが1つにまとまっていることで素早く通信できるようだ。まとめ
webpackerのことを調べて、本来の目的であるBootstrapのインストール忘れてた(/ω\)
- 投稿日:2020-01-14T17:39:04+09:00
ruby console をするとエラーが出ちゃう
僕「ruby console が使いたいなぁ」
僕「progate先生がターミナルにruby consoleって入力すれば使えるって言ってたな」
…入力
ターミナル「エラーですわ」
僕「まじか」←今ここ前提
僕のスペック
- プログラミング学習を始めて1ヶ月
- HTML/CSS/Javascript/Ruby/Railsをprogateで一応学習済
- Ruby on rails でポートフォリオを作成中
開発環境
- 端末 : LENOVO ideapad 530S-14ARR
- OS : Windows 10 Home ver.1809
- シェル : PowerShell 5.1.17763.771
- Ruby : 2.4.9
- rails : 5.2.4.1
本題
Ruby on rails を使ってアプリを作っていた僕は、データーベースの内容が知りたくなって、ターミナルから以下のコマンドを打ち込んだ。
ruby consoleその結果、以下のエラーが…
Loading development environment (Rails 5.2.4.1) This version of IRB is drastically different from the previous version. If you hit any issues, you can use "irb --legacy" to run the old version. If you want to just erase this message, please use "irb --multiline". C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/reline-0.0.7/lib/reline/line_editor.rb:1020:in `calculate_width': undefined method `grapheme_clusters' for "":String (NoMethodError) from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/reline-0.0.7/lib/reline/line_editor.rb:349:in `rerender' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/reline-0.0.7/lib/reline.rb:210:in `inner_readline' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/reline-0.0.7/lib/reline.rb:160:in `readmultiline' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb/input-method.rb:259:in `gets' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb.rb:518:in `block (2 levels) in eval_input' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb.rb:694:in `signal_status' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb.rb:517:in `block in eval_input' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb/ruby-lex.rb:164:in `lex' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb/ruby-lex.rb:136:in `block (2 levels) in each_top_level_statement' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb/ruby-lex.rb:133:in `loop' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb/ruby-lex.rb:133:in `block in each_top_level_statement' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb/ruby-lex.rb:132:in `catch' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb/ruby-lex.rb:132:in `each_top_level_statement' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb.rb:536:in `eval_input' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb.rb:471:in `block in run' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb.rb:470:in `catch' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb.rb:470:in `run' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/irb-1.1.0/lib/irb.rb:399:in `start' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.2.4.1/lib/rails/commands/console/console_command.rb:64:in `start' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.2.4.1/lib/rails/commands/console/console_command.rb:19:in `start' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.2.4.1/lib/rails/commands/console/console_command.rb:96:in `perform' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/thor-1.0.1/lib/thor/command.rb:27:in `run' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.2.4.1/lib/rails/command/base.rb:69:in `perform' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.2.4.1/lib/rails/command.rb:46:in `invoke' from C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.2.4.1/lib/rails/commands.rb:18:in `<top (required)>' from bin/rails:4:in `require' from bin/rails:4:in `<main>'なんてこった。ちょこっとコマンドを打ち込んだだけなのに、これほどの長文で怒られるとは。しくしく…
とりあえず適当に検索して直そうと試みる
なんでエラーが出ちゃうのか。検索してみると以下の記事が見つかった。
https://qiita.com/roki1801/items/7e4a371ae0b9ba928f55
この記事に従ってrb-readlineをインストールしてみた。その上で再びトライ。
僕「今度こそいけるやろ…」
…入力
ターミナル「またエラーですわw」
僕「ムキー!」もう、打つ手が無くなった…。もう僕は
rails consoleが使えないRubyエンジニアとして生きて行くしかないのか…と、絶望してふて寝しようとした時、エラー文にLoading development environment (Rails 5.2.4.1) This version of IRB is drastically different from the previous version. If you hit any issues, you can use "irb --legacy" to run the old version.と書いてあることに気付く。和訳すると
「お前が使ってるのはRails 5.2.4.1だわ。そんで、IRBのバージョンは以前のと全然違うから、必要であればIRBのバージョン落とせば?」
そう。問題はどうやらバージョンに起因するもののようだ。上記のリンクに示した解決法と今回の件は全然関係ないのである。ちゃんとエラー文を読まないせいで余計なことをしてしまった。僕「…ところでIRBってなんやねん。」
そう思った僕は謎のIRBを調べてみた。するとIRBは”Interactive Ruby”の略で、対話的にプログラムを実行するためのシステムなんだとか。
僕「ほー。ってことはこいつはそもそもRuby consoleを動かす中身的な奴じゃね?」
僕「つまり、このIRBのバージョンとrailsのバージョンがマッチしていないのね」
僕「ほいじゃ、railsのバージョンを最新にしてみようかしら。」
そうして、RubyとRailsをアップデートしてみる。
(RubyとRailsのアップデートに関しては長くなるので別の記事で)アップデートしRubyとRailsはそれぞれ以下のバージョンに。
- Ruby 2.4.9 → 2.6.4
- rails 5.2.4.1 → 5.2.4.1
ここで、railsのバージョンが変わっていないことに気づく。
あれ?railsのバージョンが古いからrails consoleが使えなかったのではないのか…?
まぁとりあえず、rails consoleを実行できるか確かめてみるか。
そうしてターミナルにrails consoleを入力すると…Loading development environment (Rails 5.2.4.1) irb(main):001:0>どうやら上手いこと動いている。
この結果からみるとrubyのバージョンのせいでconsoleが使えなかったのか??まとめ
理由はよく分かっていないが、上記のようなエラーが出た場合にはRubyのアップデートが有効そう。同じ境遇の人は是非一度試してみて欲しい。また、この問題を理解できている人がいおられれば是非ご教授を願いたい。
あと、当たり前だがエラー文はちゃんと読もう(/ω\)
- 投稿日:2020-01-14T15:56:53+09:00
Ruby|クラスメソッド内の super について
はじめに
本稿は
superについて書いています。普段はインスタンスメソッドでsuperを利用するシーンがあると思いますが、クラスメソッドだと混乱することがあったのでまとめになります。super is 何?
superをメソッドで呼び出すと、親クラスにある同名のメソッドを呼び出します。メソッドがなければ例外を起こします。class Parent def do(something) p something end end class Child < Parent def do super('something') end end c = Child.newインスタンスメソッドだと、
ancestorsを使えばどのように探索をするかヒントになります。先の例だとChildクラスの継承関係にParentクラスがあるので、そこからメソッドを探すことが出来ています。もし、期待するメソッドが
Parentクラスになければ更に親のクラスを探索します。さらに親のObjectクラスを探索してなければ、Kernelクラスを探索します。最後はBasicObjectクラスですね。p Child.ancestors #=> [Child, Parent, Object, Kernel, BasicObject]ハマったこと
仕事で pundit の中を調査することがあり、次のような記述を見つけました。
includedはモジュールがインクルードされたときのコールバックでbaseクラスに対して更に拡張をする場合(クラスメソッドの追加など)によく使われます。module PolicyExampleGroup include Pundit::RSpec::Matchers def self.included(base) base.metadata[:type] = :policy base.extend Pundit::RSpec::DSL super # これ end endさて、この
superはどのクラスで定義しているincludedメソッドでしょうか。はじめはancestorsで調べればわかると思っていたのですがモジュールは親クラスを持たないのです。。。それでも例外にならない、なぜ?
p Pundit::RSpec::PolicyExampleGroup.ancestors #=> [Pundit::RSpec::PolicyExampleGroup]Ruby はクラスメソッドは特異クラスに定義されているので、クラスメソッドで
superを使うと探索は特異クラスの継承関係で行われます。
見つける対象になるメソッドはインスタンスメソッドであることに注意
p Pundit::RSpec::PolicyExampleGroup.singleton_class.ancestors #=> [#<Class:Pundit::RSpec::PolicyExampleGroup>, Module, ..., Kernel, BasicObject]今回は
Moduleクラスにあるインスタンスメソッドにマッチしたのでそれが実行されています。オーバーライドしなければnilを返すだけのメソッドなので削除しても良さそうですね![]()
ひとまず、拙い英語で pull request を作成しましたがどうなることやら。。。
![]()
- 投稿日:2020-01-14T14:14:08+09:00
AWS Cloud9 へ mysql2 のgemを導入する時にエラーが出てなんとか解決した
Rubyの学習でデータベースを使おうと思って、
データベースといえばMySQLと思いつきでインストールしてしまい、
そのまま使えないじゃん!って思い、
mysql2というgem使えば使えるのか!と調べて気づき
mysql2がエラー出て入らねぇよ!!!と困り、
google大先生とQiitaの各先人様のおかげで導入できた
この流れの記録を書いておきます。
とりあえずスタートはmysql2の導入エラーから
まぁ困った
実際にはこんな感じ
ec2-user:/ $ sudo gem install mysql2 Building native extensions. This could take a while... ERROR: Error installing mysql2: ERROR: Failed to build gem native extension. /usr/bin/ruby2.0 extconf.rb mkmf.rb can't find header files for ruby at /usr/share/ruby/include/ruby.h Gem files will remain installed in /usr/local/share/ruby/gems/2.0/gems/mysql2-0.5.3 for inspection. Results logged to /usr/local/share/ruby/gems/2.0/gems/mysql2-0.5.3/ext/mysql2/gem_make.outそもそもまずこれやってる時点の私はCUIが苦手で、
エラーに書いてあるディレクトリまで移動してもあまり意味わかっておらず、
usr/local/share/の中にrubyフォルダ無かったりと散々でしたw結論は
https://qiita.com/higeo_kk/items/828d9f11cdc69c85c078
この方の記事通りでさくっと解決してしまった・・・
ruby-develがなかったのかな?
develってことはディベロッパーツール?
今は腹落ちしてないけどこの辺は環境構築で絶対にハマるところだと
私の未熟な勘でも感じているので、また後日解明したい。
- 投稿日:2020-01-14T13:38:40+09:00
処理の前後で作成されたObject数を数える
GC.start allocated_before = GC.stat(:total_allocated_objects) #=> ex: 108391 # ..何らかの処理.. allocated_after = GC.stat(:total_allocated_objects) #=> ex: 108871 puts "Object count: #{allocated_after - allocated_before}"Ref. https://gist.github.com/apauly/3f547f06e83b66e4187e48519b426464
- 投稿日:2020-01-14T13:14:09+09:00
#Rspec + #Ruby / overwrite class method argument or method return value
# https://relishapp.com/rspec/rspec-mocks/v/3-9/docs/configuring-responses/wrapping-the-original-implementation class You def self.say(message: ) { message: message } end end RSpec.describe do it do expect(You.say(message: 'YES')).to eq({message: 'YES'}) end it 'adds hash key value to method return hash' do allow(You).to receive(:say).and_wrap_original { |method, *args| method.call(*args).merge(hello: 'EVERYONE') } expect(You.say(message: 'YES')).to eq({message: 'YES', hello: 'EVERYONE'}) end it 'overwrites method receives argument' do allow(You).to receive(:say).and_wrap_original { |method, *args| method.call(message: 'OH') } expect(You.say(message: 'YES')).to eq({message: 'OH'}) end end class API def self.solve_for(x) (1..x).to_a end end RSpec.describe "and_wrap_original" do it "can be overridden for specific arguments using #with" do allow(API).to receive(:solve_for).and_wrap_original { |m, *args| m.call(*args).first(5) } allow(API).to receive(:solve_for).with(2).and_return([3]) expect(API.solve_for(20)).to eq [1,2,3,4,5] expect(API.solve_for(2)).to eq [3] end end # $ rspec /Users/yumainaura/.ghq/github.com/YumaInaura/YumaInaura/rspec/wrapping.rb # and_wrap_original # can be overridden for specific arguments using #with # is expected to eq {:message=>"YES"} # adds hash key value to method return hash # overwrites method receives argument # Finished in 0.01419 seconds (files took 0.1395 seconds to load) # 4 examples, 0 failuresOriginal by Github issue
- 投稿日:2020-01-14T11:22:55+09:00
【Ruby on Rails】デフォルトメッセージの日本語化
エラーメッセージなどのデフォルトメッセージを日本語化する設定です。
バージョン情報
Ruby 2.6.3
Ruby on Rails 5.2.3設定方法
config/initializers/配下にlocale.rbというファイルを作成します。ファイル名は何でも良いですが習慣上locale.rbにしてあります。下記の2文を記載します。
config/initializers/locale.rbI18n.config.available_locales = :ja I18n.default_locale = :ja日本語の辞書ファイルを作成します。
config/locales/にja.ymlというファイルを作成し、下記のURLの本文を作成したファイルにすべてコピペします。https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml
モデル名などはまだ英語のままなので、個別で日本語化していきます。
config/locales/にmodel.ja.ymlというファイルを作成します。config/locales/model.ja.ymlja: activerecord: models: post: 投稿 user: ユーザー attributes: post: content: 内容 image: 画像 user: name: 名前 email: メールアドレス current_password: 現在のパスワード password: パスワード password_confirmation: 確認用パスワード以上です。
- 投稿日:2020-01-14T06:43:24+09:00
インクリメント・デクリメントの書き方のまとめ(Scala、Java、Rust、C言語、C++、Go言語、PHP、Perl、Python、Ruby、JavaScript)
いろんな言語を触っていると、言語の細かい仕様がだんだんごっちゃになってきてしまいますので、メモです。
インクリメント・デクリメントの有無
あり: Java、C言語、C++、Go言語△、PHP、Perl、JavaScript
なし: Scala、Rust、Python、RubyGo言語は式を構成する演算子ではなく文(statement)という扱いにすることで、インクリメントの演算子としての問題を回避していて、個人的にはちょうどいい仕様に感じます。
ついでに代入演算子も確認しましたが、こちらはだいたいの言語にあるようです。
Scala
- インクリメント・デクリメント演算子はない
- 代入演算子はある
i += 1 i -= 1
i += 1などはi = i + 1などのシンタックスシュガー。参考
Assignment Operators - Expressions | Scala 2.13
Scalaでは、なぜインクリメントやデクリメントができないのか?
Java
- インクリメント・デクリメント演算子は前置・後置ともにある
- 式であり値を返す
- 代入演算子もある
++i; --i; i++; i--; i += 1; i -= 1;参考
Prefix Increment Operator ++ - Java Language Specification
Rust
- インクリメント・デクリメント演算子はない
- 代入演算子はある
i += 1; i -= 1;参考
Compound assignment expressions - Operator expressions - The Rust Reference
なぜインクリメント演算子がないのか?
Why doesn't Rust have increment and decrement operators?C言語、C++
- インクリメント・デクリメント演算子は前置・後置ともにある
- 式であり値を返す
- 代入演算子もある
++i; --i; i++; i--; i += 1; i -= 1;Go言語
- C言語でいうインクリメント・デクリメント演算子は後置のみ
- 式ではなく文の扱いなので、式の中には埋め込めない
- 代入演算子もある
i++ i-- i += 1 i -= 1参考
IncDec statements - The Go Programming Language Specification
++や--が演算子ではない件
演算子とステートメント — プログラミング言語 Go | text.Baldanders.infoPHP
- インクリメント・デクリメント演算子は前置・後置ともにある
- 式であり値を返す
- 代入演算子もある
++$i; --$i; $i++; $i--; $i += 1; $i -= 1;参考
Perl
- インクリメント・デクリメント演算子は前置・後置ともにある
- 式であり値を返す
- 代入演算子もある
++$i; --$i; $i++; $i--; $i += 1; $i -= 1;参考
インクリメントとデクリメント - perlop - Perl の演算子と優先順位 - perldoc.jp
Python
- インクリメント・デクリメント演算子はない
- 代入演算子はある
i += 1 i -= 1累算代入文というらしい。
参考
累算代入文 (augmented assignment statement) - 単純文 (simple statement) — Python 3.8.0 ドキュメント
Ruby
- インクリメント・デクリメント演算子はない
- 代入演算子はある
i += 1 i -= 1自己代入というらしい。
参考
Ruby にインクリメント演算子のようなものが無い理由 - fugafuga.write
Rubyのインクリメント速度のバージョンごとの比較 - Qiita
JavaScript
- インクリメント・デクリメント演算子は前置・後置ともにある
- 式であり値を返す
- 代入演算子もある
++i; --i; i++; i--; i += 1; i -= 1;参考
Update Expressions - ECMAScript® 2019 Language Specification
- 投稿日:2020-01-14T03:04:21+09:00
ActionView::MissingTemplate in Groups#newの一例
1.どんなエラー?
renderメソッドで表示しようとしている、viewファイルがありませんという内容です
筆者の場合は同じgroupsフォルダ内のformというファイルで記載したものを引用しnewファイルで表示しようとしていました。(下記参照)
<エラー文>
<エラーに関係したgroupsフォルダ内のファイル>
new.html.haml.chat-group-form %h1 新規チャットグループ = render partial: 'form', locals: { group: @group }form.html.haml= form_for group do |f| .chat-group-form__errors %h2 10件のエラーが発生しました %ul %li nameを入力してください .chat-group-form__field .chat-group-form__field--left = f.label :name, class: 'chat-group-form__label' .chat-group-form__field--right = f.text_field :name, class: 'chat__group_name chat-group-form__input', placeholder: 'グループ名を入力してください' .chat-group-form__field.clearfix / この部分はインクリメンタルサーチ(ユーザー追加の非同期化のときに使用します .chat-group-form__field.clearfix .chat-group-form__field--left %label.chat-group-form__label{:for => "chat_group_チャットメンバー"} チャットメンバー .chat-group-form__field--right / グループ作成機能の追加時はここにcollection_check_boxesの記述を入れてください = f.collection_check_boxes :user_ids, User.all, :id, :name / この部分はインクリメンタルサーチ(ユーザー追加の非同期化のときに使用します .chat-group-form__field.clearfix .chat-group-form__field--left .chat-group-form__field--right = f.submit class: 'chat-group-form__action-btn'2.原因
構文を確認してみるとどこにも間違いがないため、悩んでいたところ、ありました、partial: 'form'という一文が。
partialというのはフォルダ内の"部品名となっているファイル"を引用しますよという意味があり、通常のファイルに対してpartialという縛りを増やすと読み込みを行いません。
つまるところpartialで参照したファイルのファイル名は"部品"であることを意味する'_(アンダーバー)'から始めなければならないのです。3.解決方法
結論としてはpartialを使って呼び出すファイルは"_(アンダーバー)"から始まるファイル名とすればエラー要因の一つが取り除かれるということになります。
ちなみに筆者の場合の例を確認してみましょう。上記に添付した筆者のファイル名を見てみるとformのファイル名が部品の形となっていませんね。なのでform.html.haml→_form.html.hamlとすることによりエラー文は解消されます。

















