[英]In Rails, what is the best way to update a record or create a new one if it doesn't exist?
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. 我有一些模型的创建语句,但它在连接表中创建一条记录,无论该记录是否已存在。
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或减1。
I've been looking around have seen something called find_or_create_by
. 我一直在四处寻找一些名为find_or_create_by
东西。 What does this do when it finds a record? 当它找到记录时这会做什么? I would like it to take the current :score
attribute and add 1. 我希望它采用当前:score
属性并添加1。
Is it possible to find or create by id
? 是否可以通过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 id
foreign keys and the score attribute. 我不确定我会找到什么属性,因为我正在查看的模型是一个只有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
undefined方法find_by_user
What should I do? 我该怎么办?
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
})
Assuming that the Choice
model 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: 一些说明:
user_id
column in the find_or_*_by_*
, as you've already instructed Rails to only fetch choices
belonging to @user
. 您不需要在find_or_*_by_*
包含user_id
列,因为您已经指示Rails仅提取属于@user
choices
。 find_or_initialize_by_*
, which is essentially the same as find_or_create_by_*
, with the one key difference being that initialize
doesn't actually create the record. 我正在使用find_or_initialize_by_*
,它与find_or_create_by_*
基本相同,其中一个关键区别是initialize
实际上并不创建记录。 This would be similar to Model.new
as opposed to Model.create
. 这与Model.new
相似,而不是Model.create
。 c.score = 0
is only executed if the record does not exist. 该设置块c.score = 0
,如果记录不存在时,才会执行。 choice.score += 1
will update the score value for the record, regardless if it exists or not. choice.score += 1
将更新记录的分数值,无论它是否存在。 Hence, the default score c.score = 0
should be the initial value minus one. 因此,默认分数c.score = 0
应该是初始值减1。 choice.save!
最后, choice.save!
will either update the record (if it already existed) or create the initiated record (if it didn't). 将更新记录(如果已存在)或创建启动记录(如果没有)。 find_or_create_by_user_id
听起来更好
此外,在Rails 3中,您可以:
@user.choices.where(:user => @user.id, :interest => interest, :score => 4).first_or_create
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. 如果您使用的是rails 4,我认为它不会像以前那样创建finder方法,因此不会为您创建find_or_create_by_user。 Instead you'd do it like this: 相反,你会这样做:
@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
In Rails 4 You can use find_or_create_by
to get an object(if not exist,it will create), then use update
to 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
来保存或更新记录,如果不存在则更新方法将保持记录,否则更新记录。
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))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.