Rails Active_hashを攻略する

#　今日の目標

## acitive_hashでハッシュデータを扱う方法を学習する
## active_hashとは？

gemの一種。
ハッシュのデータを、ActiveRecordと同じ感覚で使えるようにしてくれる。

## どういう時に使うのか
以下の条件2つにあてはまるとき。

* これから扱うデータがDBにデータとして保存しておくほど重要ではない、かつ、基本的に変更されない。

* ActiveRecordと同じ感覚でデータを操作したい。

## 具体的に


例えば都道府県名一覧やカテゴリなど「基本的に変更されないデータ」があったとする。

そういったデータをDBに保存しておけば取り扱いは楽だけど、データの価値としてはDBに保持しておくほど重要ではない。
じゃあ ↓ の例のように定数でやるか？というとそれも微妙。
コード全体の見通しが悪くなるし、Activerecordを通して使えないので扱いづらくなってしまう。

```ruby:model
TODOHUKEN = [
 1: {name: :北海道, location: [12.323245, 102.3231231]},
 .
 .
 .
]
```
そういう悩みを解決するのに便利なのがactive_hash。
ハッシュデータをモデルとして定義することで、
ハッシュをDBから引っ張ってきたデータと同じように扱うことができるようになる。

## 導入方法
Gemfileにactive_hashを記載

```ruby:Gemfile
gem 'active_hash'
```
```
$ bundle install
```
これでおしまい

## モデル作成

次にモデルを作成する。
今回作成するモデルは2つ、AddressモデルとPrefectureモデル。
まずはrails g modelでAddressモデルを作成。

```
$ rails g model Address prefecture_id:integer city:string
```
続けてdb:createとdb:migrateを実行。

```
$ rails db:create
```

```
$ rails db:migrate
```

次にPrefectureモデルを作成。
こちらはrails g modelでの作成ではなく
ActiveHash::Baseを継承したPrefectureモデルを 自作 する。
※ActiveHash::Baseを継承することで初めて、ActiveRecordのメソッド(allなど)が使えるようになる。

都道府県のデータはハッシュで配列に格納する。

```ruby:app/models/prefecture.rb
class Prefecture < ActiveHash::Base
  self.data = [
      {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, {id: 3, name: '岩手県'},
      {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, {id: 6, name: '山形県'},
      {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, {id: 9, name: '栃木県'},
      {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, {id: 12, name: '千葉県'},
      {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, {id: 15, name: '新潟県'},
      {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, {id: 18, name: '福井県'},
      {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, {id: 21, name: '岐阜県'},
      {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, {id: 24, name: '三重県'},
      {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, {id: 27, name: '大阪府'},
      {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, {id: 30, name: '和歌山県'},
      {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, {id: 33, name: '岡山県'},
      {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, {id: 36, name: '徳島県'},
      {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, {id: 39, name: '高知県'},
      {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, {id: 42, name: '長崎県'},
      {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, {id: 45, name: '宮崎県'},
      {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'}
  ]
end


```
active_hashにはbelongs_to_active_hashメソッドが用意されているので、
address.rbに このメソッドを記述し、アソシエーションを定義する。

extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to_active_hash :prefecture
この2行を追加。

なお、Prefectureモデルのファイルには、アソシエーションを明示する必要はない。

これで準備は完了。

```ruby:app/models/address.rb
class Address < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :prefecture
end
```

##　コンソールで試してみる

```ruby
$ rails c

[1] pry(main)> @address_1 = Address.create(prefecture_id: 1, city: '函館市')                                                                                       
 id: 1,
 prefecture_id: 1,
 city: "函館市",
 created_at: Tue, 08 Jan 2019 11:41:41 UTC +00:00,
 updated_at: Tue, 08 Jan 2019 11:41:41 UTC +00:00>

[2] pry(main)> @address_2 = Address.create(prefecture_id: 13, city: '新宿区新宿')                                                                                        
 id: 2,
 prefecture_id: 13,
 city: "新宿区新宿",
 created_at: Tue, 08 Jan 2019 11:42:05 UTC +00:00,
 updated_at: Tue, 08 Jan 2019 11:42:05 UTC +00:00>

##############################
[3] pry(main)> @address_1.prefecture.name                                                                                                                                
=> "北海道"
[4] pry(main)> @address_2.prefecture.name                                                                                                                                
=> "東京都"
```
って感じで、prefecuture_idにPrefectureモデルに定義したハッシュのidを渡して、
@address.prefecture.nameで名前を取れる。
もちろんPrefecture.find でハッシュを取ることも可能。

## 利点
テーブルの数を無駄に増やさない
Activerecordを継承する
扱うデータが最初の2つの条件にあてはまる場合はactive_hashを活用していきましょう。

##使えるメソッド
```ruby
Country.all             # => returns all Country objects
Country.count           # => returns the length of the .data array
Country.first           # => returns the first country object
Country.last            # => returns the last country object
Country.find 1          # => returns the first country object with that id
Country.find [1,2]      # => returns all Country objects with ids in the array
Country.find :all       # => same as .all
Country.find :all, args # => the second argument is totally ignored, but allows it to play nicely with AR
Country.find_by_id 1    # => find the first object that matches the id

Country.find_by_name "foo"                    # => returns the first object matching that name
Country.find_all_by_name "foo"                # => returns an array of the objects with matching names
Country.find_by_id_and_name 1, "Germany"      # => returns the first object matching that id and name
Country.find_all_by_id_and_name 1, "Germany"  # => returns an array of objects matching that name and id
```
## 使えるインスタンスメソッド
```
Country#id          # => returns the id or nil
Country#id=         # => sets the id attribute
Country#quoted_id   # => returns the numeric id
Country#to_param    # => returns the id as a string
Country#new_record? # => returns true if is not part of Country.all, false otherwise
Country#readonly?   # => true
Country#hash        # => the hash of the id (or the hash of nil)
Country#eql?        # => compares type and id, returns false if id is nil
```
## 注意点
###検索
ActiveRecordのincludesやjoinsを使ってテーブル間の検索をするのは(たぶん)無理なので、
おとなしくmigrationファイルでActiveRecordを使用したほうが良さそう。
###多階層化
gem ancestryを使った多階層カテゴリー化には向いていない