我有一个答案模型属于一个具有“正确”布尔列的问题。理想情况下,一个问题只能有一个正确的答案(很像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>
答案 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