ActiveRecord:如果存在,则更新记录吗?

时间:2013-01-30 07:59:03

标签: ruby-on-rails-3 activerecord

尝试在Active Record中实现create if else else 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!

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

7 个答案:

答案 0 :(得分:59)

在Rails 4中

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

答案 1 :(得分: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:根据Dougcomment,如果您的验证在#create#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上找到的任何documentation所欺骗;这只是一种私有方法#save。)

答案 2 :(得分:13)

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

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

答案 3 :(得分:4)

@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

答案 4 :(得分:0)

不幸的是,我认为最简洁的方法是:

Student.where(user_id: id).first_or_create(age: 16).update_attribute(:age, 16)

答案 5 :(得分:0)

在Rails 5中

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

(所有功劳均来自@Zorayr答案)。

答案 6 :(得分:-5)

find_or_create_by 而非 first_or_create
例如: Client.find_or_create_by(first_name:'Andy')