Ruby-on-rails 在 Rails 中,如果记录不存在,更新记录或创建新记录的最佳方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4621208/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In Rails, what is the best way to update a record or create a new one if it doesn't exist?
提问by ChrisWesAllen
I have a create statement for some models, but it's creating a record within a join table regardless of whether the record already exists.
我有一些模型的 create 语句,但无论记录是否已经存在,它都会在连接表中创建一条记录。
Here is what my code looks like:
这是我的代码的样子:
@user = User.find(current_user)
@event = Event.find(params[:id])
for interest in @event.interests
@user.choices.create(:interest => interest, :score => 4)
end
The problem is that it creates records no matter what. I would like it to create a record only if no record already exists; if a record does exist, I would like it to take the attribute of the found record and add or subtract 1.
问题是它无论如何都会创建记录。我希望它仅在没有记录存在时才创建记录;如果确实存在记录,我希望它采用找到的记录的属性并加或减 1。
I've been looking around have seen something called find_or_create_by. What does this do when it finds a record? I would like it to take the current :scoreattribute and add 1.
我一直环顾四周,看到了一个叫做find_or_create_by. 当它找到一条记录时,它会做什么?我希望它采用当前:score属性并添加 1。
Is it possible to find or create by id? I'm not sure what attribute I would find by, since the model I'm looking at is a join model which only has idforeign keys and the score attribute.
是否可以通过查找或创建id?我不确定我会通过什么属性找到,因为我正在查看的模型是一个连接模型,它只有id外键和 score 属性。
I tried
我试过
@user.choices.find_or_create_by_user(:user => @user.id, :interest => interest, :score => 4)
but got
但得到
undefined method
find_by_user
未定义的方法
find_by_user
What should I do?
我该怎么办?
采纳答案by vonconrad
Assuming that the Choicemodel has a user_id(to associate with a user) and an interest_id(to associate with an interest), something like this should do the trick:
假设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
Some notes:
一些注意事项:
- You don't need to include the
user_idcolumn in thefind_or_*_by_*, as you've already instructed Rails to only fetchchoicesbelonging to@user. - I'm using
find_or_initialize_by_*, which is essentially the same asfind_or_create_by_*, with the one key difference being thatinitializedoesn't actually create the record. This would be similar toModel.newas opposed toModel.create. - The block that sets
c.score = 0is only executed if the record does notexist. choice.score += 1will update the score value for the record, regardless if it exists or not. Hence, the default scorec.score = 0should be the initial value minus one.- Finally,
choice.save!will either update the record (if it already existed) or create the initiated record (if it didn't).
- 您不需要在 中包含该
user_id列find_or_*_by_*,因为您已经指示 Rails 只获取choices属于@user. - 我正在使用
find_or_initialize_by_*,它本质上与 相同find_or_create_by_*,其中一个关键区别是initialize实际上并不创建记录。这将类似于而Model.new不是Model.create. - 该组块
c.score = 0在缺少记录时,才会执行不存在。 choice.score += 1将更新记录的分数值,无论它是否存在。因此,默认分数c.score = 0应该是初始值减一。- 最后,
choice.save!将更新记录(如果它已经存在)或创建启动的记录(如果它不存在)。
回答by krunal shah
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
})
回答by apneadiving
find_or_create_by_user_idsounds better
find_or_create_by_user_id听起来更好
回答by Zuhaib Ali
Also, in Rails 3you can do:
此外,在Rails 3 中,您可以执行以下操作:
@user.choices.where(:user => @user.id, :interest => interest, :score => 4).first_or_create
回答by Albert.Qing
In Rails 4You can use find_or_create_byto get an object(if not exist,it will create), then use updateto save or update the record, the update method will persist record if it is not exist, otherwise update record.
在 Rails 4 中你可以find_or_create_by用来获取一个对象(如果不存在,它会创建),然后update用来保存或更新记录,如果记录不存在,update 方法会持久化记录,否则更新记录。
For example
例如
@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))
回答by rainkinz
If you're using rails 4 I don't think it creates the finder methods like it used to, so find_or_create_by_user isn't created for you. Instead you'd do it like this:
如果您使用的是 rails 4,我认为它不会像以前那样创建 finder 方法,因此不会为您创建 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

