Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@alpaca-tc
alpaca-tc / phone_number.rb
Created May 23, 2021 13:42
渡された値から数値以外を削除する型(主に電話番号用)
# Usage
# attribute :phone_number, :number_string
class NumberString < ActiveModel::Type::String
# 与えられた値を数値のみの文字列、またはnilに変換する
#
# @param value [Object]
#
# @return [String, NilClass]
def cast(value)
super(value)&.remove(/\D/)
@alpaca-tc
alpaca-tc / wrapped_type.rb
Created May 23, 2021 13:40
渡された値でクラスを初期化する型
# Usage
# attribute :wrapped_type, klass: UserModel, array: true
class WrappedType < ActiveModel::Type::Value
KEYWORD_PARAMETERS = %i[keyreq key].freeze
private_constant(:KEYWORD_PARAMETERS)
# @param [Class, String] klass 変換したいクラス
# @param [Boolean] array 配列で変換するかどうか
def initialize(klass:, array: false)
super()
@alpaca-tc
alpaca-tc / stripped_string.rb
Last active May 31, 2021 07:29
空白を除去するString型
class StrippedString < ActiveModel::Type::String
# 左右の空白を除去した文字列クラス
#
# @param [Object] value
#
# @return [String, nil]
def cast(value)
super(value)&.strip&.presence
end
@alpaca-tc
alpaca-tc / association_owner_validator.rb
Created May 23, 2021 13:22
関連の持ち主が同一人物であることをテスト
# 使い方
# validates_with(
# AssociationOwnerValidator,
# associations: {
# sub_item: :user
# },
# owner: -> { profile_image.user },
# if: %i[sub_item profile_image]
# )
class AssociationOwnerValidator < ActiveModel::Validator
@alpaca-tc
alpaca-tc / boolean_validator.rb
Created May 23, 2021 13:17
値がtrue/falseのいずれかであることをテスト
# validates :column_name, boolean: true のように使う
class BooleanValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.is_a?(TrueClass) || value.is_a?(FalseClass)
record.errors.add(attribute, :not_boolean)
end
end
@alpaca-tc
alpaca-tc / ridgepole_unsigned_primary_id.rb
Created May 23, 2021 13:14
ridgepoleで全ての主キー・外部キーをunsigned: trueで定義する
# Schemafileで下記のように読み込む
# require_relative './lib/ridgepole_unsigned_primary_id'
# `create_table`, `t.references` で、常に `unsigned: true` を有効にするための拡張
# 個別に指定することもできるが、可読性が悪くなるのでデフォルトとする
module UnsingedReferences
def references(*args)
options = args.extract_options!
options[:unsigned] = true
args.push(options)
@alpaca-tc
alpaca-tc / ridgepole_hashed_index_name.rb
Created May 23, 2021 13:10
ridgepoleで定義するindex名をhashのランダム名で定義する(古いRailsっぽい挙動)
# Schemafileから
# require_relative './lib/ridgepole_hashed_index_name'
# して使う
module RidgepoleHashedIndexName
def index_name(table_name, options)
if options.is_a?(Hash) && options[:column]
identifier = super
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
"index_rails_#{hashed_identifier}"
@alpaca-tc
alpaca-tc / active_record_dowsing.rb
Created May 23, 2021 13:05
クエリに発行元のコメントを含める処理の簡易版
# frozen_string_literal: true
dowsing = Module.new do
def execute(sql, *)
source_location = query_source_location(caller.lazy)
sql = "#{sql} /* #{source_location} */" if source_location
super
end
private
@alpaca-tc
alpaca-tc / sidekiq_cron_spec.rb
Created May 23, 2021 12:59
sidekiq-cronのconfig/schedule.ymlがvalidであることをテスト
# frozen_string_literal: true
RSpec.describe 'sidekiq-cron' do
describe 'config/schedule.yml' do
let(:path) { Rails.root.join('config', 'schedule.yml') }
before do
Sidekiq::Cron::Job.load_from_array(YAML.load_file(path))
end
@alpaca-tc
alpaca-tc / factory_bot_spec.rb
Created May 23, 2021 12:57
FactoryBotの定義漏れ、不正な定義をテストする
# frozen_string_literal: true
RSpec.describe FactoryBot do
shared_examples_for 'valid definition' do
it 'is valid' do
is_expected.to be_valid, (-> { factory.errors.full_messages.join("\n") })
end
end
FactoryBot.factories.map(&:name).each do |factory_name|