has_many 関連で関連元をセーブすると関連までセーブされる


> 当たり前かもしれないけど、これでハマったので自分への教訓として

## この記事の内容
1. `has_many` 関連で、 `1側` のモデルに紐ついた `多側` を `new` した後に、`1側` を`save!` した時の挙動

### 結論
`model.assertions.new` した後に `model` を`save`するときは`assertions` もまとめて保存されるから気をつけよう。(便利だけど)

# 環境
## 適当な関連

![スクリーンショット 2015-10-06 18.10.59.png](https://qiita-image-store.s3.amazonaws.com/0/37097/b63b42da-134c-72c8-cece-6b4d4e047924.png "スクリーンショット 2015-10-06 18.10.59.png")


## モデルのコード達
```app/models/*.rb
class Post < ActiveRecord::Base
  belongs_to :user
end

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

# やっていくぞい
## `has_many` 関連で、 `1側` のモデルに紐ついた `多側` を `new` した後に、`1側` を`save!` した時の挙動

```まずは準備.rb
User.create(name: 'haito')
   (0.1ms)  begin transaction
  SQL (0.8ms)  INSERT INTO "users" ("created_at", "name", "updated_at") VALUES (?, ?, ?)  [["created_at", "2015-10-06 07:03:05.166165"], ["name", "haito"], ["updated_at", "2015-10-06 07:03:05.166165"]]
   (0.8ms)  commit transaction
=> #<User id: 1, name: "haito", created_at: "2015-10-06 07:03:05", updated_at: "2015-10-06 07:03:05">

user = User.first
  User Load (0.2ms)  SELECT  "users".* FROM "users"   ORDER BY "users"."id" ASC LIMIT 1
=> #<User id: 1, name: "haito", created_at: "2015-10-06 07:03:05", updated_at: "2015-10-06 07:03:05">
```

```関連を確認.rb
user.posts
  Post Load (0.3ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."user_id" = ?  [["user_id", 1]]
=> []
```

:ok_woman: 

```関連に対して(new|build)を実行.rb
user.posts.new(text: '万策尽きた〜')
=> #<Post id: nil, text: "万策尽きた〜", user_id: 1, created_at: nil, updated_at: nil>

user.posts
=> [#<Post id: nil, text: "万策尽きた〜", user_id: 1, created_at: nil, updated_at: nil>]

user.posts.new(text: 'どんどんどーなっつどーんといこー！')
=> #<Post id: nil, text: "どんどんどーなっつどーんといこー！", user_id: 1, created_at: nil, updated_at: nil>

user.posts
=> [#<Post id: nil, text: "万策尽きた〜", user_id: 1, created_at: nil, updated_at: nil>, #<Post id: nil, text: "どんどんどーなっつどーんといこー！", user_id: 1, created_at: nil, updated_at: nil>]
```

この時点で `user` インスタンスに対して `Post` モデルのインスタンスが紐付いているのが分かる。

```ちょっと確認.rb
Post.all
  Post Load (0.1ms)  SELECT "posts".* FROM "posts"
=> []
```

しかし、まだ `Post` モデルはまだ一つもDBに保存されていない

```では保存.rb
user.save!
   (0.1ms)  begin transaction
  SQL (0.3ms)  INSERT INTO "posts" ("created_at", "text", "updated_at", "user_id") VALUES (?, ?, ?, ?)  [["created_at", "2015-10-06 07:08:44.255076"], ["text", "万策尽きた〜"], ["updated_at", "2015-10-06 07:08:44.255076"], ["user_id", 1]]
  SQL (0.1ms)  INSERT INTO "posts" ("created_at", "text", "updated_at", "user_id") VALUES (?, ?, ?, ?)  [["created_at", "2015-10-06 07:08:44.257063"], ["text", "どんどんどーなっつどーんといこー！"], ["updated_at", "2015-10-06 07:08:44.257063"], ["user_id", 1]]
   (1.5ms)  commit transaction
=> true

Post.all
  Post Load (0.2ms)  SELECT "posts".* FROM "posts"
=> [#<Post id: 1, text: "万策尽きた〜", user_id: 1, created_at: "2015-10-06 07:08:44", updated_at: "2015-10-06 07:08:44">,
 #<Post id: 2, text: "どんどんどーなっつどーんといこー！", user_id: 1, created_at: "2015-10-06 07:08:44", updated_at: "2015-10-06 07:08:44">]
```

お〜　保存されましたね。`1側` の `User` モデルへのクエリは発行されていませんが、Postへのクエリはガンガン発行されるようです :eyes: 

ではちょっと別の視点から作ってみます。

```Postモデルをnewしてから作成.rb
user = User.first
=> "省略"

post = Post.new(text: '上手くいかないことを人のせいにしているようなヤツは辞めちまえよ！')
=> #<Post id: nil, text: "上手くいかないことを人のせいにしているようなヤツは辞めちまえよ！", user_id: nil, created_at: nil, updated_at: nil>

post.save!
   (0.1ms)  begin transaction
  SQL (0.4ms)  INSERT INTO "posts" ("created_at", "text", "updated_at") VALUES (?, ?, ?)  [["created_at", "2015-10-06 07:14:06.612594"], ["text", "上手くいかないことを人のせいにしているようなヤツは辞めちまえよ！"], ["updated_at", "2015-10-06 07:14:06.612594"]]
   (1.4ms)  commit transaction
=> true
```

もちろん、ユーザーに紐ついていない状態なので保存されない。こいつを工夫してみる

```Postインスタンスをごにょごにょ.rb
user.posts.push(post)
   (0.1ms)  begin transaction
  SQL (0.3ms)  UPDATE "posts" SET "updated_at" = ?, "user_id" = ? WHERE "posts"."id" = 3  [["updated_at", "2015-10-06 07:15:16.168755"], ["user_id", 1]]
   (1.4ms)  commit transaction
=> [#<Post id: 1, text: "万策尽きた〜", user_id: 1, created_at: "2015-10-06 07:08:44", updated_at: "2015-10-06 07:08:44">,
 #<Post id: 2, text: "どんどんどーなっつどーんといこー！", user_id: 1, created_at: "2015-10-06 07:08:44", updated_at: "2015-10-06 07:08:44">,
 #<Post id: 3, text: "上手くいかないことを人のせいにしているようなヤツは辞めちまえよ！", user_id: 1, created_at: "2015-10-06 07:14:06", updated_at: "2015-10-06 07:15:16">]
```

`ary#push` は破壊的変更が発生するので、その時点で`post`インスタンスが`user`インスタンスに紐ついたので、`post.user_id` が更新され、DBに保存されます。

ｆｍｆｍ :thought_balloon: 
なるほどなぁ。

### まとめ
関連モデルはもちろん便利だけれど、`user.posts.new` とかそういうのは気をつけて使ったほうが良さそう。特に `user` に紐ついたインスタンスまでまとめて保存されるのは、忘れないようにするために工夫は必要ですね。