この記事では、Micorpostにおける投稿機能について、
Modelのコーディングを簡単に理解した後、検証を通じて理解を深める事を目的としている。
投稿機能は以下の手順でコーディングを行う
- モデルファイルとマイグレーションファイルの作制
- Micropostmodel
- UserModel
投稿機能は簡単に説明すると
ユーザーがツイートを投稿する際、そのツイートにユーザ情報を持たせる、
という機能を実装する。
では、手順に沿って解説を行う。
1.モデルファイルとマイグレーションファイルの作成
railsコマンドにより、Micropostモデルを作成します。
カラムはcontent:string
と user:references
の二つです。
Commandline
$ 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
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
class Micropost < ApplicationRecord
belongs_to :user
end
belongs_to :user
は、User と Micropost の一対多を表現している。
つまり、「参照元テーブルから参照先テーブルにアクセスする」のである。
belongs_toの記述よってMicropostのuser_idと、Userのidの値が紐付きます。
このコードのおかげで、micropost.user
とすると、
この micropost インスタンスを持っている User を取得することができる。
2.モデルファイルとマイグレーションファイルの作成
### ①マイグレーションファイル
db/migrate/20170206063439_create_users.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
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
という記述は別のテーブルを参照させるという意味になります。
#3.[検証]rails console で投稿を作成
user = User.first
first
は、データベースに保存された最もid の若いユーザレコードの
インスタンスを取得することができます。
このuser
は、user_idの1を保持している。
> 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のレコードを検索し、結果が空となっている。
> 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に値が入っており、これにより、
投稿をユーザーと紐付けて作成しているのである。
> 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
保存する
> 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
のアソシエーションで使えるようになったメソッドである。