jas*_*328 2 validation ruby-on-rails ruby-on-rails-4
我们的用户记录具有名为 的属性first_name。其中许多记录没有first_name填写该属性,因此它等于 nil。我们想对此属性引入存在验证。然而我们遇到了一个巨大的问题。如果用户在任何请求期间更新其记录,则该请求将失败。这会导致一个相当严重的错误,我们不知道如何处理。
一种解决方案是仅在用户创建记录时调用验证。这非常有效,但我们希望当他们位于个人资料页面上并尝试更新其个人资料时强制执行此验证。
有没有更好的方法来处理这个问题,我们可以在更新页面上强制执行名字要求,但仍然允许用户更新他们的记录而不需要?
对不满足新要求的现有数据引入验证可能会出现问题。您所追求的这个概念从根本上来说是写入时迁移:您引入了随着记录写入而随着时间的推移发生的数据迁移,因为如果没有单独的用户输入,迁移就无法发生。这是一种在零停机环境中迁移非常大的数据集或强制用户重置密码的技术。
从根本上讲,您需要定义必须进行验证的条件,并找到一种方法来测试该条件的记录(在创建或更新时)。您的条件应选择所有新记录,以及在可以迁移的上下文中更新的记录。
定义条件后,您可以这样修改验证:
validates :first_name, presence: true, if: -> { condition_for_migration }
Run Code Online (Sandbox Code Playgroud)
理想情况下,条件应该是表中已存在的某个字段或字段组合,可以正确地将记录标识为准备好迁移,但这并不总是可能的。
如果做不到这一点,您可以专门为此目的引入一个字段。您可以调用它version_number,将所有现有记录设置为1,然后为所有新记录设置默认值2。您的迁移可能如下所示:
# All existing records will have their `version_number` set to the default of 1
add_column :users, :version_number: :integer, null: false, default: 1
# Change the default to 2 for any records created after this point
change_column_default :users, :version_number, 2
Run Code Online (Sandbox Code Playgroud)
然后您可以使用来version_number判断是否应该进行验证:
validates :first_name, presence: true, if: -> { version_number >= 2 }
Run Code Online (Sandbox Code Playgroud)
关键是要确保在您的个人资料表单中,您还进行更新version_number以启用以下验证first_name:
# app/viws/users/edit.html.haml
= form_for @user do |f|
= f.hidden_field :version, value: 2
= f.input :first_name
Run Code Online (Sandbox Code Playgroud)
如果没有用于此目的的真实数据库字段,您可以向模型添加一个临时字段,该字段仅在特定模型实例的生命周期内维护上下文:
update_from_profile_pagefirst_name在创建任何新记录期间进行验证first_name在任何更新期间验证其中update_from_profile_page是否正确例如:
class User < ActiveRecord::Base
attr_accessor :update_from_profile_page
validates :first_name, presence: true, on: :create
validates :first_name, presence: true, on: :update, if: -> { update_from_profile_page }
end
Run Code Online (Sandbox Code Playgroud)
= form_for @user do |f|
= f.input :first_name
Run Code Online (Sandbox Code Playgroud)
def update
@user = User.find(params[:id])
@user = update_from_profile_page = true
@user.update(params.require(:user).permit(:first_name)
end
Run Code Online (Sandbox Code Playgroud)
这比为条件验证找到基于具体业务逻辑的原因更不理想,因为它涉及向模型引入虚拟字段,该虚拟字段在表单提交的单个特定情况之外没有任何功能价值。
| 归档时间: |
|
| 查看次数: |
1648 次 |
| 最近记录: |