在Rails中,如果记录不存在,更新记录或创建新记录的最佳方法是什么?

Chr*_*len 26 ruby-on-rails conditional-statements

我有一些模型的创建语句,但它在连接表中创建一条记录,无论该记录是否已存在.

这是我的代码的样子:

@user = User.find(current_user)
@event = Event.find(params[:id])
for interest in @event.interests
 @user.choices.create(:interest => interest, :score => 4)
end
Run Code Online (Sandbox Code Playgroud)

问题是无论如何都会创建记录.我希望只有在没有记录的情况下才创建记录; 如果记录确实存在,我希望它获取找到的记录的属性并加1或减1.

我一直在环顾四周看过一些叫做的东西find_or_create_by.当它找到记录时这会做什么?我希望它采用当前:score属性并添加1.

是否有可能找到或创建id?我不确定我会找到什么属性,因为我正在查看的模型是一个只有id外键和得分属性的连接模型.

我试过了

@user.choices.find_or_create_by_user(:user => @user.id, :interest => interest, :score => 4)
Run Code Online (Sandbox Code Playgroud)

但得到了

未定义的方法 find_by_user

我该怎么办?

kru*_*hah 60

my_class = ClassName.find_or_initialize_by_name(name)

my_class.update_attributes({
   :street_address => self.street_address,
   :city_name => self.city_name,
   :zip_code => self.zip_code
})
Run Code Online (Sandbox Code Playgroud)

  • 不确定为什么这是低估的.这对我很有帮助 - 感谢您的贡献! (6认同)

von*_*rad 23

假设Choice模型具有user_id(与用户关联)和interest_id(与兴趣关联),这样的事情应该做到这一点:

@user = User.find(current_user)
@event = Event.find(params[:id])

@event.interests.each do |interest|
  choice = @user.choices.find_or_initialize_by_interest_id(interest.id) do |c|
    c.score = 0 # Or whatever you want the initial value to be - 1
  end

  choice.score += 1
  choice.save!
end
Run Code Online (Sandbox Code Playgroud)

一些说明:

  1. 您不需要在user_id列中包含该列find_or_*_by_*,因为您已经指示Rails仅提取choices属于@user.
  2. 我正在使用find_or_initialize_by_*,它基本上是相同的find_or_create_by_*,一个关键的区别是initialize实际上不创建记录.这类似于Model.new相反Model.create.
  3. 那台挡c.score = 0在缺少记录时,才会执行存在.
  4. choice.score += 1将更新记录的分数值,无论它是否存在.因此,默认分数c.score = 0应该是初始值减1.
  5. 最后,choice.save!将更新记录(如果已存在)或创建启动记录(如果没有).


apn*_*ing 7

find_or_create_by_user_id 听起来更好