Rails枚举validation不起作用但引发ArgumentError
这里创建了一个线程,但它没有解决我的问题。
我的代码是:
course.rb
class Course < ApplicationRecord COURSE_TYPES = %i( trial limited unlimited ) enum course_type: COURSE_TYPES validates_inclusion_of :course_type, in: COURSE_TYPES end
courses_controller.rb
class CoursesController < ApiController def create course = Course.new(course_params) # <-- Exception here if course.save # <-- But I expect the process can go here render json: course, status: :ok else render json: {error: 'Failed to create course'}, status: :unprocessable_entity end end private def course_params params.require(:course).permit(:course_type) end end
我的测试用例:
courses_controller_spec.rb
describe '#create' do context 'when invalid course type' do let(:params) { { course_type: 'english' } } before { post :create, params: { course: params } } it 'returns 422' do expect(response.status).to eq(422) end end end
运行上面的测试用例时,我得到了一个ArgumentError
exception,这个exception在Rails问题中有所描述
所以我希望如果我将一个无效的course_type
设置为枚举,它将在validation阶段失败而不是引发exception 。
另外,我知道在这里的 rails中挂钩下真正发生了什么,我不想在分配枚举类型值的每个代码块中手动挽救这种exception!
有什么建议吗?
更新以支持.valid?
进行幂等validation。
这个解决方案不是很优雅,但它确实有效。
我们在API应用程序中遇到此问题。 每次需要在任何控制器或动作中使用时,我们都不喜欢rescue
此错误的想法。 所以我们在模型方面rescue
它如下:
class Course < ApplicationRecord validate :course_type_should_be_valid def course_type=(value) super value @course_type_backup = nil rescue ArgumentError => exception error_message = 'is not a valid course_type' if exception.message.include? error_message @course_type_backup = value self[:course_type] = nil else raise end end private def course_type_should_be_valid if @course_type_backup self.course_type ||= @course_type_backup error_message = 'is not a valid course_type' errors.add(:course_type, error_message) end end end
可以说,rails-team选择引发ArgumentError
而不是validation错误是正确的,因为我们可以完全控制用户可以从单选按钮组中选择哪些选项,或者可以选择select
字段,所以如果程序员发生了要添加一个新的单选按钮,其值为拼写错误,那么最好引发错误,因为它是应用程序错误,而不是用户错误。
但是,对于API,这将不起作用,因为我们不再对发送到服务器的值有任何控制。