同一項目に同一バリデータによるバリデーションを複数種書きたいんです

max_salaryによってjob_titleのバリデーションを変えたいなあと思った場合、validatesの記述自体を分けて↓こう書けばよい。

class Job < ActiveRecord::Base
  self.primary_key = :job_id

  validates :job_title, length: {maximum: 5, if: ->{max_salary <= 1000}}
  validates :job_title, length: {maximum: 10, if: ->{max_salary > 1000}}
end

j = Job.new(job_title: 'abcdefg', max_salary: 1000)
p j.valid? ? "correct" : j.errors.full_messages # => ["Job title is too long (maximum is 5 characters)"]

j = Job.new(job_title: 'abcdefg', max_salary: 1001)
p j.valid? ? "correct" : j.errors.full_messages # => "correct"

1つにまとめて↓こう書くと失敗する。

class Job < ActiveRecord::Base
  self.primary_key = :job_id

  validates :job_title,
    length: {maximum: 5, if: ->{max_salary <= 1000}},
    length: {maximum: 10, if: ->{max_salary > 1000}}
end

j = Job.new(job_title: 'abcdefg', max_salary: 1000)
p j.valid? ? "correct" : j.errors.full_messages # => "correct"

j = Job.new(job_title: 'abcdefg', max_salary: 1001)
p j.valid? ? "correct" : j.errors.full_messages # => "correct"

1つのvalidatesで同じバリデータを複数回記述すると、最後に記述したものが有効になってしまう。だから↓こう書くと当然すべてエラーになる。

class Job < ActiveRecord::Base
  self.primary_key = :job_id

  validates :job_title,
    length: {maximum: 5, if: ->{max_salary <= 1000}},
    length: {maximum: 10, if: ->{max_salary > 1000}},
    length: {maximum: 3}
end

j = Job.new(job_title: 'abcdefg', max_salary: 1000)
p j.valid? ? "correct" : j.errors.full_messages # => ["Job title is too long (maximum is 5 characters)"]

j = Job.new(job_title: 'abcdefg', max_salary: 1001)
p j.valid? ? "correct" : j.errors.full_messages # => ["Job title is too long (maximum is 5 characters)"]

でも複数のvalidatesに書き分ければクリアできてしまう問題なので、将来的には↑この書き方でも意図通りにバリデーションしてくれるようになる可能性も微レ存?