Rails:Has_many through,嵌套复选框和验证presence_of

时间:2013-01-10 20:14:15

标签: ruby-on-rails ruby validation nested-attributes

我确信这是一个常见的问题,但它让我感到难过。

我在'Step'模型上有一个has_many:through表:

has_many :questions, :through => :question_step

该question_step模型在question_id和step_id字段中具有在线验证器:

validates_presence_of :question_id, :step_id

还有一些复选框可以确定哪些问题属于哪个步骤

td= check_box_tag "step[question_ids][]", question.id, @step.question_ids.include?(question.id)

现在,除非我想在 new 步骤中添加问题,否则此功能正常。由于step_id为空,因此question_step模型无法通过验证。如果我删除了question_step模型中的validate_presence_of:step_id参数,它可以正常工作,但我实际上想要确保step_id在那里。

我确信这是一个常见问题。 ......有什么想法吗?

2 个答案:

答案 0 :(得分:1)

您可以检查是否存在问题和步骤对象,而不是验证步骤和问题ID。

validates_presence_of :question, :step

如果这不起作用,您应该考虑删除应用程序级别验证并添加数据库约束,您只需要在迁移中向列添加非空约束:

def up
  change_column question_steps, :question_id, :integer, :null => false
  change_column question_steps, :step_id,     :integer, :null => false
end

答案 1 :(得分:0)

我有一个非常类似的问题。根据{{​​3}},存在竞争条件。

在我的控制器的创建动作中,我决定创建我的主模型,而没有关联首先使用params排除关联参数。然后使用关联参数更新模型。

所以在你的情况下可能是

def create
  @step = Step.create(create_params)
  @step.update_attributes(association_params) unless @step.errors.any?
  respond_to do |format|
    if @step.errors.empty?
      format.html #etc..
    else
      format.html#...etc..
    end
  end
end

private
def create_params
  perm_params = step_params
  perm_params.delete :question_ids
  perm_params
end
def association_params
  params.require(:step).permit(question_ids: [])
end
def step_params
  params.require(:step).permit(:name, :other_attributes, question_ids: [])
end

这样您就不必将验证移动到数据库。您仍然可以在更新方法中使用正常的step_params。

params方法可能会被干掉一点,我想知道为什么我需要为了简单地在rails 3中运行的东西而去做所有这些大惊小怪的事情,但它现在适用于我。