ためすう

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 で発生する理由はこちらにあるようです(まだ理解していない)

参考

How to Win a Data Science Competition (Week2-3 part4)

2019-05-29

Validation

学習目標

  • Describe validation process and its purpose
  • Compare validation strategies
  • Identify train/test split in a competition
  • Identify and analyze validation problems

Problems occurring during validation

バリデーション段階の問題

  • データがあまりにも少ないとき
  • データが多様すぎて、不整合があるとき
  • KFold は大抵多くても5で充分

課題の提出段階の問題

  • リーダーボードのスコアがバリデーションスコアより一貫して、高い or 低い
  • リーダーボードのスコアがバリデーションスコアと相関がない

発生する原因

  • Kfold でかなり異なるスコアかもしれない
  • 公開リーダーボードのデータが少なすぎる場合
  • 訓練データとテストデータの分布が異なっているかもしれない

まとめ

  • 公開テストデータが少な過ぎる場合、バリデーションを信頼する(オーバフィットしてないことも確認)
  • 訓練データとテストデータの分け方
  • 訓練データとテストデータの分布

参考