如何确保mongoid只保存一个已保存模型的实例?

时间:2012-07-11 16:13:05

标签: ruby-on-rails mongodb mongoid

我遇到了一个问题,我认为我的解决方案目前非常难看,有什么更好的方法可以使用rails / mongoid执行以下操作?基本上,用户可以进入并提供'nil'的answer_id,但是一旦他们回答了问题,我们就想锁定他们的第一个非零回答。

controller.rb

r = Response.new(user: current_user, question_id: qid, answer_id: aid)
r.save_now!

以下response.rb模型:

def save_now!
    user = self.user
    qid = self.question_id
    aid = self.answer_id
    resp = Response.where({user_id: user._id, question_id: qid}).first

    # We accept the first answer that is non-nil, 
    # so a user can skip the question (answer_id=nil)
    # And then return and update the answer_id from nil to 'xyz'
    if resp.nil?
      resp = Response.new(user: user, question_id: qid, answer_id: aid)
    else
      if resp.answer_id.nil? && aid.present?
         resp.answer_id = aid
      end    
    end    
    resp.save!
end

所以我想最初允许answer_id为nil(如果用户跳过了问题),然后取第一个非零的答案。

我真的不认为两次实例化Response对象是直观和干净的,一次在控制器中,一次在模型中,但我不确定最好的方法吗?感谢。

2 个答案:

答案 0 :(得分:1)

(user, question_id, answer_id)上创建唯一索引。这样只有第一个插入才会成功。后续插入将失败并显示错误。这样就无需在find方法中进行save_now!查询。

请记住以安全模式运行此插入,否则您将无法获得异常,它将无声地失败。

更新

似乎可以通过重命名方法解决您的问题。 :)看看:

class Response
  def self.save_answer(user, qid, aid)
      resp = Response.where({user_id: user._id, question_id: qid}).first

      if resp.nil?
        resp = Response.new(user: user, question_id: qid, answer_id: aid)
      else
        if resp.answer_id.nil? && aid.present?
           resp.answer_id = aid
        end    
      end    
      resp.save!
  end
end

# controller.rb
r = Response.save_answer(current_user, qid, aid)

答案 1 :(得分:-1)

Mongoid对您可以使用的唯一性进行验证。在您的情况下,您可以在user,question_id和answer_id上创建复合索引,并且不需要编写save_answer方法。

例如,您可以将其放在Response模型中:

validates_uniqueness_of :user_id, :question_id

确保每个用户只能对一个问题进行一次回复。