【问题标题】:Rails form validationRails 表单验证
【发布时间】:2010-09-26 13:05:29
【问题描述】:

我有一个 Rails 应用程序,它允许用户通过填写​​扩展表单来构建数据库查询。我想知道在 Rails 中检查表单参数的最佳实践。以前,我有我的results 方法(表单提交的方法)执行以下操作:

if params[:name] && !params[:name].blank?
  @name = params[:name]
else
  flash[:error] = 'You must give a name'
  redirect_to :action => 'index'
  return
end

但是对于几个表单字段,看到每个字段都重复这种情况会让人厌烦。我不能将它们全部放在某个循环中以检查每个字段,因为这些字段的设置不同:

  • 单键:params[:name]
  • 一个键和一个子键:params[:image][:font_size]
  • 如果设置了其他字段,则只希望填写某些表单字段

等等。这也是重复的,因为我为每个缺失/无效参数设置了flash[:error],并为每个参数重定向到相同的 URL。我改用before_filter 来检查所有必要的表单参数,只有在一切正常时才返回true。然后我的results 方法继续,变量被完全分配,不涉及检查:

@name = params[:name]

在我的 validate_form 方法中,我有如下代码段:

if (
  params[:analysis_type][:to_s] == 'development' ||
  params[:results_to_generate].include?('graph')
)
  {:graph_type => :to_s, :graph_width => :to_s,
   :theme => :to_s}.each do |key, sub_key|
    unless params[key] && params[key][sub_key]
      flash[:error] = "Cannot leave '#{Inflector.humanize(key)}' blank"
      redirect_to(url)
      return false
    end
  end
end

我只是想知道我是否会以最好的方式解决这个问题,或者在参数验证方面我是否遗漏了一些明显的东西。我担心这仍然不是最有效的技术,因为我有几个块在其中为flash[:error] 赋值,然后重定向到相同的 URL,然后返回 false。

编辑澄清:我目前没有在模型中进行此验证的原因有两个:

  • 我不是为了在数据库中创建或更新行而尝试从用户那里收集数据。用户提交的所有数据在退出后都不会保存。当他们提交它以搜索数据库并生成一些东西时,它就全部使用了。
  • 查询表单接收与多个模型相关的数据,并接收与模型完全不相关的其他数据。例如。上面显示的图形类型和主题不连接到任何模型,它们只是传达有关用户希望如何显示其结果的信息。

编辑以显示改进的技术: 感谢 Jamis Buck 的 Raising the Right Exception article,我现在使用特定于应用程序的异常。例如:

def results
  if params[:name] && !params[:name].blank?
    @name = params[:name]
  else
    raise MyApp::MissingFieldError
  end

  if params[:age] && !params[:age].blank? && params[:age].numeric?
    @age = params[:age].to_i
  else
    raise MyApp::MissingFieldError
  end
rescue MyApp::MissingFieldError => err
  flash[:error] = "Invalid form submission: #{err.clean_message}"
  redirect_to :action => 'index'
end

【问题讨论】:

  • 我认为您不必使用 params[:name] 和 !params[:name].blank?在你的条件下。 !params[:name].blank?足够的。 params[:name] 如果为 nil(没有这样的参数)返回 false 并且 params[:name].blank?如果为 nil 或为空,则返回 true。
  • 你得到一个 NoMethodError。我可以覆盖 NilClass 来添加#blank?对它,我想。 irb(main):002:0> 参数 = {:a => 1, :b => 2, :c => 3} => {:c=>3, :a=>1, :b=>2 } irb(main):003:0> !params[:name].blank? NoMethodError:未定义的方法“空白?”对于 nil:NilClass from (irb):3
  • 这里没有 Ruby,只有 Rails。 已删除标签

标签: ruby-on-rails forms validation


【解决方案1】:

看起来您正在控制器中进行验证,尝试将其放入模型中,它更适合那种事情。

【讨论】:

  • 正如guide 中所推荐的那样:“控制器级别的验证可能很容易使用,但通常会变得笨拙且难以测试和维护。只要有可能,@987654322 是个好主意@,因为从长远来看,它会让您的应用程序愉快地工作。”
【解决方案2】:

您可以尝试 active_form (http://github.com/cs/active_form/tree/master/lib/active_form.rb) - 只需 ActiveRecord 减去数据库内容。通过这种方式,您可以使用 AR 的所有验证内容,并像对待任何其他模型一样对待您的表单。

class MyForm < ActiveForm
  validates_presence_of :name
  validates_presence_of :graph_size, :if => # ...blah blah 
end

form = MyForm.new(params[:form])
form.validate
form.errors

【讨论】:

【解决方案3】:

如果你今天要再次解决这个问题,你可以为查询参数集创建一个模型并使用 Rails 的内置验证,Rails 3 使用 ActiveModel::Validations 使这更容易,请参阅this post

【讨论】:

    【解决方案4】:

    型号

    class Person 
        include ActiveModel::Validations
        include ActiveModel::Conversion
        extend ActiveModel::Naming
    
        attr_accessor :name
        attr_accessor :email
    
    
        validates_presence_of :name,:message => "Please Provide User Name"
        validates_presence_of :email,:message => "Please Provide Email"
    end
    

    请注意,您不一定需要保存/保留模型以进行验证。

    控制器

    @person.name= params["name"]
    @person.email= params["email"]
    @person.valid?
    

    您称为 .valid 的那个?模型上的方法,错误将填充到 @person 对象中。因此,

    查看

    <%if @person.errors.any? %>
         <%@person.errors.messages.each do|msg| %>
              <div class="alert alert-danger">
                <%=msg[0][1]%>
              </div>
         <%end%>
    <%end%>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-19
      • 1970-01-01
      • 2011-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多