Skip to content
旧时的足迹
Go back

Rails - Delete the records

编辑此页

ActiveRecord::Relation

delete delete_all

以下是文档中的例子:

# Delete a single row
Todo.delete(1)

# Delete multiple rows
Todo.delete([2,3,4])

下面看下其源码实现:

# File activerecord/lib/active_record/relation.rb
def delete(id_or_array)
  where(primary_key => id_or_array).delete_all
end

源码很简单,这个方法其实就是调用了 delete_all 方法

例子:

Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')")
Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else'])
Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all

destroy destroy_all

例子:

# Destroy a single object
Todo.destroy(1)

# Destroy multiple objects
Todo.destroy([1,2,3])

来看下源码实现

# File activerecord/lib/active_record/relation.rb
def destroy(id)
  if id.is_a?(Array)
    id.map { |one_id| destroy(one_id) }
  else
    find(id).destroy
  end
end

源码中表示该方法会先实例化一个一个的对象再删除。

ActiveRecord::Associations::CollectionProxy

下面来看下 model 关联时的 :dependent option 对 has_many 来说

例如:

class User < ActiveRecord::Base
  has_many :posts # dependent: :nullify option by default
end

user.posts
# => #<ActiveRecord::Associations::CollectionProxy [#<Post id: 1, body: "aaa", user_id: 1, created_at: "2016-09-09 02:18:47", updated_at: "2016-09-09 02:18:47">, #<Post id: 2, body: "bbb", user_id: 1, created_at: "2016-09-09 02:18:58", updated_at: "2016-09-09 02:18:58">]>

user.posts.delete(Post.find(1))
# or (other way)
user.posts.delete(1)

Post.find(1)
# => #<Post id: 1, body: "aaa", user_id: nil, created_at: "2016-09-09 02:18:47", updated_at: "2016-09-09 02:18:47">

user.posts.delete_all

user.posts.size
# => 0

Post.find(1, 2)
# => [#<Post id: 1, body: "aaa", user_id: nil, created_at: "2016-09-09 02:18:47", updated_at: "2016-09-09 02:18:47">, #<Post id: 2, body: "bbb", user_id: nil, created_at: "2016-09-09 02:18:58", updated_at: "2016-09-09 02:18:58">]

当使用 delete 方法时,被删除记录会被实例化并且删除时 callback 方法会被触发

class User < ActiveRecord::Base
  has_many :posts, dependent: :destroy
end

user.posts
# => #<ActiveRecord::Associations::CollectionProxy [#<Post id: 7, body: "1", user_id: 1, created_at: "2016-09-09 06:20:17", updated_at: "2016-09-09 06:20:17">, #<Post id: 8, body: "2", user_id: 1, created_at: "2016-09-09 06:20:20", updated_at: "2016-09-09 06:20:20">, #<Post id: 9, body: "3", user_id: 1, created_at: "2016-09-09 06:20:23", updated_at: "2016-09-09 06:20:23">]>

user.posts.delete(7,8)
# => [#<Post id: 7, body: "1", user_id: 1, created_at: "2016-09-09 06:20:17", updated_at: "2016-09-09 06:20:17">, #<Post id: 8, body: "2", user_id: 1, created_at: "2016-09-09 06:20:20", updated_at: "2016-09-09 06:20:20">]

### DEBUG INFO
# Post Load (0.4ms)  SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 1 AND #`posts`.`id` IN (7, 8)
#   (0.2ms)  BEGIN
#  SQL (0.3ms)  DELETE FROM `posts` WHERE `posts`.`id` = 7
#  SQL (0.2ms)  DELETE FROM `posts` WHERE `posts`.`id` = 8
#   (43.4ms)  COMMIT

当使用 delete_all 方法时,虽然设置了 :dependent 为 :destroy ,但实际上其策略却会是 :delete_all ,这时删除操作并不会将记录实例化, callback 方法也不会被触发,实际操作将会是一条 DELETE 语句

user.posts.delete_all
### DEBUG INFO
# SQL (0.7ms)  DELETE FROM `posts` WHERE `posts`.`user_id` = 1

使用 delete 方法,记录会被真正删除,但是却不会调用其 destroy 方法,也不会触发 callbacks。(注意,如果参数传递的是 id 值,那么当此条目不存在时将会抛出异常 ‘ActiveRecord::RecordNotFound’)

user.posts.delete(12)
### DEBUG INFO
#  Post Load (0.4ms)  SELECT  `posts`.* FROM `posts` WHERE `posts`.`user_id` = 1 AND #`posts`.`id` = 12 LIMIT 1
#   (0.2ms)  BEGIN
#  SQL (0.3ms)  DELETE FROM `posts` WHERE `posts`.`user_id` = 1 AND `posts`.`id` = 12
#   (0.6ms)  COMMIT

这两个方法都会忽视掉 :dependent option


编辑此页
Share this post on:

Previous Post
VI-String-Matching-KMP
Next Post
Feed流系统