Rails 4 :Detailed Association Reference

#introduction
自習用のRails Guide「Detailed Association Reference」の日本語訳です。
http://guides.rubyonrails.org/association_basics.html#detailed-association-reference
based on version at 2014/07/11(JST)です。
めっちゃ間違ってるかもしれない。

#belongs_to Association Reference

##追加メソッド
`belongs_to`のアソシエーションでは以下のメソッドが使える。

- association(force_reload = false)
- association=(associate)
- build_association(attributes = {})
- create_association(attributes = {})
- create_association!(attributes = {})

例えば以下のようなアソシエーションのモデルでは

```rb
class Order < ActiveRecord::Base
  belongs_to :customer
end

```

以下のメソッドが利用可能になる。

```
customer
customer=
build_customer
create_customer
create_customer!
```

###association(force_reload = false)

こんな感じ。該当するオブジェクトがない場合は、`nil`を返す。

```rb
@customer = @order.customer
```

###association=(associate)

オブジェクトに関連オブジェクトをアサインする。関連オブジェクトの外部キーにはオブジェクトの主キーが自動で代入される。

```rb
@order.customer = @customer
```

###build_association(attributes = {})
インスタンスは作られるけどsaveはされない。

```rb
@customer = @order.build_customer(customer_number: 123,
                                  customer_name: "John Doe")
```

###create_association(attributes = {})

インスタンスが作られて、かつsaveされる。

```rb
@customer = @order.create_customer(customer_number: 123,
                                   customer_name: "John Doe")
```

###create_association!(attributes = {})

上記の`create_association` と同じだけどレコードがinvalidのとき `ActiveRecord::RecordInvalid`をraiseする。

##オプション

アソシエーションを作成するとき、オプションが使える。こんな感じで。

```rb
class Order < ActiveRecord::Base
  belongs_to :customer, dependent: :destroy,
    counter_cache: true
end
```

`belongs_to` アソシエーションでは下記のオプションが使用可能。

```
:autosave
:class_name
:counter_cache
:dependent
:foreign_key
:inverse_of
:polymorphic
:touch
:validate
```

###:autosave
親オブジェクトをsaveしたとき、子オブジェクトを自動でsaveしたりdestroyしたりする。

### :class_name
モデルの名前をアソシエーションから読み取れない場合、`:class_name`でモデルの名前を指定できる。たとえばorderはcustomerに所属しているけど、customerを含むクラスの名前がPatronだったときとか。


```rb
class Order < ActiveRecord::Base
  belongs_to :customer, class_name: "Patron"
end
```

###:counter_cache

関連するオブジェクトの個数を把握するのに役立つ。たとえば下記のようなアソシエーションがある場合

```rb
class Order < ActiveRecord::Base
  belongs_to :customer
end
class Customer < ActiveRecord::Base
  has_many :orders
end
```

 `@customer.orders.size` だと都度DBに`COUNT(*)`クエリを発行するけど、これを避けるための方法が用意されている。

```rb
class Order < ActiveRecord::Base
  belongs_to :customer, counter_cache: true
end
class Customer < ActiveRecord::Base
  has_many :orders
end
```
上記でorderの個数に`size`メソッドでアクセスできるようになる。しかし`:counter_cache`の利用には、`belongs_to`で指定された方のモデルに実際のカラムが必要になる。たとえば上記のケースでは、`Customer`に`orders_count`という名称のカラムが必要になる。必要に応じて下記の記法で既存のカラムを利用することもできる。追加されたカラムは`attr_readonly`でアクセス可能である。

```rb
class Order < ActiveRecord::Base
  belongs_to :customer, counter_cache: :count_of_orders
end
class Customer < ActiveRecord::Base
  has_many :orders
end
```


###:dependent
DBの制約を付与できる。

:destroy, 親オブジェクトがdestroyされたら、子オブジェクトもdestroyされる。
:delete, 親オブジェクトがdestroyされたら、destroyの呼び出しなしに即時に子オブジェクトのレコードをDBから削除する。

###:foreign_key

外部キーの名称を指定できる。

```rb
class Order < ActiveRecord::Base
  belongs_to :customer, class_name: "Patron",
                        foreign_key: "patron_id"
end
```

外部キー制約は付与されないので、外部キー制約を付与したいときは migrationに記述すること。

###:inverse_of

逆の順序のアソシエーションも利用可能にする。（よくわからない） `:polymorphic`オプションとは併用できない。

