Ruby on rails 3 ActiveRecord:如果存在,则更新记录。是否创建?

Ruby on rails 3 ActiveRecord:如果存在,则更新记录。是否创建?,ruby-on-rails-3,activerecord,Ruby On Rails 3,Activerecord,正在尝试在活动记录中实现create if not EXCESS update记录 当前使用: @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

正在尝试在活动记录中实现create if not EXCESS update记录

当前使用:

@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!

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

您可能正在寻找
first\u或\u create
或类似的内容:

如果用户和学生之间有关联,这会更漂亮。类似于

@student = current_user.student || current_user.build_student
@student.department_id = 1
@student.save
编辑:

您也可以使用Sevensacat的回答,但您仍然需要处理不同的场景,例如更新学生的部门id

更新:

你可以用


它是“查找”或“创建”,而不是“先查找”或“创建”。
前任: 客户端。在Rails 4中查找或创建(名字:“Andy”)

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

::first_或_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">

(注意,有一种方法叫做
#create\u或#update
,但不要被你在谷歌上找到的任何方法所愚弄;这只是
#save
使用的一种私有方法)

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

Student.where(user_id: id).first_or_create(age: 16).update_attribute(:age, 16)
在Rails 5中

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

(从@Zorayr answer获得所有积分)。

first\u或\u create不会更新记录,因此它不会使代码变得更好。但它会返回找到的或创建的记录,因此您可以将
update
调用链接到它。请参阅本页的。这会导致创建时的验证出现问题,并导致两个单独的db事务。来自@Zorayr的答案更可取,因为它尊重验证。这是真的。要通过验证,我认为您可以使用
first\u或\u initialize
,方法与
first\u或\u create
完全相同;但是你必须对结果调用
save
update
。@rune schjellerup philosof,但你可以在
之后更新它。首先\u或\u创建(用户id:current\u user.id,部门:1)。更新(部门:1)
确实存在,(即使在一年前),我不确定你想用这个答案说什么,但这听起来像是对另一篇文章的评论,两者的作用也略有不同
Model.where(find:'find_value')。first_或_create(create:'create_value')
相当于
Model.find_或_create_by(find:'find_value'){| r | r.create='create_value'}
查找或_初始化+
更新_属性将执行以下操作
更新属性的返回值是一个布尔值,而不是实际记录。您可以使用
Student.find_或_initialize_by(…).tap{e|e.update!(…)}
有两个问题-首先,您无法“仅在创建时设置值”,其次,它查看表列而不是模型方法。例如,
User.where(email:email).find_或_initialize_by(password:password)
会给您一个
列users.password不存在的错误(假设您是明智的,并且没有在数据库中存储普通密码)。这是一个不错的解决方案。在Rails 4中,我只会将
.update\u attributes
更改为
.update
。这是一种惯用的方法,源代码显示它与.update\u属性相同!(它只需分配属性并调用
.save
…检查和)。
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">
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')
Student.where(user_id: id).first_or_create(age: 16).update_attribute(:age, 16)
Student.
  find_or_initialize_by(:user_id => current_user.id).
  update(:department => 1)