- 投稿日:2019-02-27T23:53:20+09:00
payjp.jsの導入方法<Rails>
Payjp.jsを導入するにあたって、理解するのに時間がかかってしまったので(なにせ記事が少ない!)今後導入される方の時間短縮のために、ここに残しておきます。
Pay.jpとは
Pay.jpのサービスを利用することでクレジットカード決済機能を簡単に導入することができます。
gem'payjp'をインストールすることで使用可能に。
利用方法については大きく2通りあります。「チェックアウト」
公式で用意されたスクリプトタグをHTMLに記述すれば、デザインされた決済フォーム、カード情報のバリデーション、カード情報のトークン化を行うフォームを生成することができます。こちらを使用すれば、ささっとすぐに実装可能です。
ビューについてこだわりがないという方であればこちらで十分だと思います。「カスタムフォーム(payjp.js)」
payjp.jsを使うことで、好きなデザインや挙動でトークン化を行うフォームを組み込めます。
ここで注意をしたいのが、payjp.jsはトークン化に特化したライブラリであり、これを使用したからといって決済ができる訳ではありません。
クレジットカード情報入力ページは自分の好みのビューにしたい!という方はこちらです。
今回はこのpayjp.jsで実装していくための説明となります。トークンとは
クレジットカード情報を自身のデータベース上で管理するのはセキュリティの観点で好ましくないので、顧客が入力したカード情報をトークン化しなくてはいけません。
顧客情報を持った情報の塊のことをトークンを呼びます。IDを使用することで顧客情報を呼び出すことができます。トークン化については公式を参考にしてください。
https://pay.jp/docs/cardtokenまたトークンは1度のみの使用しか出来ないので、2度以上使いたい場合は顧客カードを作成してカード情報をそこに紐付けることが必要です。顧客カードへの紐付けというのは後ほど説明します。
いざ導入!
ここからは実際のコードを交えて説明します。
まずは、顧客がカード情報を入力するためのフォームを作成します。qiita.html.haml%h2 クレジットカード情報入力 = form_tag("/users/purchase", method: "PATCH", id: "charge-form") do %label カード番号 %input{maxlength: "16", type: "text", class: "number", id: "payment_card_no" name: "number", placeholder: "カード番号"} %label CVC %input{type: "text", class: "cvc", id: "payment_card_security_code", name: "cvc", maxlength: "3", placeholder: "CVC"} %label 有効期限 %input{type: "text", class: "exp_month", id: "payment_card_expire_mm", name: "exp_month", maxlength: "2", placeholder: "月"} %input{type: "text", class: "exp_year", name: "exp_year", maxlength: "4", placeholder: "年"}Pay.jpにトークンを作成してもらうには、公式で用意されているフォームを活用しましょう。
(本記事では所々書き換えています。)qiita.js$(document).on('turbolinks:load', function() { var form = $("#charge-form"); Payjp.setPublicKey('pk_test_0383a1b8f91e8a6e3ea0e2a9'); $("#charge-form").on("click", "#submit-button", function(e) { e.preventDefault(); form.find("input[type=submit]").prop("disabled", true); var card = { number: parseInt($("#payment_card_no").val()), cvc: parseInt($("#payment_card_security_code").val()), exp_month: parseInt($("#payment_card_expire_mm").val()), exp_year: parseInt($("#payment_card_expire_yy").val()) }; Payjp.createToken(card, function(s, response) { if (response.error) { alert("error") form.find('button').prop('disabled', false); } else { $(".number").removeAttr("name"); $(".cvc").removeAttr("name"); $(".exp_month").removeAttr("name"); $(".exp_year").removeAttr("name"); var token = response.id; $("#charge-form").append($('<input type="hidden" name="payjp_token" class="payjp-token" />').val(token)); $("#charge-form").get(0).submit(); } }); }); });顧客がsubmitボタンを押した瞬間にこのjsファイルが反応するようにしてあげます。
このフォームの中のPayjp.createTokenで作成されたトークンIDがresponse.idに返ってきます。
後はif文で分岐をさせてあげて、最後にe.preventDefault();によって停止させていたsubmitを実行させます。setPublicKeyにはpay.jpにログインした際の管理画面で確認できるAPIキーを入れてください。
APIキーはconfig/initializers/setting.rbを作成してその中に変数を定義して入れてあげるとrbファイル間で共有できるので、利便性・セキュア面で良いですね!
(記載しているAPIキーは公式のものなのでご心配なく)qiita.html.haml%input.payjp-token{ type: "hidden", name: "payjpToken", value: "" }そしてHTML上で上記の記述をして、jsファイルで作成したトークンIDが空のvalueに入ることで、paramsとしてコントローラーへ投げることができます。
inputタグをhiddenにすることでビュー上には反映されていません。
以上でトークン作成と、トークンIDをparamsとしてコントローラーへ渡せるようになりました。顧客カードとの紐付け
カード情報非通過対応により2018年6月頃からサーバーサイドからのカード情報のPOSTリクエストができなくなりました。
そのためトークン化はビュー上で行いましたが、顧客作成はコントローラーで行います。users.controller.rbPayjp.api_key = PAYJP_SECRET_KEY customer = Payjp::Customer.create(card: params[:payjp_token])Payjp::Customer.createで顧客カードが作成されたので、その中のcardキーのバリューとしてトークンIDを指定してあげます。
カード情報を取り出す際にもこのIDは使用するので、私はUserテーブルのカラムに入れてあげました。他にも支払い等の詳しいやり方は公式のリファレンスを参照ください。
https://pay.jp/docs/api/#introduction終わりに
私自身まだエンジニアとしてプログラミングを学んで3ヶ月満たないので、ツッコミどころがあるかもしれません。
こういったやり方もあるんだな〜という、一つの実装方法として参考程度に見てください。
他に効率の良いやり方があるよ!この記述無駄じゃない?と気づいた方がいらしたらご指摘ください(_ _)
- 投稿日:2019-02-27T23:27:57+09:00
Ruby on RailsのIDEをどれにしようかなぁと軽く調べた
Cloud9で開発するの、地味に疲れる
今までAWSのクラウド開発環境であるCloud9を利用してきたわけですが、それをやめようかなぁと思い始めています。
理由は単純で、Command+W 暴発問題があるから。ファイルを閉じたくてうっかりCommand+Wを叩くと、Safariのタブが閉じてしまい、開発環境そのものが閉じてしまいます。
そんなの気をつけれてば済む話じゃんって言われるとそこまでなのですが、ロジックを書くことに集中しているといつの間にか頭から飛んでしまうのだ…つらぁ…。Macに入れるIDEを考え始める
元々Java屋でEclipseを使っていたので、とりあえずイマドキなIDEを入れればいいかって考えに至り、探してみることに。
パッと検索した限り、以下の3つが良いっぽい。
- Eclipse (+RadRails)
- RubyMine
- VS Code
Eclipse (+RadRails)
Javaをやってる方で(使用有無はさておき、)Eclipseを知らない方はいないでしょう。
Pleiadesでフル日本語化されたAll in Oneを落としてくればささっと開発に取りかかれる簡単さがあります。
元々使っていたところにプラグインを入れれば使えるというのは学習コストをかなり抑えられそうです。良さそうなところ:
- 学習コスト低め
ちょっとなーってところ:
- Javaやってた時と代わり映えしないので飽きが…
RubyMine
使いやすいIDEを出してくることに定評のある(と伝え聞いている)JetBrains社製IDE。
ちょっと前までデファクトスタンダードだったとどこかで見ました。良さそうなところ:
- 情報量が豊富、何かあっても検索してどうにかなりそう
ちょっとなーってところ:
- 有料か…
VS Code
プロプライエタリ製品の名称だったVisual Studioの名を冠して登場した無料版だと思ってたら、あっという間にWeb業界へ浸透している感のあるIDE。
色んなところから「VS Codeはいいぞ」と聞こえてきます。良さそうなところ:
- 今超絶ホット。使ってるだけで最前線感バリバリ。
ちょっとなーってところ:
- まだ情報が蓄積されていなさそう(& バージョン依存のトラブルシュートが引っかかる)
とりあえずVS Codeからかじってみようかなー
ローカルでRailsの開発をするのはこれからなので、切り替えの手間を考えなくていい分、新しいやつをやってみようという安直な理由でVS Code。
ダメだったらEclipseに転ぶことにしよう。IDE?テキストエディタ使えよ
わかる、わかるよ、その方が軽いし環境選ばないしハッカーっぽいしで良いってのはわかるよ。
でもこちとらRailsに関してはホビープログラマ、楽なやり方で開発したいのだ…本当にすまない…。おすすめあったら教えてくださいなんでもしますから!
「(なんでもするとは言ってない)」の文脈。
「RailsでこのIDEいいよ!」って意見、お待ちしております。
- 投稿日:2019-02-27T22:39:45+09:00
RailsでI18n.localeを書き換えていたらたまに言語設定がバグる問題に遭遇した
RailsでI18n.localeを書き換えてたらたまに言語設定がバグる問題に遭遇した
他のユーザー(:en)で画面を参照したあとに元のユーザー(:ja)で画面を見ると、
稀に、locale=:enで画面が表示されてしまうという問題に遭遇しました。実装はこんな感じ。
class HogeController < ApplicationController before_action :set_locale def set_locale I18n.locale = current_user.locale || I18n.default_locale end endhttps://railsguides.jp/i18n.html#リクエスト間でロケールを管理する
Railsガイドでもだいたいおんなじ感じのコードが乗ってる。ApplicationControllerに書いて全コントローラーに継承させるのならこれでもいけるんですが、継承されないコントローラーがあったりするとバグる。
https://github.com/rails/rails/pull/34356
こんなPull RequestもありI18nはスレッドセーフだと言っていますが、
スレッドセーフなだけで、after_actionとかで元の言語に戻しておいてあげないと次に同じスレッドを使ったときに変更されたままの言語が使われてしまうといった感じなんだと思われます。
(違うコントローラーなどでset_localeが実行されない場合に起こる)こんなふうに実装を変えたら解消しました。
class HogeController < ApplicationController around_action :set_locale def set_locale locale = current_user.locale || I18n.default_locale I18n.with_locale locale do yield end end end
I18n.with_locale
を使うことにより、ロケールの変更をアクション実行時に限定しました。
after_action
でもとに戻すでも行けると思いますが、こっちのほうがドヤり感が高い。around_action 初めて使った。
- 投稿日:2019-02-27T21:15:01+09:00
RSpec
- 投稿日:2019-02-27T21:14:42+09:00
Ruby コメント、変数、定数、リテラル
動作環境はMacとなります。
主に自分の勉強用メモとして残しています。コメント
特定の処理を向こうにしたいときや、メモを残したい時にしようする。
comment.rb# puts "Hello, World!" # 処理を向こうにしたいときは、プログラムの先頭に#をつける。改行までがコメント扱いとなる。
$ruby comment.rb $ #コメントアウトしているため出力されない。複数行コメントアウトしたい場合
comment.rb=begin puts "Hello, World!" puts "Hello, World!" puts "Hello, World!" =end # =beginから=endの間の処理がコメントアウトされる$ruby comment.rb $ #コメントアウトしているため出力されない。実務上複数行に渡る場合でも、行頭に一行ごとに#をつけて実行されることが多い。
コメントを解除したい場合
commandキー+/キーで解除可能 ※複数行の場合、解除したい行をまとめて選択
メモとして残したい場合でも使用可能。
comment.rb# This is a comment.
$ruby comment.rb $ #コメントアウトしているため出力されない。変数
扱うデータに名前をつけて、一時的に利用できるようにしたもの
変数名 = 式
例
name = "suzuki"
fruit = "apple"
x = 10#変数sに Helloという文字列を代入 irb(main):001:0> s = "Hello!" => "Hello!" irb(main):002:0> puts s Hello! => nil #出力 #型の宣言は不要 irb(main):001:0> char s = "Hello!" irb(main):001:0> var s = "Hello!"数値の代入
irb(main):003:0> n = 2 * 10 #値20を変数nに代入 => 20 irb(main):004:0> puts n #変数nの出力 20 => nil変数には何かしら代入しないといけない
#変数に何も値が入っていないとエラーになる。 irb(main):005:0> i NameError: undefined local variable or method `i' for main:Object from (irb):5 from /Users/toripurug884/.rbenv/versions/2.4.1/bin/irb:11:in `<main>' #中身を入れて再出力 irb(main):006:0> i = nil => nil irb(main):007:0> i => nil #実行された!変数名の命名規則
アルファベットの小文字かアンダースコアで始まる。
それに続けてアルファベット、数字、アンダースコアで記述する。irb(main):014:0> price = 100 => 100 #以下原則しないほうが良い命名規則 irb(main):015:0> price1 = 100 #数字をつける => 100 irb(main):016:0> _price = 100 #アンダースコアから始まる変数 => 100 #数字から始まる変数名はエラーになる。 irb(main):017:0> 1price = 100 SyntaxError: (irb):17: syntax error, unexpected tIDENTIFIER, expecting end-of-input 1price = 100#2語以上になる場合は原則_で繋げる。 #キャメルケース(単語と単語の間の文字を大文字にする)は原則使わない。 irb(main):018:0> price_cost = 100 => 100 irb(main):019:0> priceCost = 100 => 100 irb(main):020:0>よくない変数の使い方
エラーではないが、メンテナンス性が悪くなるので推奨されない変数の使い方
同じ変数に違う型を代入
irb(main):022:0> x = "abc" #文字列を代入 => "abc" irb(main):023:0> x = 123 #数字を代入 => 123 irb(main):024:0> x = "def" #文字列を代入 => "def" irb(main):025:0> x = [1,2,3] #配列を代入 => [1, 2, 3] #同じ値を入れてしまうとわかりにくくなる複数の変数に代入
irb(main):026:0> x,y = 1,2 => [1, 2] irb(main):027:0> x => 1 irb(main):028:0> y => 2 #あまりメリットがない。irb(main):029:0> a = b = 10 => 10 irb(main):030:0> a => 10 irb(main):031:0> b => 10 #あえて使う必要はない定数
あまり変化しない値を扱う時に使う
例)消費税、円周率、手数料など定数は原則全て大文字
irb(main):032:0> TAX = 1.08 #定数TAXに値を代入 => 1.08 irb(main):036:0> puts TAX 1.08 => nil irb(main):037:0> TAX_RATE = 1.08 #2語以上の定数の場合単語は_で繋ぐ => 1.08 irb(main):038:0> puts TAX_RATE 1.08 => nilコードのメンテナンスを保つため、定数には再代入は原則しない。
irb(main):039:0> TAX_RATE = 1.1 #一度定義した定数に再代入 #警告が出るが、再代入されてしまうので注意 (irb):39: warning: already initialized constant TAX_RATE (irb):37: warning: previous definition of TAX_RATE was here => 1.1 #再代入後の値が出力される irb(main):040:0> puts TAX_RATE 1.1 => nilリテラルとは
数値の123や文字列の"Hello! World"など
Rubyのプログラムの中に直接記述できる値ソースコードに書いたもの
- 投稿日:2019-02-27T21:05:43+09:00
Herokuデプロイ時に「 `relative_path_from': different prefix」がでたよ
heroku本番環境にS3を使いたかったので、
gem aws-sdk
を登録し、
bundle install
およびcommit、リモートリポジトリにpushまでしたあと$ git push heroku dev:masterを実行したら
Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 8 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 5.73 KiB | 2.87 MiB/s, done. Total 4 (delta 2), reused 0 (delta 0) remote: Compressing source files... done. remote: Building source: remote: remote: -----> Ruby app detected remote: remote: ! remote: ! different prefix: "" and "/tmp/build_edc3150bda146e5ca10eb1b67d801667" remote: ! remote: /app/tmp/buildpacks/b7af5642714be4eddaa5f35e2b4c36176b839b4abcd9bfe57ee71c358d71152b4fd2cf925c5b6e6816adee359c4f0f966b663a7f8649b0729509d510091abc07/vendor/ruby/heroku-18/lib/ruby/2.5.0/pathname.rb:522:in `relative_path_from': different prefix: "" and "/tmp/build_edc3150bda146e5ca10eb1b67d801667" (ArgumentError)というエラーがでた。
解決策
rails s
をすると、$ rails s Your lockfile is unreadable. Run `rm Gemfile.lock` and then `bundle install` to generate a new lockfile.とでたので、
rm Gemfile.lock
を実行し、bundle install
を実行。その後、再度
git push heroku dev:master
をすると、deploy成功。
ググってもまったくヒットしなかったので、
この記事にヒットした方は試してみてください。。
おわり
- 投稿日:2019-02-27T17:46:14+09:00
助けてください
- 投稿日:2019-02-27T16:51:13+09:00
ActiveStorageのファイルをアップロードするタイミングについて
ActiveStorageを使うにあたって、アップロードできたかどうかを調べるために、アップロードをどの処理で実施しているか調べたので、覚書として。(アップロードできたかどうかについては、これから改めて調査)
アプリケーションコードに近い方から遠い方へ順に追っていきます。
前提条件
- activestorage のバージョンは5.2.2を使用する
- 属性の定義に
has_one_attached
を使用する- attachするファイルはHTMLからアップロードしたファイルを使用する
- ファイル保存サービスはローカル(S3やGCSではない)を使用する
ActiveStorage::Attached::Macros
https://github.com/rails/rails/blob/v5.2.2/activestorage/lib/active_storage/attached/macros.rb#L37
ActiveRecord::Baseを継承するモデルクラス内に定義した
has_one_attached
の属性に対して、値が代入された時にattach
メソッドを実行します。ActiveStorage::Attached::One
https://github.com/rails/rails/blob/v5.2.2/activestorage/lib/active_storage/attached/one.rb#L24
ActiveStorage::Attached::One.attach
メソッドがcreate_blob_from
を実行します。ActiveStorage::Attached
https://github.com/rails/rails/blob/v5.2.2/activestorage/lib/active_storage/attached.rb#L23
ActiveStorage::Attached. create_blob_from
メソッドで、attachableのクラスによって処理を分けています。
今回はアップロードされたファイルを属性に指定したので、
ActiveStorage::Blob.create_after_upload!
を実行します。ActiveStorage::Blob
https://github.com/rails/rails/blob/v5.2.2/activestorage/app/models/active_storage/blob.rb#L65
ActiveStorage::Blob.create_after_upload!
がActiveStorage::Blob.build_after_upload
を実行します。https://github.com/rails/rails/blob/v5.2.2/activestorage/app/models/active_storage/blob.rb#L57
ActiveStorage::Blob.build_after_upload
がActiveStorage::Blob
をnew
して、upload
を実行します。https://github.com/rails/rails/blob/v5.2.2/activestorage/app/models/active_storage/blob.rb#L159
ActiveStorage::Blob#upload
がservice
インスタンスのupload
を実行します。
このservice
は、公式ガイドのセットアップでservice
に指定したDisk
やS3
が ActiveStorage::Service::DiskServiceやActiveStorage::Service::S3Serviceをnewしたインスタンスが格納されています。今回はローカルディスクを保存サービスに指定しているので、
ActiveStorage::Service::DiskService
のupload
を実行します。ActiveStorage::Service::DiskService
ActiveStorage::Service::DiskService.upload
で IO.copy_stream でファイルをRails.root/storage/
にコピーして、アップロード処理が終わります。
instrument
のブロックで囲まれていますが、これはActiveSupport::Notifications.instrument
をラップするためのメソッドです。
ログを見ると、logs/development.logDisk Storage (31.0ms) Uploaded file to key: fH4PhWtse6qwM6hBqsoqqmtz (checksum: ci+Mp/YmvV385qYcTJnlgg==)こんな感じのログが、アップロードファイルを属性に代入、またはattachの処理あたりで流れてくると思います。
感想
調べ終わってから記事を書いたので思考とは逆順になっています。
調べ始める前は、モデルクラスを
save
するタイミングでupload
的なメソッドをアプリケーションコードに近いところで実行していると予想していたので、attach
がそれに相当すると気づくまで時間がかかりました。
save
に合わせてファイルを保存するようにしたい場合は、直接属性に代入するのではなく、after_save
かそれに近いタイミングでattach
してあげると良さそうです。
- 投稿日:2019-02-27T16:00:44+09:00
RSpec+FactoryBot+Springでエラーが発生したお話
はじめに
Deviseを利用したWebアプリを作成しており、RSpecを用いたテストを実装しています。
FactoryBotを使い早速Userモデルのモデルスペックを作成し始めたのですが、エラーが発生してしまいました。
一応、解決することができたので、事態をメモしたいと思います。環境
ruby : 2.5.1 rails : 5.2.2 device : 4.6.1 rspec-rails : 3.8.2 factory_bot_rails : 5.0.1 capybara : 3.13.2 spring-commands-rspec : 1.0.4事態
前提
ユーザーに関するファクトリーとモデルスペックは以下の通りです。
spec/factories/users.rbFactoryBot.define do factory :user do sequence(:name) { |n| "User#{n}" } sequence(:email) { |n| "tester#{n}@example.com" } password "password" password_confirmation "password" end endspec/models/user_spec.rbrequire 'rails_helper' RSpec.describe User, type: :model do it "is valid with a name, email,password and password_confirmation" do expect(build(:user)).to be_valid end endエラー内容
1. NoMethodError
上記の通りファクトリーとモデルスペックを作成して
bundle exec rspec spec/models/user_spec.rb
を執行したところ以下のエラーが発生しました。An error occurred while loading ./spec/models/user_spec.rb. Failure/Error: password "password" NoMethodError: undefined method 'password' in 'user' factory # ./spec/factories/users.rb:5:in `block (2 levels) in <main>' # ./spec/factories/users.rb:2:in `block in <main>' # ./spec/factories/users.rb:1:in `<main>' # ./config/environment.rb:5:in `<top (required)>' # ./spec/rails_helper.rb:4:in `require' # ./spec/rails_helper.rb:4:in `<top (required)>' # ./spec/models/user_spec.rb:1:in `require' # ./spec/models/user_spec.rb:1:in `<top (required)>' No examples found. Finished in 0.00064 seconds (files took 2.23 seconds to load) 0 examples, 0 failures, 1 error occurred outside of examplesファクトリーにパスワード設定しているのになんでpasswordがないと言われるのか全く分からず途方に暮れましたが以下で解決しました。
spec/factories/users.rbFactoryBot.define do factory :user do sequence(:name) { |n| "User#{n}" } sequence(:email) { |n| "tester#{n}@example.com" } password { "password" } password_confirmation { "password" } end endそうです、"password"を{}でくくったことで解決しました。
RSpecを使用するにあたり、Everyday Rails - RSpecによるRailsテスト入門やQiitaで勉強していたのですが、特段{}をつけていなかったので同様に私も外していました。
ただFactoryBot-Getting startedを見ると、すべて{}で囲われていたので試しに囲ってみたら解決した次第です。
今のFactoryBotのバージョンには{}が必要なのでしょうか、、、2.KeyError
そういえばspring-commands-rspecをインストールしていたので、
bin/rspec spec/models/user_spec.rb
でRSpecを実行してみたところ、今度は違うエラーが発生しました。$ bin/rspec spec/models/user_spec.rb Running via Spring preloader in process 99000 Failures: 1) User is valid with a name, email,password and password_confirmation Failure/Error: expect(build(:user)).to be_valid KeyError: Factory not registered: "user" # ./spec/models/user_spec.rb:5:in `block (2 levels) in <main>' # -e:1:in `<main>' # ------------------ # --- Caused by: --- # KeyError: # key not found: "user" # ./spec/models/user_spec.rb:5:in `block (2 levels) in <main>'ユーザーが見つからないってどういうこと、、、とこれまた途方に暮れたのですが、spec/factories以下に正しいfactoryの定義が存在するのにFactory not registeredとArgumentError: Factory not registeredを参考にして、spec_helper.rbに以下追加したところ解決しました。
spec/sepc_helper.rbRSpec.configure do |config| config.before(:all) do FactoryBot.reload end end参考記事
- 投稿日:2019-02-27T14:53:28+09:00
Ruby on Rails 開発メモ
開発中のメモを備忘録程度にまとめます。(随時更新)
メイラーに2つの引数を渡す
controller
def create @contact = Contact.new(contact_params) @user = current_user.email if @contact.save ContactMailer.contact_mail(@contact, @user).deliver redirect_to blogs_path, notice: 'Contact was successfully created.' else render :new end endmailer
class ContactMailer < ApplicationMailer def contact_mail(contact, user) @contact = contact @user = user mail to: @user, subject: "お問い合わせの確認メール" end end
- 投稿日:2019-02-27T13:23:40+09:00
RSpecの導入
はじめに
RSpecをインストールしたのでその手順をメモします。
*環境
ruby : 2.5.1
rails : 5.2.2導入手順
1. gemのインストール
Gemnfilegroup :development, :test do # 省略 gem 'rspec-rails' endbundle installします。
2. RSpecの設定
rails generate rspec:install
すると結果は以下。Running via Spring preloader in process 93674 create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb次にRSpecの出力形式を設定します。形式の種類についてはProject: RSpec Core 2.6 --format optionを参照ください。
今回はドキュメント形式にします。/rspec--require spec_helper --format documentation # この一行を追加3. springを使ってRSpecの起動時間を速くする
Gemnfilegroup :development do # 省略 gem 'spring-commands-rspec' endbundle installし、次に
bundle exec spring binstub rspec
をするとbinディレクトリにrspecファイルが生成されます。bin/rspec#!/usr/bin/env ruby begin load File.expand_path('../spring', __FILE__) rescue LoadError => e raise unless e.message.include?('spring') end require 'bundler/setup' load Gem.bin_path('rspec-core', 'rspec')
bin/rspec
もしくはbundle exec rspec
を実行して以下の通り結果がでればrspecは正常にインストールされています。Running via Spring preloader in process 93755 No examples found. Finished in 0.00079 seconds (files took 0.2886 seconds to load) 0 examples, 0 failures4. ジェネレーターを(お好み)設定
rails gコマンドを実行した際に自動生成されるファイルについて、生成の要否を各自お好みで設定します。
config/application.rb# 省略 module アプリ名 class Application < Rails::Application # 省略 config.generators.test_framework = :rspec config.generators.system_tests = false config.generators.stylesheets = false config.generators.javascripts = false config.generators.helper = false config.generators.helper_specs = false config.generators.view_specs = false config.generators.controller_specs = false end endその他
Factory Botのインストール
テスト用のデータを簡単に作成できるFactory Botを導入します。
Gemnfilegroup :development, :test do # 省略 gem 'factory_bot_rails' end/spec/rails_helper.rbRSpec.configure do |config| # 省略 config.include FactoryBot::Syntax::Methods endファクトリを作成するには
bin/rails g factory/bot:model モデル名
を実行します。Capybaraの設定
Capybaraを導入することで、Webアプリのブラウザ操作をシミュレーションすることができます。
Rails5.1からデフォルトで同梱されていますが、RSpecでCapybaraを扱えるようにするために以下の一行を追加する必要があります。/spec/rails_helper.rb# This file is copied to spec/ when you run 'rails generate rspec:install' require 'spec_helper' ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) # Prevent database truncation if the environment is production abort("The Rails environment is running in production mode!") if Rails.env.production? require 'rspec/rails' # Add additional requires below this line. Rails is not loaded until this point! require 'capybara/rspec' # この一行を追加 end
- 投稿日:2019-02-27T06:06:52+09:00
Rspec導入まとめ
最低限の導入手順を記載
後ほどいつもやりそうな初期設定を追記事前設定
config/database.ymlにtestの指定がある事
config/database.ymltest: <<: *default database: プロジェクト名_testテストを導入したい環境に以下のgemを指定している事
Gemfilegroup :development, :test do ・ ・ gem 'rspec-rails', '~> 3.6' gem 'factory_bot_rails' gem 'database_cleaner' ・ ・ end導入
rspecに必要なモジュールをインストールする
bundle install rspec:install rails generate rspec:install下記を追記
spec/support/factory_bot.rbRSpec.configure do |config| config.include FactoryBot::Syntax::Methods endテスト用DBの作成
rails db:migrate RAILS_ENV=test実行方法
rspec spec/対象の階層下 or ファイル
- 投稿日:2019-02-27T01:41:41+09:00
【備忘録】No route matches [GET]の原因と解決策
エラー
post/indexのブラウザ上で、postコントローラーのdestroyアクションを実施した結果、以下のエラーが起きた。
エラーの該当箇所
<%= link_to("削除", "/posts/#{@post.id}/destroy", {method: "delete"}) %>解決策
rake routesでひとまず確認
rake routesposts_create POST /posts/create(.:format) posts#create GET /posts/:id/edit(.:format) posts#edit POST /posts/:id/update(.:format) posts#update POST /posts/:id/destroy(.:format) posts#destroy解決策
routesと、メソッドを変えたら解決した。
①POSTをDELETEに変更
routesで、POST /posts/:id/destroy(.:format) を、DELETE /posts/:id/destroy(.:format)に変更
参考記事:https://railsguides.jp/routing.html
②link_toをbutton_toに変更
<%= button_to("削除", "/posts/#{@post.id}/destroy",method: :delete) %>参考記事:https://qiita.com/y-temp4/items/2d50feb3ff0d65acdf67
メモ
link_toからbutton_toに変更すると、Viewはこうなった。
- 投稿日:2019-02-27T01:41:41+09:00
No route matches [GET]の原因と解決策
エラー
post/indexのブラウザ上で、postコントローラーのdestroyアクションを実施した結果、以下のエラーが起きた。
エラーの該当箇所
<%= link_to("削除", "/posts/#{@post.id}/destroy", {method: "delete"}) %>解決策
rake routesでひとまず確認
rake routesposts_create POST /posts/create(.:format) posts#create GET /posts/:id/edit(.:format) posts#edit POST /posts/:id/update(.:format) posts#update POST /posts/:id/destroy(.:format) posts#destroy解決策
routesと、メソッドを変えたら解決した。
①POSTをDELETEに変更
routesで、POST /posts/:id/destroy(.:format) を、DELETE /posts/:id/destroy(.:format)に変更
参考記事:https://railsguides.jp/routing.html
②link_toをbutton_toに変更
<%= button_to("削除", "/posts/#{@post.id}/destroy",method: :delete) %>参考記事:https://qiita.com/y-temp4/items/2d50feb3ff0d65acdf67
メモ
link_toからbutton_toに変更すると、Viewはこうなった。
- 投稿日:2019-02-27T00:51:35+09:00
Docker + Rails + MySQL + Vue で Todo アプリ作成 〜その1〜
はじめに
前回: Docker + Rails で開発環境を作った。
せっかく作ったのに開発しないのはもったいないよね。
でもできることって限られてる。
ということで、TODOアプリを作ってみる目標
- trello
- 今回はとりあえず、seed データを投入して、その一覧を表示させるとこまで。
- タイトル詐欺してますね、「その1」では Vue は使いません(そこまでいけない)
1.準備
Docker を起動し、コンテナに接続していきます。
$ cd myapp $ docker-compose up $ docker ps
myapp_web
とmysql
のCONTAINER ID
を控える
そぞれのコンテナに接続をする。web$ docker exec -it CONTAINER_ID bash root@CONTAINER_ID:/myapp# これでOKdbdocker exec -it CONTAINER_ID bash root@CONTAINER_ID:/# mysql -u root -p Enter password: # database.yml に記載したパスワード mysql> これでOK2. Rails の操作
2.1 モデルを作る
Task モデルを作る。
web# rails g model Task title:string context:string level:integer # rails db:migrate2.2 コントローラーも作る
こっちは Tasks
複数形であることに注目、Rails Tutorial で確かそう習った# rails g controller Tasks
とりあえず一覧を見たい
tasks_controller.rbclass TasksController < ApplicationController def index @tasks = Task.all end def show end def new end def create end def edit end def update end def destroy end endついでに他のも CRUD の7つも枠だけ用意しておく。
2.3 index で表示させる seed データを作る
seeds.rbTask.create( [ { title: 'task 001', context: 'hogehoge', level: '2', }, { title: 'task 002', context: 'fugafuga', level: '3', }, { title: 'task 003', context: 'piyopiyo', level: '1', }, ], )web# rails db:seed
2.4 seed データを作成したら db を覗く
MySQL 側でデータベース名を確認し
sequel pro で実際にデータが入っているか確認する。dbmysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | myapp_development | # こいつを使うよ | myapp_test | | mysql | | performance_schema | | sys | +--------------------+終わったらコンテナごと
exit
しちゃう。3. View とその準備
さっき
rails db:seed
で作成したデータを表示させたい。
表示させるページは/tasks
と/
(ルートページ)3.1 ルーティング
routes.rbRails.application.routes.draw do root to: 'tasks#index' resources :tasks end3.2 View ファイルの作成
model, controller は
rails g
があるけど
view にはないらしい。
ので、手動で作っていく、$ touch app/views/tasks/index.html.erb $ touch app/views/tasks/show.html.erb $ touch app/views/tasks/new.html.erb $ touch app/views/tasks/edit.html.erbindex.html.erb<h1>Your Tasks</h1> <ul> <% @tasks.each do |task| %> <li><%= task.title %><%= task.context %></li> <% end %> </ul>
Task.all
の数だけ Task の持っている title と context を表示...なんかだんだんモデルの作りがイケてない気がしてきた。
そしてローカルホストに接続して確認。
参考
Railsでタスク管理ができるWebアプリを作成してみた(Rails入門)
【Ruby on Rails】ToDoアプリを簡単に作ってみるありがとうございます。
- 投稿日:2019-02-27T00:12:33+09:00
【備忘録】undefined method `name' for nil:NilClassの原因と解決策
エラー
2行目のpost.user.nameの「name」のメソッドが見当たらない
post.indexActionView::Template::Error (undefined method `name' for nil:NilClass): 1: <% @posts.each do |post| %> 2: <P><%= link_to(post.user.name, "/users/#{post.user.id}") %></p> 3: <p><%= link_to(post.content, "/posts/#{post.id}") %></p> 4: <% end %>原因:postテーブル内の何かしらのレコードがなかった
考えられる原因は2つ
(1)postはpost.controller.rbに定義されていない
(2)データベースのpostモデルに、あるべきレコードがない前者は、コントローラーで定義されていたので、後者の方に原因があると見立てた。
解決策:DBの全てのレコードを空にした
rake db:reset全てのテーブルを dropして、"db/schema.rb" を元にテーブルを再作成する。(参考記事:http://o.inchiki.jp/obbr/183)
メモ
DBの全てのレコードを空にした後、改めて、post.createしたら無事にpost.indexに反映された。
- 投稿日:2019-02-27T00:12:33+09:00
undefined method `name' for nil:NilClassの原因と解決策
エラー
2行目のpost.user.nameの「name」のメソッドが見当たらない
post.indexActionView::Template::Error (undefined method `name' for nil:NilClass): 1: <% @posts.each do |post| %> 2: <P><%= link_to(post.user.name, "/users/#{post.user.id}") %></p> 3: <p><%= link_to(post.content, "/posts/#{post.id}") %></p> 4: <% end %>原因:postテーブル内の何かしらのレコードがなかった
考えられる原因は2つ
(1)postはpost.controller.rbに定義されていない
(2)データベースのpostモデルに、あるべきレコードがない前者は、コントローラーで定義されていたので、後者の方に原因があると見立てた。
解決策:DBの全てのレコードを空にした
rake db:reset全てのテーブルを dropして、"db/schema.rb" を元にテーブルを再作成する。(参考記事:http://o.inchiki.jp/obbr/183)
メモ
DBの全てのレコードを空にした後、改めて、post.createしたら無事にpost.indexに反映された。