在Rails中,更新记录或创建新记录的最佳方式是什么?

问题描述:

我有一些模型的create语句,但它创建连接表内的记录,无论记录是否已存在。在Rails中,更新记录或创建新记录的最佳方式是什么?

这里是我的代码如下所示:

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

的问题是,它创造的记录,不管是什么。我希望它只在没有记录存在的情况下才创建记录;如果记录确实存在,我希望它将所找到的记录的属性加上或减去1.

我一直在四处看看有什么东西叫做find_or_create_by。当它发现一条记录时,它做了什么?我希望它取当前的:score属性并添加1.

是否可以通过id查找或创建?我不确定我会找到什么属性,因为我正在查看的模型是只有id外键和score属性的连接模型。

我试图

@user.choices.find_or_create_by_user(:user => @user.id, :interest => interest, :score => 4) 

,但得到

未定义的方法find_by_user

我应该怎么办?

+1

是CURRENT_USER已经是用户模型的实例?如果是这样,你不需要重新找到它,只需使用`current_user`而不是`@user = ...`。 – 2011-01-07 05:30:02

假设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 

一些注意事项:

  1. 您不需要在find_or_*_by_*中包含user_id列,因为您已经指示Rails仅获取属于@userchoices
  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!将更新记录(如果它已经存在)或创建启动的记录(如果它没有)。

find_or_create_by_user_id听起来更好

+0

tho有什么区别? – MartinElvar 2014-01-23 13:00:47

+1

这不会更新记录?它找到它,或者它创建它。 – baash05 2014-09-10 00:26:03

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 
}) 
+0

为什么要投票? – 2011-01-07 01:25:52

+6

不知道为什么这是downvoted。这对我有帮助 - 感谢贡献! – shedd 2011-03-07 19:16:21

如果您使用的是rails 4,我认为它不会像以前那样创建查找程序方法,所以find_or_create_by_user不会为您创建。相反,你会做这样的:

@user = User.find(current_user) 
@event = Event.find(params[:id]) 
for interest in @event.interests 
@user.choices.find_or_create_by(:interest => interest) do |c| 
    c.score ||= 0 
    c.score += 1 
end 
end 

此外,在的Rails 3你可以这样做:

@user.choices.where(:user => @user.id, :interest => interest, :score => 4).first_or_create 

在Rails 4 您可以使用find_or_create_by得到一个对象(如果不存在,它会创建),然后使用update来保存或更新记录,如果更新方法不存在,则更新方法将保持记录,否则更新记录。

例如

@edu = current_user.member_edu_basics.find_or_create_by(params.require(:member).permit(:school)) 

if @edu.update(params.require(:member).permit(:school, :majoy, :started, :ended))