Rails APIでbooleanが勝手にcastされバリデーション通過するのを防ぐ
事象
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"}}
$ 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にいろいろ引っかかるので今回の記事を書いています
Author And Source
この問題について(Rails APIでbooleanが勝手にcastされバリデーション通過するのを防ぐ), 我々は、より多くの情報をここで見つけました https://qiita.com/rf_p/items/db7f2cce3d0e314550a7著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .