41

尝试在 Active Record 中实现创建,如果不存在则更新记录。

目前使用:

@student = Student.where(:user_id => current_user.id).first

if @student
    Student.destroy_all(:user_id => current_user.id)
end

Student = Student.new(:user_id => current_user.id, :department => 1
)
Student.save!

如果记录存在或创建记录,那么更新记录的正确方法是什么?

4

7 回答 7

77

在 Rails 4 中

Student.
  find_or_initialize_by(:user_id => current_user.id).
  update_attributes!(:department => 1)
于 2014-04-19T01:09:02.460 回答
17

您可能正在寻找first_or_create或类似的东西:

http://guides.rubyonrails.org/v3.2.17/active_record_querying.html#first_or_create

于 2013-01-30T08:03:42.340 回答
15

::first_or_create(自 v3.2.1 起可用)按照包装盒上的说明进行操作。

Model.where(find: 'find_value').
  first_or_create(create: 'create_value')

# If a record with {find: 'find_value'} already exists:
before #=> #<Model id: 1, find: "find_value", create: nil>
after  #=> #<Model id: 1, find: "find_value", create: nil>

# Otherwise:
before #=> nil
after  #=> #<Model id: 2, find: "find_value", create: "create_value">

如果您还希望它更新已经存在的记录,请尝试:

Model.where(find: 'find_value').
  first_or_create(create: 'create_value').
  update(update: 'update_value')

# If one already exists:
before #=> #<Model id: 1, find: "find_value", create: nil, update: nil>
after  #=> #<Model id: 1, find: "find_value", create: nil, update: "update_value">

# If it already matches, no UPDATE statement will be run:
before #=> #<Model id: 1, find: "find_value", create: nil, update: "update_value">
after  #=> #<Model id: 1, find: "find_value", create: nil, update: "update_value">

# Otherwise:
before #=> nil
after  #=> #<Model id: 2, find: "find_value", create: 'create_value', update: "update_value">

编辑 2016-03-08:根据Doug评论,如果您的验证在#createand#update调用之间失败,或者您想最小化数据库调用,您可以::first_or_initialize改用,以避免在第一次调用时保留记录。但是,您必须确保您致电#save#update之后才能保留记录(我不确定是否#update适用于尚未保留的记录):

Model.validates :update, presence: true # The create call would fail this

Model.where(find: 'find_value').
  first_or_initialize(create: 'create_value'). # doesn't call validations
  update(update: 'update_value')

(注意。有一种方法称为#create_or_update,但不要被您在 Google 上找到的任何文档所迷惑;这只是#save.

于 2014-08-26T03:18:24.997 回答
7
@student = Student.where(user_id: current_user.id).first
@student ||= Student.new(user_id: current_user.id)
@student.department_id = 1
@student.save

如果您在用户和学生之间有关联,这会更漂亮。类似的东西

@student = current_user.student || current_user.build_student
@student.department_id = 1
@student.save

编辑:

您也可以使用http://guides.rubyonrails.org/active_record_querying.html#first_or_create由 Sevenseacat 回答,但您仍然需要处理不同的情况,例如更新学生的部门 ID。

更新:

您可以使用find_or_create_by

@student = Student.find_or_create_by(user_id: current_user.id) do |student|
  student.department_id = 1
end
于 2013-01-30T08:07:17.330 回答
4

在 Rails 5 中

Student.
  find_or_initialize_by(:user_id => current_user.id).
  update(:department => 1)

(所有功劳取自@Zorayr 的回答)。

于 2019-03-11T17:25:41.697 回答
0

不幸的是,我认为最干净的方法是:

Student.where(user_id: id).first_or_create(age: 16).update_attribute(:age, 16)
于 2017-01-17T02:45:58.027 回答
-4

它是find_or_create_by不是first_or_create
例如:Client.find_or_create_by(first_name: 'Andy')

于 2014-01-31T10:43:52.183 回答