Rails6 のちょい足しな新機能を試す７（touch_all 編）

# はじめに

Rails 6 に追加されそうな新機能を試す第7段。 今回のちょい足し機能は、日時を(現在時刻に)一気に更新するメソッド touch_all 編です。
記載時点では、Rails は 6.0.0.beta3 です。　`gem install rails --prerelease` でインストールできます。

```
$  rails --version
Rails 6.0.0.beta3
```

# 単純な model を作る

新機能を試すために、Book model を作ります。出版時刻なんてあるのかよというツッコミは無しでお願いします。

```
$ rails new sandbox_6_0_0b3
$ cd sandbox_6_0_0b3
$ rails g model Book title published_at:datetime
$ rails db:migrate
```

データ　２件作ります。

```ruby
$ bin/rails c
irb(main):001:0> Book.new(title: 'Ruby Book',  published_at: Time.now - 10.year).save
   (0.2ms)  BEGIN
  Book Create (0.4ms)  INSERT INTO "books" ("title", "published_at", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["title", "Ruby Book"], ["published_at", "2009-04-24 11:23:20.452962"], ["created_at", "2019-04-24 11:23:20.474368"], ["updated_at", "2019-04-24 11:23:20.474368"]]
   (1.2ms)  COMMIT
=> true
irb(main):002:0> Book.new(title: 'Rails Book',  published_at: Time.now - 5.year).save
   (0.4ms)  BEGIN
  Book Create (0.7ms)  INSERT INTO "books" ("title", "published_at", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["title", "Rails Book"], ["published_at", "2014-04-24 11:23:41.370049"], ["created_at", "2019-04-24 11:23:41.370751"], ["updated_at", "2019-04-24 11:23:41.370751"]]
   (7.2ms)  COMMIT
=> true
irb(main):003:0> Book.all
  Book Load (0.7ms)  SELECT "books".* FROM "books" LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation 
[
#<Book id: 2, title: "Ruby Book", published_at: "2009-04-24 11:23:20", created_at: "2019-04-24 11:23:20", updated_at: "2019-04-24 11:23:20">, 
#<Book id: 3, title: "Rails Book", published_at: "2014-04-24 11:23:41", created_at: "2019-04-24 11:23:41", updated_at: "2019-04-24 11:23:41">
]>
irb(main):005:0>
```

`touch_all` を使ってみます。 （`Book.all` の結果はわかりやすいように改行を入れました。）

## 引数なしで touch_all
`touch_all` を引数なしで実行すると `updated_at` が現在時刻に更新されます。

```ruby
irb(main):007:0> Book.all.touch_all
  Book Update All (7.6ms)  UPDATE "books" SET "updated_at" = $1  [["updated_at", "2019-04-24 11:38:54.990656"]]
=> 2
irb(main):008:0> Book.all
  Book Load (0.8ms)  SELECT "books".* FROM "books" LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation 
[
#<Book id: 2, title: "Ruby Book", published_at: "2009-04-24 11:23:20", created_at: "2019-04-24 11:23:20", updated_at: "2019-04-24 11:38:54">, 
#<Book id: 3, title: "Rails Book", published_at: "2014-04-24 11:23:41", created_at: "2019-04-24 11:23:41", updated_at: "2019-04-24 11:38:54">
]>
```

## touch_all(column)
`touch_all` の引数にカラムを指定すると指定したカラムと `updated_at` が現在時刻に更新されます。
`where` と組み合わせることもできます。
(Ruby Book の `published_at` と `updated_at` が現在時刻に更新されます。）

```ruby
irb(main):009:0> Book.where(title: 'Ruby Book').touch_all(:published_at)
  Book Update All (8.2ms)  UPDATE "books" SET "updated_at" = $1, "published_at" = $2 WHERE "books"."title" = $3  [["updated_at", "2019-04-24 11:40:16.201803"], ["published_at", "2019-04-24 11:40:16.201803"], ["title", "Ruby Book"]]
=> 1
irb(main):010:0> Book.all
  Book Load (0.7ms)  SELECT "books".* FROM "books" LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation 
[
#<Book id: 3, title: "Rails Book", published_at: "2014-04-24 11:23:41", created_at: "2019-04-24 11:23:41", updated_at: "2019-04-24 11:38:54">, 
#<Book id: 2, title: "Ruby Book", published_at: "2019-04-24 11:40:16", created_at: "2019-04-24 11:23:20", updated_at: "2019-04-24 11:40:16">
]>
```
## touch_all(column1, column2, ...)

`touch_all` の引数に複数のカラムを指定することもできます。
(Rails Book の `created_at` , `updated_at` , `published_at` が現在時刻に更新されます。)

```ruby
irb(main):011:0> Book.where(title: 'Rails Book').touch_all(:published_at, :created_at)
  Book Update All (7.8ms)  UPDATE "books" SET "updated_at" = $1, "published_at" = $2, "created_at" = $3 WHERE "books"."title" = $4  [["updated_at", "2019-04-24 11:54:03.981679"], ["published_at", "2019-04-24 11:54:03.981679"], ["created_at", "2019-04-24 11:54:03.981679"], ["title", "Rails Book"]]
=> 1
irb(main):012:0> Book.all
  Book Load (0.9ms)  SELECT "books".* FROM "books" LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation
[
#<Book id: 2, title: "Ruby Book", published_at: "2019-04-24 11:40:16", created_at: "2019-04-24 11:23:20", updated_at: "2019-04-24 11:40:16">, 
#<Book id: 3, title: "Rails Book", published_at: "2019-04-24 11:54:03", created_at: "2019-04-24 11:54:03", updated_at: "2019-04-24 11:54:03">
]>
```
## touch_all(column1, column2,..., time: xxx)
`touch_all` の引数に `time: xxxx` で指定した時刻に更新することもできます。
(Rails Book の `created_at` , `updated_at` , `published_at` が 3年前に更新されます。）

```ruby
irb(main):013:0> Book.where(title: 'Rails Book').touch_all(:published_at, :created_at, time: Time.now - 3.year)
  Book Update All (7.3ms)  UPDATE "books" SET "updated_at" = $1, "published_at" = $2, "created_at" = $3 WHERE "books"."title" = $4  [["updated_at", "2016-04-24 11:59:16.030048"], ["published_at", "2016-04-24 11:59:16.030048"], ["created_at", "2016-04-24 11:59:16.030048"], ["title", "Rails Book"]]
=> 1
irb(main):014:0> Book.all
  Book Load (0.8ms)  SELECT "books".* FROM "books" LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation 
[
#<Book id: 2, title: "Ruby Book", published_at: "2019-04-24 11:40:16", created_at: "2019-04-24 11:23:20", updated_at: "2019-04-24 11:40:16">, 
#<Book id: 3, title: "Rails Book", published_at: "2016-04-24 11:59:16", created_at: "2016-04-24 11:59:16", updated_at: "2016-04-24 11:59:16">
]>
irb(main):015:0>

```

## touch_all 実行時の callback や validation

`touch_all` は内部で `update_all` を呼び出していて、`touch_all` が実行されるときに、callback や validation は実行されません。


# 参考情報

* [What is new in Rails 6.0](https://bogdanvlviv.com/posts/ruby/rails/what-is-new-in-rails-6_0.html)
* [Add `touch_all` method to `ActiveRecord::Relation`](https://github.com/rails/rails/pull/31513)
* [Fix typo in the `touch_all` doc [ci skip]](https://github.com/rails/rails/commit/ac1efe7a947ba04b276a7109f1a86e559a6ab683)