如果使用first_or_create“首先”或“创建”某些内容,我如何区分

时间:2012-05-10 16:05:12

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

我正在尝试使用此声明:

@vote = Vote.where(:resource_id => params[:id], :user_id => current_user.id).first_or_create(:value => 1)

这是一个upvote或downvote。如果该行不存在于DB中,则应该创建它(如果他们从未在该帖子上投票),则应该使用-1,0,1来修改该值。

如果他们第二次点击upvote则需要“撤消”投票并将行“值”设置为0而不是1.同样的事情发生在downvote但这只是upvote函数。

我在使用rails时调试此语句时遇到问题。我需要基本上区分它是保存的记录还是创建的记录。如果我把:

@vote = Vote.where(:resource_id => 25, :user_id => 1)
@vote.exists?

我得到true

但是,如果我把它...(并且记录存在,它只是在上面工作)..

@vote = Vote.where(:resource_id => 25, :user_id => 1).first_or_create(:value => 1)
@vote.exists?

我明白了...... NoMethodError:未定义的方法`存在?'对于#

在查看两个对象的类之后,我看到一个是“投票”,一个是“ActiveRecord :: Relation”。

我的最终目标是以某种方式重构这个(主要是它检查投票值是否已经为1的部分,如果这样设置为零(撤消投票),否则将其置于1

这是我开始尝试使用first_or_create重构之前的代码。它长而丑。

 if @vote.exists?
      # Check if they have already voted
      if @vote.first.value == 1
        @vote.first.value = 0
      else
        @vote.first.value = 1
      end
      flash[:notice] = "previous vote modified"
      @vote.first.save
    else
      # Create a new Vote instance, save it
      @vote = Vote.new(:resource_id => params[:id], :user_id => current_user.id, :value => 1)
      if @vote.valid?
        @vote.save
        flash[:notice] = "New vote added"
      else
        @vote.save
        flash[:notice] = (@vote.errors.full_messages).to_s
      end
    end

1 个答案:

答案 0 :(得分:5)

我会使用Rails魔术方法find_or_create_by方法。

在此处查看“基于动态属性的查找程序”:

http://api.rubyonrails.org/classes/ActiveRecord/Base.html

您可以像使用动态查找方法一样使用它,但是如果它不存在则传入您想要添加的额外变量来创建投票。

在你的情况下,它就像是:

@vote = Vote.find_or_create_by_resource_id_and_user_id(25, 1, :value => 1)

如果您不希望立即创建,则可以使用基本上创建find_or_initialize_by而不保存的Vote.new