外部キーがnilでも保存できる方法

今回は外部キーがnilでもエラーが出ない方法について解説します。

infomationテーブル

|`id`|`talent_name`|`age`|`user_id`|
|----|------|-----|-------|
|1   |山田太郎|20|nil|
|2   |山田花子|20|nil|


usersテーブル                             

|`id`|`login_name`|
|-----|---|
|1|nick|
|2|tom|


今回はこの2つのテーブルを使います。usersテーブルとinfomationテーブルはアソシエーションを組んでいます。
usersテーブルは親で、infomationテーブルは子です。

※マーク今回infomationテーブルはどんな情報が追加されてもuser_idカラムは'nil'とします
その状態でスクレイピングをしたらこのようになります。

```termin
Running via Spring preloader in process 5268
Loading development environment (Rails 5.2.4.4)
[1] pry(main)> Scraping.get_infomation
D, [2020-11-09T06:30:25.470701 #5268] DEBUG -- :    (0.3ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
D, [2020-11-09T06:30:25.489471 #5268] DEBUG -- :   Infomation Load (1.5ms)  SELECT  `infomations`.* FROM `infomations` WHERE `infomations`.`name` = '波瑠' ORDER BY `infomations`.`id` ASC LIMIT 1
D, [2020-11-09T06:30:25.503981 #5268] DEBUG -- :    (0.1ms)  BEGIN
D, [2020-11-09T06:30:25.524340 #5268] DEBUG -- :    (0.1ms)  ROLLBACK
Return value is: nil

[24, 33] in /home/ec2-user/environment/filebook/app/models/scraping.rb
   24:         names = aaas.at('h1').inner_text  if aaas.at('h1')
   25:         image_urls = personal_page.at('.main_image img').get_attribute('src') if personal_page.at('.main_image img')
   26:         infomation = Infomation.where(name: names).first_or_initialize
   27:         infomation.age = ages
   28:         infomation.image_url = image_urls
   29:         infomation.save
   30:         
   31:         byebug
=> 32:     end
   33: end
(byebug) infomation
#<Infomation id: nil, age: 29, name: "波瑠", image_url: "https://images.talent-dictionary.com/uploads/image...", created_at: nil, updated_at: nil>
(byebug) 
本当はuser_idカラムがあります。user_id: nil  ごめん

```

途中でrollbackされinfomationテーブルにはidがnil,created_atやupdated_atもnilとなっており保存ができないことがわかります。

そこで今回
user_idがnilでも保存できる方法を解説します。
まずは小要素のモデルを開いてください。

``` ruby:infomation.rb
class Infomation < ApplicationRecord
    belongs_to: user
end
```
このようにアソシエーションを組んでいると思いますがその横にoptional: trueをつけてください。


```ruby:infomation.rb
class Infomation < ApplicationRecord
    belongs_to: user,optional: true
end

```

そうすると

```
Running via Spring preloader in process 6358
Loading development environment (Rails 5.2.4.4)
[1] pry(main)> Scraping.get_infomation
D, [2020-11-09T06:45:18.429070 #6358] DEBUG -- :    (0.4ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
D, [2020-11-09T06:45:18.434125 #6358] DEBUG -- :   Infomation Load (0.2ms)  SELECT  `infomations`.* FROM `infomations` WHERE `infomations`.`name` = '美山加恋' ORDER BY `infomations`.`id` ASC LIMIT 1
D, [2020-11-09T06:45:18.440170 #6358] DEBUG -- :    (0.1ms)  BEGIN
D, [2020-11-09T06:45:18.442031 #6358] DEBUG -- :   Infomation Create (0.2ms)  INSERT INTO `infomations` (`age`, `name`, `image_url`, `created_at`, `updated_at`) VALUES (23, '美山加恋', 'https://images.talent-dictionary.com/uploads/images/tldb/086a19d1703dda4390ae74328861c5c858939acb.jpg', '2020-11-09 06:45:18', '2020-11-09 06:45:18')
D, [2020-11-09T06:45:18.444995 #6358] DEBUG -- :    (2.3ms)  COMMIT
Return value is: nil

[23, 32] in /home/ec2-user/environment/filebook/app/models/scraping.rb
   23:         ages = aaas.at('.age').inner_text.delete('歳').to_i if aaas.at('.age')
   24:         names = aaas.at('h1').inner_text  if aaas.at('h1')
   25:         image_urls = personal_page.at('.main_image img').get_attribute('src') if personal_page.at('.main_image img')
   26:         infomation = Infomation.where(name: names).first_or_initialize
   27:         infomation.age = ages
   28:         infomation.image_url = image_urls
   29:         infomation.save
   30:         byebug
=> 31:     end
   32: end
(byebug) 

```

ちゃんとコミットされて保存されてますね!!!!!!
ちなみにoptional: trueとは外部キーのnilを許可すると言うことです。