アプリを作る Micropostモデル

###user-micropostsにチェックアウト
```
git checkout -b user-microposts
```
###マイクロポストのモデルを作成
```
ubuntu:~/environment/my_app (user-microposts) $ rails generate model Micropost content:text user:references

user:references
自動的にインデックスと外部キー参照付きのuser_idカラムが追加され、UserとMicropostを関連付けする下準備をしてくれます。

Running via Spring preloader in process 4915
      invoke  active_record
      create    db/migrate/20220122135127_create_microposts.rb
      create    app/models/micropost.rb
      invoke    test_unit
      create      test/models/micropost_test.rb
      create      test/fixtures/microposts.yml
```
###app/models/micropost.rb
```rb
class Micropost < ApplicationRecord
  belongs_to :user
  # userモデルと関連付けがされる
    # belongs_to関連付けを行なうと、他方のモデルとの間に「1対1」のつながりが設定されます。
  default_scope -> { order(created_at: :desc) }
  # アロー演算子は、ラムダを作成するための演算子です。
    # ラムダとはproc.newメソッドのようにブロックを変数に代入をすることが出来るprocクラスのオブジェクトです。
    #引数を受け取るブロック変数をXとした場合は、
    # ->  (x){

    # (やりたい処理)

    # }

    # デフォルト値を与えることも可能
# --------------------------------   
# 2.6.3 :001 > test = -> (x) {
# 2.6.3 :002 >      p x
# 2.6.3 :003?>   }
  # = > #<Proc:0x0000555b4d7f3070@(irb):1 (lambda)> 
# 2.6.3 :004 > test.call(1)
# 1
  # => 1 
# 2.6.3 :005 > test = -> (x = 0) {p x}
  # => #<Proc:0x0000555b4d89b018@(irb):5 (lambda)> 
# 2.6.3 :006 > test.call()
# 0
  # => 0 
# --------------------------------
# default_scope -> { order(created_at: :desc) }
  # 作成時刻の降順に並び替えるらしい
    # 変数はどうかわからないが
      # 処理は{ order(created_at: :desc) }らしい
        # order() 
          # モデル.order(引数..)
          # 取得したレコードを特定のキーで並び替える
        # DESC	大きい方から小さい方に並ぶ(降順)
  validates :user_id, presence: true
  # user_idの存在性を検証
  validates :content, presence: true, length: { maximum: 140 }
  # マイクロポストの内容の存在性が有り、最大長が140文字以内に検証する
end
```
###db/migrate/[timestamp]_create_microposts.rb
```rb
class CreateMicroposts < ActiveRecord::Migration[6.0]
  def change
    create_table :microposts do |t|
    # create_table :micropostsから一つずつ取り出す

      t.text :content
      t.references :user, null: false, foreign_key: true

      t.timestamps
    end
    add_index :microposts, [:user_id, :created_at]
    # マイクロポストに新しく属性を追加する
  end
end
```
マイクロポストの設定の追加 属性を追加したので```rails db:migrate```を行う。

###test/models/micropost_test.rb
```rb
require 'test_helper'

class MicropostTest < ActiveSupport::TestCase
  
  def setup
    @user = users(:michael)
    # このコードは慣習的に正しくない
    @micropost = @user.microposts.build(content: "Lorem ipsum")
  end

  test "should be valid" do
    assert @micropost.valid?
    # マイクロポスtのインスタンス変数は有効か？
  end

  test "user id should be present" do
    @micropost.user_id = nil
    # マイクロポストのuser_idが空にする
    assert_not @micropost.valid?
    # 無効か確認
  end
  
  test "content should be present" do
  # マイクロポストの内容を検証する
    @micropost.content = "   "
    assert_not @micropost.valid?
  end

  test "content should be at most 140 characters" do
  # マイクロポストの文字数制限を検証する
    @micropost.content = "a" * 141
    assert_not @micropost.valid?
  end

  test "order should be most recent first" do
    assert_equal microposts(:most_recent), Micropost.first
    # 最近と最初のマイクロポストは同じか検証
  end
end
```
```
rails test:models
```
###app/models/user.rb
```rb
class User < ApplicationRecord
# 継承させる
  has_many :microposts, dependent: :destroy
  # ユーザーを消すとそのマイクロポストも削除されるのかな？
    # has_many 
      # 相手のモデルとの「1対多」のつながりを表す
      # 多くの場合belongs_toの反対側で使われます
    # dependent: :destroy
      # 親モデルを削除する際に、その親モデルに紐づく「子モデル」も一緒に削除できる
  attr_accessor :remember_token, :activation_token, :reset_token
  before_save   :downcase_email
  before_create :create_activation_digest
  validates :name,  presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false } 
  has_secure_password
  validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
  def User.digest(string)
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                  BCrypt::Engine.cost
    # コストパラメータはテストでは最小にする
    BCrypt::Password.create(string, cost: cost)
  end
  
  # ランダムなトークンを返す
  def User.new_token
    SecureRandom.urlsafe_base64
  end
  
  # 永続セッションのためにユーザーをデータベースに記憶する
  def remember
    self.remember_token = User.new_token
    update_attribute(:remember_digest, User.digest(remember_token))
  end
  
  # トークンがダイジェストと一致したらtrueを返す
  def authenticated?(attribute, token)
    digest = send("#{attribute}_digest")
    return false if digest.nil?
    BCrypt::Password.new(digest).is_password?(token)
  end
  
  # ユーザーのログイン情報を破棄する
  def forget
    update_attribute(:remember_digest, nil)
  end
  
  def activate
  # # アカウントを有効にする
    update_attribute(:activated,    true)
    update_attribute(:activated_at, Time.zone.now)
  end

  # 有効化用のメールを送信する
  def send_activation_email
    UserMailer.account_activation(self).deliver_now
  end
  
  # パスワード再設定の属性を設定する
  def create_reset_digest
    self.reset_token = User.new_token
    update_attribute(:reset_digest,  User.digest(reset_token))
    update_attribute(:reset_sent_at, Time.zone.now)
  end

  # パスワード再設定のメールを送信する
  def send_password_reset_email
    UserMailer.password_reset(self).deliver_now
  end
  
  # パスワード再設定の期限が切れている場合はtrueを返す
  def password_reset_expired?
    reset_sent_at < 2.hours.ago
  end
  
  private

    # メールアドレスをすべて小文字にする
    def downcase_email
      self.email = email.downcase
    end

    # 有効化トークンとダイジェストを作成および代入する
    def create_activation_digest
      self.activation_token  = User.new_token
      self.activation_digest = User.digest(activation_token)
    end
end
```
###test/fixtures/microposts.yml
```yml
orange:
  content: "I just ate an orange!"
  created_at: <%= 10.minutes.ago %>
  user: michael

tau_manifesto:
  content: "Check out the @tauday site by @mhartl: https://tauday.com"
  created_at: <%= 3.years.ago %>
  user: michael

cat_video:
  content: "Sad cats are sad: https://youtu.be/PKffm2uI4dk"
  created_at: <%= 2.hours.ago %>
  user: michael

most_recent:
  content: "Writing a short test"
  created_at: <%= Time.zone.now %>
  user: michael
```
テストユーザーを設定する

