Rails 中的 update

作者:周星 发布:2017-10-07

Rails 中有很多 update model 的方法,今天我们来总结一下 Rails 中的各种 update.

1.update

update 方法在 ActiveRecord::Relation 上执行,它接收两个参数,id 和一个 name: value 型的 Hash。如果执行成功则返回这个 id 对应的修改后的对象,该方法不能绕过 model 层 Validates。

irb(main):028:0> Message.update(12, content: "xsfef", publish_status: false)
  Message Load (23.6ms)  SELECT `messages`.* FROM `messages` WHERE `messages`.`id` = 12 LIMIT 1
   (1.1ms)  BEGIN
   (3.9ms)  UPDATE `messages` SET `content` = 'xsfef', `publish_status` = 0, `updated_at` = '2015-06-07 11:08:43' WHERE `messages`.`id` = 12
   (0.3ms)  COMMIT
=> #<Message id: 12, user_id: 1, content: "xsfef", created_at: "2014-04-25 21:27:29", updated_at: "2015-06-07 11:08:43", publish_status: false>

注: Rails 4 中 object 也有 update 方法,object 上的 update 方法 alias update_attributes

2.update_all

update_all 方法在 ActiveRecord::Relation 上执行,顾名思义,它会 update 很多的 record,此方法生成一个 SQL UPDATE 语句然后直接发送给数据库,所以它会绕过 model 层的 Validates 和 Callback,它接收3个参数,第一个是 updates(String),第二个是 condition(可省略/String),第三个是 option(可省略/Hash),比如 limit/order,执行成功返回 condition match 的 record 数量,请看下面这个例子:

irb(main):098:0* Message.update_all("publish_status = 1", "content like '%fe%'", order: 'created_at')
  SQL (1.9ms)  UPDATE `messages` SET publish_status = 1 WHERE (content like '%fe%') ORDER BY created_at
=> 10

3.update_attributes

update_attributes 方法最为常见,此方法在单个 object 上执行,并接收一个 key: value 型的参数,自动执行 save 方法,需要注意的是它不会绕过 model 层 Validates 和 Callback,执行结果为 true or false,这在判断一个 model 是否成功 update 时非常有用。

irb(main):021:0* m = Message.last
  Message Load (0.3ms)  SELECT `messages`.* FROM `messages` ORDER BY `messages`.`id` DESC LIMIT 1
=> #<Message id: 12, user_id: 1, content: "fef", created_at: "2014-04-25 21:27:29", updated_at: "2015-06-07 11:19:04", publish_status: true>
irb(main):022:0> m.update_attributes({content: "111"})
   (0.9ms)  SAVEPOINT active_record_1
   (0.2ms)  UPDATE `messages` SET `content` = '111', `updated_at` = '2015-06-07 11:34:32' WHERE `messages`.`id` = 12
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true

4.update_attributes!

加上感叹号的方法大家都懂的,它会调用 save!,即不成功会抛出异常,这两种方法请按需选择。

5.update_attribute

较上面的方法少了个 s,此方法需传递两个参数,name 和 value,返回值同样为 true or false。

irb(main):055:0* Message.last.update_attribute(:content, "55555")
  Message Load (0.2ms)  SELECT `messages`.* FROM `messages` ORDER BY `messages`.`id` DESC LIMIT 1
   (0.1ms)  SAVEPOINT active_record_1
   (0.2ms)  UPDATE `messages` SET `content` = '55555', `updated_at` = '2015-06-07 11:47:41' WHERE `messages`.`id` = 12
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true

但是需要注意以下几点:

model 层 Validates 被绕过,但是 Callbacks 不会

只有值变化时才会更新 updated_at/updated_on 字段(同 update_attributes)

update 所有在此 object 上的 dirty attributes(此处需格外注意

如果需要更新的某个属性在数据库中是 readonly 的,则会抛出ActiveRecord::ActiveRecordError

irb(main):059:0* m = Message.last
  Message Load (0.2ms)  SELECT `messages`.* FROM `messages` ORDER BY `messages`.`id` DESC LIMIT 1
=> #<Message id: 12, user_id: 3, content: "55555", created_at: "2014-04-25 21:27:29", updated_at: "2015-06-07 11:47:41", publish_status: true>
irb(main):060:0> m.user_id = 100
=> 100
irb(main):061:0> m.update_attribute(:content, "the user_id will be updated too")
   (0.1ms)  SAVEPOINT active_record_1
   (0.2ms)  UPDATE `messages` SET `user_id` = 100, `content` = 'the user_id will be updated too', `updated_at` = '2015-06-07 11:48:55' WHERE `messages`.`id` = 12
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true
irb(main):062:0> m
=> #<Message id: 12, user_id: 100, content: "the user_id will be updated too", created_at: "2014-04-25 21:27:29", updated_at: "2015-06-07 11:48:55", publish_status: true>

我先改以下 m.user_id 的值,且没有 save,但是在执行 update_attribute(:content, "the user_id will be updated too") 时,user_id 也被更新了,update_attributes 方法也会如此,因为它们都调用了 save 方法。

6.update_column

update_column 的参数/返回值和 update_attribute 一样,区别在于 update_column 会绕过 model 层的 Validates 和 Callbacks,而且它不会更新 updated_at/updated_on 字段

7.update_columns

Rails 4 中的方法,参数是一个 name: value 的哈希

irb(main):022:0* m.update_columns({:title => "1", :content => "22"})
  SQL (0.3ms)  UPDATE `messages` SET `messages`.`title` = '1', `messages`.`content` = '22' WHERE `messages`.`id` = 1
=> true

8. assign_attributes

assign_attributes 方法接收一个 name: value 的哈希,它只支持赋值,需要手动 save,这在有些场景非常有用。

总结:Rails 的这些 update model 方法其实区别主要在于:是否绕过 Validates/Callbacks,是否需要手动 save,是否会更新 updated_at 字段,这里如果画张图可能会更好的让人记忆和查找。如果您对本文有什么意见或建议,请在下方评论。

支付宝扫码赞助博主


评论(0)