两个在Ruby中形成一个模型,每个模型都有单独的验证

时间:2012-01-29 23:14:21

标签: ruby-on-rails ruby

我在一个表单中有三个字段,在另一个表单中有两个字段(与早期表单相同,但只缺少一个字段)。我想只验证较小形式的两个字段,但问题是它正在验证所有这三个字段。

我写了以下逻辑:

**

class User < ActiveRecord::Base
  validate :validate_form #for form with 2 fields
  private
    def validate_form
      if :classify_create
        self.errors.add(:weight, "need weight") if weight.blank?
        self.errors.add(:height, "need height") if height.blank?
      end
  end

  #   Validations of attributes (for form with three fields)
  validates :weight, :presence => true

  validates :height, :presence => true

  validates :gender, :presence => true
end

**

这是我的控制器动作:基本上我写了两个单独的创建:

**# for form with two fields
  def classify
    @user  = User.new
    @title = "Classify"
  end

  def classify_create
    @user  = User.where("weight = ? and height = ?", params[:weight] ,params[:height])
  end

# for form with three fields
  def new
    @user  = User.new
    @title = "Train"
  end

  def create
    @user = User.new(params[:user])
    if @user.save
       redirect_to @user
    else
      @title = "Train"
      render 'new'
    end
  end**

当我提交到两个字段表单时,它也会给我一个性别错误,并重定向到具有三个字段的表单的页面。我应该怎么做呢?

任何帮助将不胜感激。

此致 阿伦

2 个答案:

答案 0 :(得分:3)

首先,我 使用classify作为方法名称。您可能与ActiveSupport提供的核心inflector冲突。称之为classification或其他。

其次,您的验证正在if @user.save方法的create上运行。

classify_create中,您使用User.where(...)这是一种查找程序方法。您正在提取匹配记录并将其设置为@user。这不会运行验证,但您会收到验证错误。您要发布到create,而不是classify_create。错误的路线会导致这种情况。

让我们首先解决条件验证问题。在User模型中,创建一个变量作为性别验证的旁路开关。然后告诉您的验证在运行之前检查此旁路开关是否为假:

User < ActiveRecord::Base
  attr_accessor :skip_gender  # defaults to nil (false)
  # ...

  validates :gender, :presence => true, :if => :validate_gender? # validate if...
  # ...

  private
  def validate_gender?
    !self.skip_gender # true = run validation, false = skip validation
  end
  # ...
end

接下来,清理您的控制器。写两个create方法,一个设置开关,一个不设置。 (这不是干的):

def new_classification
  # for form with two fields
  @user  = User.new
  @title = "Classify"
end

def new
  # for form with three fields
  @user  = User.new
  @title = "Train"
end

def create
  @user = User.new(params[:user])
  if @user.save
    redirect_to @user
  else
    render :action => 'new' # render three-field form
  end
end

def create_classification
  @user  = User.where(:weight => params[:weight], :height => params[:height])
  # ... do something with @user ...
  @user.skip_gender = true # tell @user to skip gender validation
  if @user.save
    redirect_to @user
  else
    render :action => 'new_classification' # render two-field form
  end      
end

接下来,调整config/routes.rb以指定自定义方法的路由。

resources :users do
  member do
    get 'new_classification',     :to => 'users#new_classification', \
                                  :as => :new_classification_for
    post 'create_classification', :to => 'users#create_classification', \
                                  :as => :create_classification_for
  end
end

现在更改双字段表单视图。指定表单提交的位置。

<%= form_for @user, :url => create_classification_for_user_url(@user) do |f| %>

那应该让你了解你所拥有的......

答案 1 :(得分:0)

你的问题有两个方面:

  1. 您正在尝试将一个控制器用于两个不同的操作。
  2. Rails验证模型有些限制且不灵活,控制器方法和模型应该有单独的验证通道。
  3. 简单的解决方案是通过单独的控制器解决限制:

    def create_genderless
        # Force the issue to an explicit "unknown" state so that
        # "unknown" and "missing" can be differentiated.
        params[:user][:gender] = 'U'
        # And then punt to the existing `create` method.
        create
    end
    

    然后在模型中进行更多验证以获得良好的衡量标准

    class User < ActiveRecord::Base
        validates :gender, :inclusion => { :in => %w[M F U] }
        #...
    end
    

    然后根据需要更新您的表单以使用UserController#createUserController#create_genderless