LoginSignup
1
0

More than 3 years have passed since last update.

Rails APIでbooleanが勝手にcastされバリデーション通過するのを防ぐ

Last updated at Posted at 2020-08-16

事象

Rails APIでboolean型のカラムに対しcreate, updateした際、boolean以外の型は弾くようにしたい

$ rails -v
Rails 6.0.3.2
$ rails g model Post body:text opened:boolean
app/models/post.rb
class Post < ApplicationRecord
  validates :opened, inclusion: { in: [true, false]}
end

こうすれば本来、boolean以外は弾かれる、はずが…

$ curl localhost:3000/posts -X POST -H "Content-Type: application/json" -d '{"body": "hoge", "opened": "moge"}'
{"status":"success","data":{"id":1,"body":"hoge","opened":true,"created_at":"2020-08-16T01:31:14.277Z","updated_at":"2020-08-16T01:31:14.277Z"}}

booleanのopenedカラムに対し"moge"を指定

期待: booleanじゃないのでエラーになり弾かれる
実態: エラーにならず、trueにcastされsaveされる

$ curl localhost:3000/posts -X POST -H "Content-Type: application/json" -d '{"body": "hoge", "opened": "0"}'
{"status":"SUCCESS","data":{"id":2,"body":"hoge","opened":false,"created_at":"2020-08-16T01:31:28.498Z","updated_at":"2020-08-16T01:31:28.498Z"}}

期待: booleanじゃないのでエラーになり弾かれる
実態: エラーにならず、falseにcastされsaveされる

どうやら値がキャストされた状態で渡ってしまう模様

対策

カスタムバリデーションを作る

app/validators/boolean_validator.rb
class BooleanValidator < ActiveModel::EachValidator
  def validate_each(record, attr, _value)
    before_value = record.send("#{attr}_before_type_cast")
    record.errors.add(attr, "is invalid") unless %w[true false].include?(before_value.to_s.downcase)
  end
end
app/models/post.rb
class Post < ApplicationRecord
  validates :opened, boolean: true
end

※カスタムバリデーションを実装した後はRailsサーバを再起動すること

結果

$ curl localhost:3000/posts -X POST -H "Content-Type: application/json" -d '{"body": "hoge", "opened": "moge"}' 
{"status":"error","data":{"opened":["is invalid"]}}
$ curl localhost:3000/posts -X POST -H "Content-Type: application/json" -d '{"body": "hoge", "opened": "0"}' 
{"status":"error","data":{"opened":["is invalid"]}}
$ curl localhost:3000/posts -X POST -H "Content-Type: application/json" -d '{"body": "hoge", "opened": "true"}'
{"status":"success","data":{"id":3,"body":"hoge","opened":true,"created_at":"2020-08-16T02:25:18.211Z","updated_at":"2020-08-16T02:25:18.211Z"}}
$ curl localhost:3000/posts -X POST -H "Content-Type: application/json" -d '{"body": "hoge", "opened": "false"}'
{"status":"success","data":{"id":4,"body":"hoge","opened":false,"created_at":"2020-08-16T02:25:30.700Z","updated_at":"2020-08-16T02:25:30.700Z"}}

期待した通り、trueとfalse以外は弾かれるようになりました

参考

Railsでboolean型のカラムのvalidationを行い型が異なる場合エラーとして返す方法

上記URLで実装すると、rubocopにいろいろ引っかかるので今回の記事を書いています

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0