ためすう
Rails5 で validate の on オプションを使う
2019-06-13やったこと
Rails5 で validate の on オプションを使います。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
app/models/task.rb
class Task < ApplicationRecord
validates :name , uniqueness: true, on: :task_setup
end
task.name に “name1” で1件登録します。
$ rails c
Running via Spring preloader in process 23605
Loading development environment (Rails 5.2.3)
irb(main):001:0> a1 = Task.new
=> #<Task id: nil, created_at: nil, updated_at: nil, name: nil>
irb(main):002:0> a1.name = "name1"
=> "name1"
irb(main):003:0> a1.save
(0.1ms) begin transaction
Task Create (0.5ms) INSERT INTO "tasks" ("created_at", "updated_at", "name") VALUES (?, ?, ?) [["created_at", "2019-06-12 12:50:53.647258"], ["updated_at", "2019-06-12 12:50:53.647258"], ["name", "name1"]]
(0.8ms) commit transaction
=> true
save メソッドに context で指定すると、保存に失敗します。
irb(main):005:0> a2 = Task.new
=> #<Task id: nil, created_at: nil, updated_at: nil, name: nil>
irb(main):006:0> a2.name = "name1"
irb(main):007:0> a2.save(context: :task_setup)
(0.1ms) begin transaction
Task Exists (0.2ms) SELECT 1 AS one FROM "tasks" WHERE "tasks"."name" = ? LIMIT ? [["name", "name1"], ["LIMIT", 1]]
(0.1ms) rollback transaction
=> false
context を指定せずに save すると、保存できました。
irb(main):008:0> a2.save()
(0.1ms) begin transaction
Task Create (0.4ms) INSERT INTO "tasks" ("created_at", "updated_at", "name") VALUES (?, ?, ?) [["created_at", "2019-06-12 12:52:31.539434"], ["updated_at", "2019-06-12 12:52:31.539434"], ["name", "name1"]]
(0.8ms) commit transaction
=> true
参考
rspec の let と let!
2019-06-13やったこと
rspec の let と let! の違いについて調べてみます。
確認環境
$ 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)
調査
- let は遅延評価
- let! はテスト前に実行される
let を使う
spec/models/task6_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
let(:user) { create(:user) }
let(:task) { create(:task) }
it 'test1' do
end
end
出力結果
$ rspec spec/models/task6_spec.rb
.
Finished in 0.01818 seconds (files took 1.66 seconds to load)
1 example, 0 failures
let! を使う
spec/models/task6_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
let!(:user) { create(:user) }
let!(:task) { create(:task) }
it 'test1' do
end
end
出力結果
$ rspec spec/models/task6_spec.rb
F
Failures:
1) Task test1
Failure/Error: let!(:user) { create(:user) }
KeyError:
Factory not registered: "user"
# ./spec/models/task6_spec.rb:7:in `block (2 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# KeyError:
# key not found: "user"
# ./spec/models/task6_spec.rb:7:in `block (2 levels) in <top (required)>'
Finished in 0.00288 seconds (files took 1.65 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/models/task6_spec.rb:10 # Task test1
参考
Ruby で each_with_object を使う
2019-06-12やったこと
Ruby で each_with_object を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
調査
test.rb
scores = { 'Carol' => 90, 'Alice' => 50, 'David' => 40, 'Bob' => 60 }
names = scores.each_with_object([]) do |(key, val), arr|
arr << val * 2 if val >= 60
end
p names
arr に値を入れていくイメージです。
出力結果
$ ruby test.rb
[180, 120]
参考
Rails5 で escape_javascript を使う
2019-06-12やったこと
Rails5 で escape_javascript を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
例えば、下記の view ファイルに書いてみます。
app/views/tasks/new.html.erb
<span>
<%= escape_javascript("111
222") %>
</span>
<span>
<%= escape_javascript("<script>alert(1111);</script>") %>
</span>
<span>
<%= "333
222" %>
</span>
出力結果
<span>
111\n222
</span>
<span>
<script>alert(1111);<\/script>
</span>
<span>
333
222
</span>
改行もエスケープされてます。
参考
Rails5 の css で画像を設定する
2019-06-11やったこと
Rails5 の css で画像を設定します。
今回 production 環境で試します。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
画像を下記に配置します
app/assets/images/sample.png
app/views/tasks/new.html.erb
<div id="main">
dddd
</div>
app/assets/stylesheets/tasks.scss
#main {
background-image: image-url('sample.png')
}
config/environments/production.rb
# config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.public_file_server.enabled = true
↑ Webサーバから静的ファイルを読み込むことができるようにします。
$ RAILS_ENV=production bin/rails assets:precompile
↑ プリコンパイルして、ファイルを作成します。
参考
Rails5 で自作ミドルウェアを作ってみる
2019-06-11やったこと
Rails5 で自作したミドルウェアを読み込んで使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
現在のミドルウェア
$ bin/rails middleware
use Rack::Sendfile
use ActionDispatch::Static
use ActionDispatch::Executor
use ActiveSupport::Cache::Strategy::LocalCache::Middleware
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use ActionDispatch::RemoteIp
use Sprockets::Rails::QuietAssets
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use WebConsole::Middleware
use ActionDispatch::DebugExceptions
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ContentSecurityPolicy::Middleware
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Rack::TempfileReaper
run Sample2::Application.routes
lib/middlewares/my_middleware.rb
class MyMiddleware
def initialize(app)
@app = app
end
def call(env)
if env['PATH_INFO'] == '/tasks/new'
Rails.logger.debug('path is /tasks/new')
res = @app.call(env)
else
Rails.logger.debug('path is other')
res = @app.call(env)
end
res
end
end
config/application.rb
require './lib/middlewares/my_middleware'
...
module Sample2
class Application < Rails::Application
...
config.middleware.use ::MyMiddleware
end
end
$ bin/rails middleware | grep My
use MyMiddleware
参考
Ruby でインターフェースクラスを作る
2019-06-10やったこと
Ruby では下記のようなインターフェースがありません。
そこで、Ruby でも似たようなことを実現する方法を試してみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
調査
継承で実現する
main.rb
class MyInterface
def hoge
raise NotImplementedError.new("#{self.class}##{__method__} を実装してください")
end
end
class SampleFailed < MyInterface
end
class SampleSuccess < MyInterface
def hoge
p "#{self.class}##{__method__}が実装されている!"
end
end
SampleSuccess.new.hoge
SampleFailed.new.hoge
出力結果
$ ruby main.rb
"SampleSuccess#hogeが実装されている!"
Traceback (most recent call last):
1: from main.rb:17:in `<main>'
main.rb:3:in `hoge': SampleFailed#hoge を実装してください (NotImplementedError)
Module で実現する
main2.rb
module MyInterface
def hoge
raise NotImplementedError.new("#{self.class}##{__method__} を実装してください")
end
end
class SampleFailed
include MyInterface
end
class SampleSuccess
include MyInterface
def hoge
p "#{self.class}##{__method__}が実装されている!"
end
end
SampleSuccess.new.hoge
SampleFailed.new.hoge
出力結果
$ ruby main2.rb
"SampleSuccess#hogeが実装されている!"
Traceback (most recent call last):
1: from main2.rb:20:in `<main>'
main2.rb:3:in `hoge': SampleFailed#hoge を実装してください (NotImplementedError)
参考
Rails5 で System Spec を使ってみる
2019-06-10やったこと
System Spec を使ってみます。
確認環境
$ 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)
調査
System Spec とは
Rails の SystemTestCase を Rspec から利用できるようにしたもの
SystemTestCase は E2E テストを実行することができます。
使ってみる
ファイル準備
$ mkdir spec/system
$ touch spec/system/tasks_spec.rb
app/views/tasks/new.html.erb
<button onclick="if (confirm('ok???')) { alert('pushed ok!!!'); }">
テストボタン
</button>
spec/system/tasks_spec.rb
require 'rails_helper'
RSpec.describe 'Tasks', type: :system do
it 'js test' do
visit '/tasks/new'
click_button('テストボタン')
expect(page.driver.browser.switch_to.alert.text).to eq 'ok???'
page.accept_confirm
expect(page.driver.browser.switch_to.alert.text).to eq 'pushed ok!!!'
page.accept_alert
end
end
System Spec を実行
$ rails spec spec/system/tasks_spec.rb
参考
やったこと
JavaScript の encodeURI と encodeURIComponet を使ってみます。
確認環境
navigator.userAgent
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36"
調査
encodeURI を使う
encodeURI("/hogehoge/index?a=22&b=ああ")
"/hogehoge/index?a=22&b=%E3%81%82%E3%81%82"
エスケープされない文字: A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ‘ ( ) #
encodeURIComponent を使う
encodeURIComponent("/hogehoge/index?a=22&b=ああ")
"%2Fhogehoge%2Findex%3Fa%3D22%26b%3D%E3%81%82%E3%81%82"
encodeURIComponent は次を除く全ての文字をエスケープします : アルファベット、10進数字、- _ . ! ~ * ‘ ( )
encodeURIComponent は、URI の構成要素となる文字列 をエスケープするものです。
参考
jq を使って json を整形してみる
2019-06-09やったこと
jq コマンドを使って、json を見やすいように整形してみます。
確認環境
Mac High Sierra (10.13.6)
調査
jq のインストール
$ brew install jq
json を出力する
jq なし
$ echo '{"root":[{"group1": [1]},{"group2": [3,4,5]}]}'
{"root":[{"group1": [1]},{"group2": [3,4,5]}]}
読みにくいですね。
jq あり
$ echo '{"root":[{"group1": [1]},{"group2": [3,4,5]}]}' | jq
{
"root": [
{
"group1": [
1
]
},
{
"group2": [
3,
4,
5
]
}
]
}
階層が分かりやすくなりました。
ちなみに json が壊れてたりすると、下記のようなエラーが出ます。
$ echo '{"root"' | jq
parse error: Unfinished JSON term at EOF at line 2, column 0