###テストをする
```
ubuntu:~/environment/my_app (user-microposts) $ rails test test/models/micropost_test.rb
Running via Spring preloader in process 6654
Run options: --seed 45896

# Running:

F

Failure:
MicropostTest#test_order_should_be_most_recent_first [/home/ubuntu/environment/my_app/test/models/micropost_test.rb:31]:
--- expected
+++ actual
@@ -1 +1 @@
-#<Micropost id: 941832919, content: "Writing a short test", user_id: 762146111, created_at: "2022-01-23 03:21:13", updated_at: "2022-01-23 03:21:13">
+#<Micropost id: 12348100, content: "Sad cats are sad: https://youtu.be/PKffm2uI4dk", user_id: 762146111, created_at: "2022-01-23 01:21:13", updated_at: "2022-01-23 03:21:13">



rails test test/models/micropost_test.rb:30

....

Finished in 0.530364s, 9.4275 runs/s, 9.4275 assertions/s.
5 runs, 5 assertions, 1 failures, 0 errors, 0 skips
```
```rb
 test "order should be most recent first" do
    assert_equal microposts(:most_recent), Micropost.first
  end
```
ここで引っ掛かっているらしい。
多分マイクロポストの内容があっていないようだ。

### テストをする　マイクロポストの最初と最近
```
ubuntu:~/environment/my_app (user-microposts) $ rails tRunning via Spring preloader in process 9070
Run options: --seed 52634

# Running:

.......................................

Finished in 4.438422s, 8.7869 runs/s, 41.6815 assertions/s.
39 runs, 185 assertions, 0 failures, 0 errors, 0 skips
```
さっきマイクロポストが降順にしたからテストが通ったのだろう。
###test/models/user_test.rb
```rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com",
                     password: "foobar", password_confirmation: "foobar")
  end

  test "should be valid" do
    assert @user.valid?
  end
  
  test "name should be present" do
    @user.name = ""
    assert_not @user.valid?
  end
  
  test "email should be present" do
    @user.email = "     "
    assert_not @user.valid?
  end
  
  test "name should not be too long" do
    @user.name = "a" * 51
    assert_not @user.valid?
  end

  test "email should not be too long" do
    @user.email = "a" * 244 + "@example.com"
    assert_not @user.valid?
  end
  
   test "email validation should accept valid addresses" do
    valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org
                         first.last@foo.jp alice+bob@baz.cn]
    valid_addresses.each do |valid_address|
      @user.email = valid_address
      assert @user.valid?, "#{valid_address.inspect} should be valid"
    end
  end
  
  test "email validation should reject invalid addresses" do
    invalid_addresses = %w[user@example,com user_at_foo.org user.name@example.
                           foo@bar_baz.com foo@bar+baz.com]
    invalid_addresses.each do |invalid_address|
      @user.email = invalid_address
      assert_not @user.valid?, "#{invalid_address.inspect} should be invalid"
    end
  end
  
  test "email addresses should be unique" do
    duplicate_user = @user.dup
    duplicate_user.email = @user.email.upcase
    @user.save
    assert_not duplicate_user.valid?
  end
  
  test "password should be present (nonblank)" do
    @user.password = @user.password_confirmation = " " * 6
    assert_not @user.valid?
  end

  test "password should have a minimum length" do
    @user.password = @user.password_confirmation = "a" * 5
    assert_not @user.valid?
  end
  
  test "authenticated? should return false for a user with nil digest" do
    assert_not @user.authenticated?(:remember, '')
  end
  
  test "associated microposts should be destroyed" do
    @user.save
    # dbに保存
    @user.microposts.create!(content: "Lorem ipsum")
    # マイクロポストを作成する。
    # create!
      # 失敗するとエラー画面が表示されるらしい。
    assert_difference 'Micropost.count', -1 do
    # マイクロポストの数が一つ減っているか？
      @user.destroy
      # ユーザーを削除
    end
  end
end
```
###テストをする 　ユーザーが削除されたらマクロポストも削除されるか？
```
ubuntu:~/environment/my_app (user-microposts) $ rails t
Running via Spring preloader in process 3785
Run options: --seed 54248

# Running:

........................................

Finished in 5.028572s, 7.9545 runs/s, 36.9886 assertions/s.
40 runs, 186 assertions, 0 failures, 0 errors, 0 skips
```