Rails自定义属性验证不允许创建新对象

时间:2013-06-03 06:26:59

标签: ruby-on-rails ruby ruby-on-rails-3 validation

我有一个答案模型属于一个具有“正确”布尔列的问题。理想情况下,一个问题只能有一个正确的答案(很像stackoverflow系统)。

我有以下控制器+模型代码,它使用toggle_correct方法在视图中切换“正确”的布尔值(所有这些都很好用)。

当我尝试创建新答案时,即使正确的列设置为default:false,也会引发one_correct_answer验证错误:迁移中的值为false,并且应用程序POST跟踪中的值设置为0(false)

如何修改我的代码,以便此验证只允许每个问题有1个正确的答案,并且不会中断创建新的答案对象?

answer.rb

validate :one_correct_answer

  def one_correct_answer
    answers = self.question.answers.map(&:correct)
    errors.add(:user_id, "You can't have more than 1 correct answer #{answers}") if answers & [true]
    logger.debug("Answers array #{answers}")
  end

def toggle_correct(attribute)
    toggle(attribute).update_attributes({attribute => self[attribute]})
  end 

answers_controller.rb

def correct 
    @answer = Answer.find(params[:id])
    if @answer.toggle_correct(:correct)
    respond_to do |format|
      format.html { redirect_to :back, notice: "Answer submitted" }
      format.js
      end
    end
  end

_answer.html.erb

<div id="correct_answer_<%= answer.id %>" class="<%= answer.correct == true ? 'green-tick' : 'default-tick' %>">
    <% if answer.question.user == current_user %>
        <%= link_to "✓", correct_answer_path(answer), id: "tick", class: "correct_#{answer.id}", remote: true, method: :put %>
    <% else %>
        <% if answer.correct == true %>
           <div id="tick", class='correct_<% answer.id %>'> ✓</div>
        <% end %>
    <% end %>
</div>

2 个答案:

答案 0 :(得分:1)

失败的原因是,如果与问题相关的任何答案都正确,则会添加错误。即使您尝试保存的答案是正确与否,您也可以对此进行测试。所以你要做的第一件事就是只检查你试图保存的答案是否正确,如果有正确的答案,如下:

validate :one_correct_answer, if: :correct?

这样,只有当前答案正确时才会验证方法one_correct_answer。

但是,您还有一个问题。如果您尝试保存的答案是正确的,那么将调用该方法,如果有任何答案是正确的,它将添加错误...这可能是因为当前答案也应列在该关联中。所以你想要做的是检查是否还有一个正确的答案。

所以最后,我可能最终会这样验证它:

validates_uniqueness_of :correct, scope: :question_id, if: :correct?

这样做会验证question_id列和正确列的唯一组合,但前提是它是正确的。这使得每个问题可以有多个错误但只有一个真正正确的列。

答案 1 :(得分:1)

你的问题可能就在这里:

errors.add(:user_id, "You can't have more than 1 correct answer #{answers}") if answers & [true]

answers & [true]将始终返回一个数组(因为answers是一个数组),而空行数组在Ruby中是真值。

即使它们是错误的值,你的情况也不会起作用,因为必须有一个正确的答案,你的情况会检查没有。

我会用这个条件:

self.question.answers.count(&:correct) <= 1