MicroPostにおける投稿機能

この記事では、Micorpostにおける投稿機能について、
Modelのコーディングを簡単に理解した後、検証を通じて理解を深める事を目的としている。

投稿機能は以下の手順でコーディングを行う
> - モデルファイルとマイグレーションファイルの作制
- Micropostmodel
- UserModel


投稿機能は簡単に説明すると
ユーザーがツイートを投稿する際、そのツイートにユーザ情報を持たせる、
という機能を実装する。

では、手順に沿って解説を行う。

# １．モデルファイルとマイグレーションファイルの作成
railsコマンドにより、Micropostモデルを作成します。
カラムは`content:string`と `user:references`の二つです。

*Commandline*

```ruby:qiita.rb
$ rails g model Micropost content:string user:references

      create    db/migrate/20170207073121_create_microposts.rb
      create    app/models/micropost.rb
```
一対多を設定する場合には、`user:references` のように、
データの型として `references` を指定します

 `references` の詳しい説明は後述します。

###　①マイグレーションファイル
マイグレーションファイルを見てみましょう。

*db/migrate/年月日時_create_microposts.rb*

```ruby:qiita.rb
class CreateMicroposts < ActiveRecord::Migration[5.0]
  def change
    create_table :microposts do |t|
      t.string :content
      t.references :user, foreign_key: true

      t.timestamps
    end
  end
end
```
Micropost が持つカラムは、 `content` と `user` です。
`content` はツイートメッセージであり
`user` は User と一対多の関係を保存するためのカラムです。

テーブルを作成するマイグレーションファイル内で 
`t.references `という記述は「別のテーブルを参照させる」という意味になります。

User にカラムを追加せずとも、Micropost に User 用のカラムを追加するだけで
データベース上の一対多の関係が表現可能になります。

`t.references :user, foreign_key: true` は、
実際のデータベース上では、 user_id カラムとして存在し、
そこにMicropostインスタンスの User の id が保存されます。
Railsの方で自動的にUserを参照するようになっている。

これで Micropost を発言したユーザを特定することができます。
また、foreign_key は外部キー制約というものです。
外部キー制約についてはここでは説明しません。





###　②Micropost Model
app/models/micropost.rb

```ruby:qiita.rb
class Micropost < ApplicationRecord
  belongs_to :user
end
```
`belongs_to :user`は、User と Micropost の一対多を表現している。
つまり、「参照元テーブルから参照先テーブルにアクセスする」のである。
belongs_toの記述よってMicropostのuser_idと、Userのidの値が紐付きます。

このコードのおかげで、`micropost.user `とすると、
この micropost インスタンスを持っている User を取得することができる。

[Railsドキュメント：belongs_to](http://railsdoc.com/references/belongs_to)

# ２．モデルファイルとマイグレーションファイルの作成

###　①マイグレーションファイル
*db/migrate/20170206063439_create_users.rb*

```ruby:qiita.rb
class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email
      t.string :password_digest

      t.timestamps
    end
  end
end
```

###　②User Model
app/models/user.rb

```ruby:qiita.rb
class User < ApplicationRecord
  before_save { self.email.downcase! }
  validates :name, presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i },
                    uniqueness: { case_sensitive: false }
  has_secure_password

  has_many :microposts
end
```
User モデルファイルも一対多を表現しておきます。
User から Micropost をみたとき、複数存在するので、 
`has_many :microposts`とします。

これにより`user.microposts` にて
 User のインスタンスが自分の Microposts を取得することができます。 

テーブルを作成するマイグレーションファイル内で 
`t.references `という記述は別のテーブルを参照させるという意味になります。

#３．[検証]rails console で投稿を作成
```ruby:qiita.rb
user = User.first
```
`first`は、データベースに保存された最もid の若いユーザレコードの
インスタンスを取得することができます。

この`user`は、user_idの1を保持している。

```ruby:qiita.rb
> user.microposts
  Micropost Load (0.5ms)  SELECT `microposts`.* FROM `microposts` WHERE `microposts`.`user_id` = 1
 => #<ActiveRecord::Associations::CollectionProxy []>
```

Userモデルの`has_many :microposts'により、
`user.microposts` が使えるようになっている。

この時点で`user.microposts` を使って
User のインスタンスが自分の投稿（microposts） を取得しても、
中身はまだ空っぽである。

ここでは、Micropostモデルの操作が、最終的には SQL を生成し、
micropostsテーブルから`user_id`が1のレコードを検索し、結果が空となっている。

```ruby:qiita.rb
> micropost = user.microposts.build(content: 'hello')
 => #<Micropost id: nil, content: "hello", user_id: 1, created_at: nil, updated_at: nil>
```
今度は投稿（micropost）のインスタンスを生成してみよう。
投稿の作成は `user.microposts.build `のように操作する。
先ほど`first`により取得したインスタンスを元に、ポストを作成する。

`user.microposts.build `、いわゆる`build`は 
`Micropost.new(user: user) `と同じようにインスタンス生成の処理である。
※userカラムに予め変数が代入されている。

このコードにより、Micropostのインスタンスが生成され、
生成されたインスタンスは、User_idが付保されることで、
Userとの紐付がなされる。

belongs_toの記述よってMicropostのuser_idと、Userのidの値が紐付いているので、
`Micropost.new(user: user)`でも値を渡す際に、
内部的にこの関連付けが使われるので、上手くいくということです。

ただ、ここは`Micropost.new(user: user)`より
`Micropost.new(user_id: user.id)`の方が、イメージしやすい。
belongs_toによってテキストのようにも書ける、と覚えておけば良い。

user_idに値が入っており、これにより、
投稿をユーザーと紐付けて作成しているのである。

```ruby:qiita.rb
> micropost.save
   (0.3ms)  BEGIN
  SQL (0.7ms)  INSERT INTO `microposts` (`content`, `user_id`, `created_at`, `updated_at`) VALUES ('hello', 1, '2017-02-07 07:52:59', '2017-02-07 07:52:59')
   (5.0ms)  COMMIT
 => true
```
保存する

```ruby:qiita.rb
> User.first.microposts
  User Load (0.3ms)  SELECT  `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
  Micropost Load (0.3ms)  SELECT `microposts`.* FROM `microposts` WHERE `microposts`.`user_id` = 1
 => #<ActiveRecord::Associations::CollectionProxy [#<Micropost id: 1, content: "hello", user_id: 1, created_at: "2017-02-07 07:52:59", updated_at: "2017-02-07 07:52:59">]>
```
改めて、ユーザーの投稿を確認してみよう。
先ほどのレコードが保存されていることが分かる。

`User.first.microposts`とは、
`user = User.first`と`user.microposts`を繋げて書いたものである。
`has_many :microposts`のアソシエーションで使えるようになったメソッドである。