```rb
class Customer < ActiveRecord::Base
  has_many :orders, inverse_of: :customer
end
 
class Order < ActiveRecord::Base
  belongs_to :customer, inverse_of: :orders
end
```

###:polymorphic
ポリモーフィック関連を利用可能にする。

###:touch

`:touch` を `:true` にすると、子オブジェクトがsaveされたりdestroyされたりしたとき、親オブジェクトの `updated_at` や `updated_on` にカレントタイムが設定される。下記の場合、`order`をsaveしたりdestroyしたりすると、`customer`のタイムスタンプが更新される。

```rb
class Order < ActiveRecord::Base
  belongs_to :customer, touch: true
end
 
class Customer < ActiveRecord::Base
  has_many :orders
end
```

下記の記法でタイムスタンプの属性名称を指定可能。

```rb
class Order < ActiveRecord::Base
  belongs_to :customer, touch: :orders_updated_at
end
```

###validate
`:validate` を `:true`にすると子オブジェクト(ここではorder)がsaveされるとき検証をおこなう。

```rb
class Order < ActiveRecord::Base
  belongs_to :customer, validate: true
end
 
class Customer < ActiveRecord::Base
  has_many :orders
end
```

##スコープ

下記のスコープが使える。

```rb
class Order < ActiveRecord::Base
  belongs_to :customer, -> { where active: true },
                        dependent: :destroy
end
```

下記のスコープが使える。

```
where
includes
readonly
select
```

###where

親オブジェクトにたいする指定条件を付与する。下記の例では`order`は`active`が`true`になっている`customer`にのみ所属するように指定される。

```rb
class Order < ActiveRecord::Base
  belongs_to :customer, -> { where active: true }
end
```

###includes

あいだにモデルをはさむアソシエーションで eager-loadしたいときにはincludeを利用できる。

```rb
class LineItem < ActiveRecord::Base
  belongs_to :order
end
 
class Order < ActiveRecord::Base
  belongs_to :customer
  has_many :line_items
end
 
class Customer < ActiveRecord::Base
  has_many :orders
end
```

もし頻繁に`@line_item.order.customer`するようなら、`include`を使う方が効率的である。（DBへの接続回数を減らせるので。）

```rb
class LineItem < ActiveRecord::Base
  belongs_to :order, -> { includes :customer }
end
 
class Order < ActiveRecord::Base
  belongs_to :customer
  has_many :line_items
end
 
class Customer < ActiveRecord::Base
  has_many :orders
end
```

アソシエーションが直接の場合、includeは不要。上記の場合、`@order.customer`については `customer`が自動で eager-loadされるので`order`に`-> { includes :customer }`は不要。


###readonly
親オブジェクトに読み取り専用でアクセスするようになる。

###select
親オブジェクトのすべてのカラムをSELECTするようにSQLのSELECT文を上書きする。

##親オブジェクトの存在確認

`.nil?`で親がいるか確認できる。

```rb
if @order.customer.nil?
  @msg = "No customer found for this order"
end
```

##ObjectがSaveされるタイミング

saveされるまで自動でsaveはしない。

#has_one Association Reference
あとで書く。

#has_many Association Reference
あとで書く。

#has_and_belongs_to_many Association Reference
あとで書く。

#Association Callbacks
あとで書く。

#Association Extensions

匿名のモジュールをつかってメソッドなどを拡張できる。

```rb
class Customer < ActiveRecord::Base
  has_many :orders do
    def find_by_order_prefix(order_number)
      find_by(region_id: order_number[0..2])
    end
  end
end
```

複数のアソシエーションで利用したい場合、名前つきの拡張モジュールが定義できる。

```rb
module FindRecentExtension
  def find_recent
    where("created_at > ?", 5.days.ago)
  end
end
 
class Customer < ActiveRecord::Base
  has_many :orders, -> { extending FindRecentExtension }
end
 
class Supplier < ActiveRecord::Base
  has_many :deliveries, -> { extending FindRecentExtension }
end

```

下記の3つのproxy_association accessorでassociation proxyを参照できる。

```rb
proxy_association.owner
#=>returns the object that the association is a part of.
proxy_association.reflection
#=>returns the reflection object that describes the association.
proxy_association.target
#~>returns the associated object for belongs_to or has_one, or the collection of associated objects for has_many or has_and_belongs_to_many.
```