Rails6のアプリに、validates追加とRSpecでのテストを追加してみました。
過去の経験だと、どうしても納期優先でRSpecが後回し(最終的にはやらない)になってしまうので、簡単に流用できるように残しておく事にします。
モデル作成
spaceモデルにサブドメイン(subdomain)とスペース名(name)の例
$ rails g model space subdomain:string name:string または $ rails g scaffold space subdomain:string name:string
DBで出来る制限は入れておいた方が無難なので、NOT NULL制約とユニーク制約を追加しておきます。
NOT NULLでも空は許容されてしまうので、validatesで担保します。
db/migrate/20200518002450_create_spaces.rbを修正
class CreateSpaces < ActiveRecord::Migration[6.0] def change create_table :spaces do |t| t.string :subdomain, null: false t.string :name, null: false t.timestamps end add_index :spaces, :subdomain, unique: true end end
$ rails db:migrate
validates追加
サブドメインは1〜32文字。アルファベット(小文字)・数字・ハイフン(先頭不可)です。
連続ハイフンは不可と書いてあるサイトもありましたが、AWSのRoute53でワイルドカード設定したドメインで名前解決出来たので、制限は入れない事にしました。
名前は表示上の問題だけなので、一旦、必須(1文字以上)と32文字までとします。
app/models/space.rbの2行目辺り(classの中)に追加
validates :subdomain, presence: true validates :subdomain, length: { in: 1..32 } validates :subdomain, format: { with: /\A[a-z0-9][a-z0-9\d\-]*\z/ } validates :subdomain, uniqueness: true validates :name, presence: true validates :name, length: { maximum: 32 }
翻訳追加
RailsAdmin等を導入していれば、この段階で使われますが、いずれ使う事が多いので追加しておきます。
参考: RailsアプリにサクッとRailsAdminを導入
config/locales/ja.yml
ja: activerecord: attributes: space: subdomain: "サブドメイン" name: "スペース名" created_at: "作成日" updated_at: "更新日" models: space: "スペース" errors: models: space: attributes: subdomain: taken: "既に使用されています。" blank: "入力してください。" too_short: "%{count}文字以上で入力してください。" too_long: "%{count}文字以下で入力してください。" invalid: "アルファベット(小文字)・数字・ハイフン(先頭不可)のみで入力してください。" name: blank: "入力してください。" too_long: "%{count}文字以下で入力してください。"
テスト追加
FactoryBotは導入済みの想定です。
参考: Railsアプリにサクッとdeviseを導入
spec/factories/spaces.rb
FactoryBot.define do factory :space do subdomain { 'myspace' } name { 'マイスペース' } end end
spec/models/space_spec.rb
require 'rails_helper' RSpec.describe Space, type: :model do describe 'validates subdomain' do subdomain_minimum = 1 context "#{subdomain_minimum - 1}文字" do it 'NG' do space = FactoryBot.build(:space) space.subdomain = 'a' * (subdomain_minimum - 1) expect(space).not_to be_valid end end context "#{subdomain_minimum}文字" do it 'OK' do space = FactoryBot.build(:space) space.subdomain = 'a' * subdomain_minimum expect(space).to be_valid end end context '32文字' do it 'OK' do space = FactoryBot.build(:space) space.subdomain = 'a' * 32 expect(space).to be_valid end end context '33文字' do it 'NG' do space = FactoryBot.build(:space) space.subdomain = 'a' * 33 expect(space).not_to be_valid end end context 'アルファベット(小文字)・数字・ハイフン(先頭不可)' do it 'OK' do space = FactoryBot.build(:space) space.subdomain = 'a' * [subdomain_minimum - 4, 1].max + 'z09-' expect(space).to be_valid end end context 'アルファベット(大文字)' do it 'NG' do space = FactoryBot.build(:space) space.subdomain = 'A' * subdomain_minimum expect(space).not_to be_valid end end context 'ハイフン(先頭)' do it 'NG' do space = FactoryBot.build(:space) space.subdomain = '-' + 'a' * [subdomain_minimum - 1, 1].max expect(space).not_to be_valid end end context 'ハイフン(後尾)' do it 'OK' do space = FactoryBot.build(:space) space.subdomain = 'a' * [subdomain_minimum - 1, 1].max + '-' expect(space).to be_valid end end context '重複' do it 'NG' do space1 = FactoryBot.build(:space) space1.save space2 = FactoryBot.build(:space) space2.subdomain = space1.subdomain expect(space2).not_to be_valid end end end describe 'validates name' do context '0文字' do it 'NG' do space = FactoryBot.build(:space) space.name = '' expect(space).not_to be_valid end end context '1文字' do it 'OK' do space = FactoryBot.build(:space) space.name = 'a' expect(space).to be_valid end end context '32文字' do it 'OK' do space = FactoryBot.build(:space) space.name = 'a' * 32 expect(space).to be_valid end end context '33文字' do it 'NG' do space = FactoryBot.build(:space) space.name = 'a' * 33 expect(space).not_to be_valid end end end end
$ rspec spec/models/space_spec.rb 13 examples, 0 failures
【参考】ここまでのコミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/93c100e2011a56a7338447515407f85e0cf2a2ea
備考
実際にはサブドメインが1文字OKだと都合が悪い事もある。3〜5文字とか?
下記のみで変更可能になっています。
app/models/space.rb
validates :subdomain, length: { in: 1..32 }
spec/models/space_spec.rb
subdomain_minimum = 1
共通化
上記は冗長なので、この後、追加したConfig(gem)で共通化しました。
Config(gem)で環境毎に異なる定数を管理
config/settings.yml
subdomain_minimum: 1 subdomain_maximum: 32
app/models/space.rb
- validates :subdomain, length: { in: 1..32 } + validates :subdomain, length: { in: Settings['subdomain_minimum']..Settings['subdomain_maximum'] }
【参考】ここまでのコミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/184ff1498e734e24346e2290352a7e27bb298c84