ためすう
Rails5 で例外が発生したときに backtrace を出す
2019-06-06やったこと
Rails5 で例外が発生したときにどこで発生したのかを知るため
Exception クラスの backtrace を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
ソースコード編集
app/controllers/tasks_controller.rb
class TasksController < ApplicationController
def index
begin
@task = Task.new
private_dummy
rescue => e
logger.debug(e.backtrace.join("\n"))
logger.info('logger.info')
logger.info(e)
end
end
def private_dummy
raise 'private_dummy'
end
end
ログ確認
log/development.log
Started GET "/" for ::1 at 2019-06-06 22:12:58 +0900
Processing by TasksController#index as HTML
/Users/xxxxx/sample2/app/controllers/tasks_controller.rb:25:in `private_dummy'
/Users/xxxxx/sample2/app/controllers/tasks_controller.rb:16:in `index'
... (省略)
logger.info
private_dummy
参考
Rails5 のレイアウト指定をコントローラ単位で行う(自動)
2019-06-03やったこと
Rails5 のレイアウトをコントローラ単位で適用する方法について調べました。
今回はコントローラに明示的に設定せずに、適用する方法を試します。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
app/views/layouts/tasks.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Task-Sample2</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<p>Taskのレイアウト<p>
<%= yield %>
</body>
</html>
下記のようなコントローラがあるとします。
app/controllers/tasks_controller.rb
class TasksController < ApplicationController
def new
end
end
コントローラ側では特に指定しなくても、レイアウトが切り替わります。
参考
rspec の allow と expect の違い
2019-06-03やったこと
Rails5 で使っている rspec の allow と expect の違いについて調べます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
$ gem list | grep rspec-rails
rspec-rails (3.8.2)
調査
spec/models/task3_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
it 'test1 allow success' do
o = Object.new
allow(o).to receive(:display).and_return(:display_value2)
expect(o.display).to eq(:display_value2)
end
it 'test1 expect fail' do
o = Object.new
expect(o).to receive(:display).and_return(:display_value)
end
it 'test1 expect success' do
o = Object.new
expect(o).to receive(:display).and_return(:display_value)
expect(o.display).to eq(:display_value)
end
end
出力結果
$ bundle exec rspec spec/models/task3_spec.rb
.F.
Failures:
1) Task test1 expect fail
Failure/Error: expect(o).to receive(:display).and_return(:display_value)
(#<Object:0x00007fef8b614e28>).display(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
# ./spec/models/task3_spec.rb:15:in `block (2 levels) in <top (required)>'
Finished in 0.02301 seconds (files took 1.13 seconds to load)
3 examples, 1 failure
Failed examples:
rspec ./spec/models/task3_spec.rb:12 # Task test1 expect fail
allow と expect の違いは、呼び出しの検査をするかどうかになります。
expect で定義したメソッドを呼び出さないとエラーになります。
参考
Rails5 の rspec で allow_any_instance_of を使う
2019-06-02やったこと
Rails5 の rspec で allow_any_instance_of を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
$ gem list | grep rspec-rails
rspec-rails (3.8.2)
調査
allow_any_instance_of は、不具合があるので
あまり使わない方が良いようです。
spec/models/task3_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
it 'test1 allow_any_instance_of' do
allow_any_instance_of(Object).to receive(:display).and_return(:display_value)
o = Object.new
expect(o.display).to eq(:display_value)
end
end
出力結果
$ bundle exec rspec spec/models/task3_spec.rb
.
Finished in 0.0136 seconds (files took 0.86209 seconds to load)
1 example, 0 failures
参考
Rails5 で seed-fu を使ってみる
2019-06-02やったこと
Rails5 の seed-fu を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
Gemfile に追加 + インストール
Gemfile
gem 'seed-fu'
$ bundle install
インストールされたバージョンを確認する
$ gem list | grep seed
seed-fu (2.3.9)
fixtures の準備
db/fixtures/tasks.rb
Task.seed do |s|
s.id = 1
s.name = 'name1'
end
Task.seed do |s|
s.id = 2
s.name = 'name2'
end
seed_fu を実行
$ rake db:seed_fu
== Seed from /Users/xxxx/sample2/db/fixtures/tasks.rb
- Task {:id=>1, :name=>"name1"}
- Task {:id=>2, :name=>"name2"}
参考
Rails5 の rspec で forgery を使ってみる
2019-06-02やったこと
Rails5 の rspec で forgery を使ってみます。
forgery はダミーデータを作成するのに使います。
名前、金額、日付など生成できます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
$ gem list | grep rspec-rails
rspec-rails (3.8.2)
調査
Gemfile に追加 + インストール
Gemfile
group :development, :test do
...
gem 'forgery'
end
$ bundle install
rspec に記述 (FactoryBot)
今回データ作成に FactoryBot を使っているので、 こちらに forgery を導入してみます。
spec/factories/task.rb
FactoryBot.define do
factory :task do
name { Forgery(:name).first_name }
end
end
spec/models/task3_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
before do
@task = build(:task)
end
it 'テスト1' do
p @task.name
end
it 'テスト2' do
p @task.name
end
end
テスト実行
1回目
$ bundle exec rspec spec/models/task3_spec.rb -fd
Task
"Jason"
テスト1
"Sean"
テスト2
Finished in 0.01026 seconds (files took 0.9455 seconds to load)
2 examples, 0 failures
2回目
$ bundle exec rspec spec/models/task3_spec.rb -fd
Task
"Julie"
テスト1
"Justin"
テスト2
Finished in 0.01186 seconds (files took 0.91584 seconds to load)
2 examples, 0 failures
名前が生成されていることが分かります。
ただし、呼び出すために変わるので、データに依存するテストには利用できません。
とりあえずデータを埋めときたい時に利用するものみたいですね。
参考
Rails5 で DatabaseCleaner を使う
2019-06-02やったこと
Rails5 の Rspec で、DatabaseCleaner を導入してみます。
テスト用のデータベースとして MySQL を利用しているのですが、ロールバックしても auto_increment のカラムは数字が増え続けてしまうので、その対応をするため、DatabaseCleaner を使ってみます。
確認環境
$ ruby --version
ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
$ gem list | grep rspec-rails
rspec-rails (3.8.2)
調査
Gemfile に記載
Gemfile
group :development, :test do
...
gem 'database_cleaner'
end
$ bundle install
設定
spec/rails_helper.rb
require 'database_cleaner'
RSpec.configure do |config|
...
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
rspec で実行する (例)
spec/models/task_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
context 'validate task' do
scenario 'is valid with task' do
user = create(:user)
p user.id
task = build(
:task,
user_id: user.id
)
expect(task).to be_valid
end
end
end
下記テストを何回実行しても id が 1 であることを確認できます。
$ bundle exec rspec spec/models/task_spec.rb -fd
Task
validate task
1
is valid with task
Finished in 0.18589 seconds (files took 1.26 seconds to load)
1 example, 0 failures
test.log を見てみる
$ less -qR log/test.log
...
(0.8ms) SET FOREIGN_KEY_CHECKS = 0
(1.5ms) select table_name from information_schema.views where table_schema = 'xxxx_test'
(18.6ms) TRUNCATE TABLE `ar_internal_metadata`;
(26.6ms) TRUNCATE TABLE `tasks`;
(13.0ms) TRUNCATE TABLE `users`;
(0.8ms) SET FOREIGN_KEY_CHECKS = 1
truncate コマンドが実行されていることが確認できます。
※ 最初、DatabaseRewinder で試したのですが、うまく行かなかったので諦めました。
参考
Rails5 で struct を json に変換する
2019-06-02やったこと
struct クラスを json に変換する方法を調べました。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
Rails の to_json は、ActiveSupport で上書きされてます。
速度面の要件次第では別の方法を考えた方が良いかもしれません。
app/controllers/tasks_controller.rb
class TasksController < ApplicationController
def show
point = Struct.new(:x, :y)
tmp = point.new(111, 222)
render :json => tmp.to_json
end
end
出力結果
$ curl http://localhost:3000/tasks/1
{"x":111,"y":222}
参考
Rails5 で factory_bot をインストールする
2019-06-02やったこと
Rails5 で factory_bot をインストールします。
rspec はインストール済みです。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
$ gem list | grep rspec-rails
rspec-rails (3.8.2)
調査
Gem のインストール
Gemfile
group :development, :test do
...
gem 'factory_bot_rails'
end
$ bundle install
Factory Bot の設定
spec/rails_helper.rb
RSpec.configure do |config|
...
config.include FactoryBot::Syntax::Methods
end
データ定義
spec/factories/tasks.rb
FactoryBot.define do
factory :task do
sequence(:name) { |n| "NAME#{n}" }
end
end
テスト記述
spec/models/task3_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
before do
@task = build(:task)
end
it 'テスト1' do
p @task.name
end
it 'テスト2' do
p @task.name
end
end
テスト実行
$ bundle exec rspec spec/models/task3_spec.rb -f d
Task
"NAME1"
テスト1
"NAME2"
テスト2
Finished in 0.00557 seconds (files took 0.86627 seconds to load)
2 examples, 0 failures
参考
Rails5 で rspec の expect を使ってみる
2019-06-02やったこと
Rails5 で rspec の expect を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
$ gem list | grep rspec-rails
rspec-rails (3.8.2)
調査
spec/models/task2_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
it '計算1 should' do
(1 + 2).should eq 3
end
it '計算2 expect' do
expect(3 + 4).to eq 7
end
end
出力結果
$ bundle exec rspec spec/models/task_spec.rb -f d
Task
計算1 should
計算2 expect
Deprecation Warnings:
Using `should` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax is deprecated. Use the new `:expect` syntax or explicitly enable `:should` with `config.expect_with(:rspec) { |c| c.syntax = :should }` instead. Called from /Users/xxxx/sample2/spec/models/task2_spec.rb:5:in `block (2 levels) in <top (required)>'.
If you need more of the backtrace for any of these deprecations to
identify where to make the necessary changes, you can configure
`config.raise_errors_for_deprecations!`, and it will turn the
deprecation warnings into errors, giving you the full backtrace.
1 deprecation warning total
Finished in 0.00259 seconds (files took 0.84059 seconds to load)
2 examples, 0 failures
should は非推奨になったので、警告が出ています。
should で発生する理由はこちらにあるようです(まだ理解していない)