Railsチュートリアル11章 アカウント有効化

Railsチュートリアル11章について大事だと思ったことメモっていきます。

テストコードはRspecで書いてます。

 

アカウントの有効化とは・・・

ユーザーを新規登録する際にメールを送って、メール内に貼ってあるリンクをクリックすることで、初めてログインできるようになる。

 

全体の流れ

ユーザーがsave出来たら、before_createでactivation_tokenを作り、それをdigest化してハッシュにしたactivation_digestを作る(self.activation_digestとなっているのでuserのカラム内に入る)。そしてuserコントローラー内でメールを送る。この段階でuserはcreateされている。このメール内のedit_pathに行くとauthenticatedで、先ほどdigest化したやつとactivation_tokenが合っているか確かめる。合っていたらactivationコントローラー内のeditアクションでactivatedをtrueにする。セッションコントローラーでactivatedがtrueであればログインできる。falseであればログインできないように記述する。これによって初めてログインできるようになる。

 

テストコード(Rspec

 

まずはmailerのテスト

これはmailer作成時にある程度できていたので変更した点を修正するだけで助かる

spec/mailer/user_mailer_spec.rb

require "rails_helper"

RSpec.describe UserMailer, type: :mailer do
                 typeはmailerになっている。
describe "account_activation" do
let(:mail) { UserMailer.account_activation(@user) }
mailに関しては@userのようなfactorybotは全く関係ないのでletを使うことにした。
 
before do
@user = FactoryBot.create(:user)
# mail = UserMailer.account_activation(@user)
end

it "renders the headers" do
expect(mail.subject).to eq("Account activation")      " "の中身やemailを変えるくらいだ
expect(mail.to).to eq([@user.email])
expect(mail.from).to eq(["noreply@example.com"])
end

it "renders the body" do
expect(mail.body.encoded).to match("Welcome to the Sample App! Click on the link below to activate your account")
expect(mail.body.encoded).to match(@user.name)
end
end

end

 

続いてアカウント有効化についてのテスト

spec/factories/user.rb

FactoryBot.define do
factory :user do
name { Faker::Name.name }
email { Faker::Internet.free_email }
password { '1a' + Faker::Internet.password(min_length: 4)}
password_confirmation { password }
# 下の二つは後で改良
activated {true}
activated_at {Time.zone.now}
end

trait :admin do
admin { true }
end

trait :not_activation do ここ!!
activated {false}
activated_at {nil}
end

end

spec/system/users_spec.rb

RSpec.describe "アカウント有効化", type: :system do

before do
@user = FactoryBot.create(:user,:not_activation)
                       ここ!! factorybotでactivated:false
という特性を追加
end

it "activation_tokenが正しくない時" do
 
visit edit_account_activation_path("invalid",email:@user.email)
expect(current_path).to eq(root_path)
expect(page).to have_content("Invalid activation link")
 
expect(page).to have_link href: login_path
end

it "emailが正しくない時" do
 
visit edit_account_activation_path("invalid",email:"111@111.com")
expect(current_path).to eq(root_path)
expect(page).to have_content("Invalid activation link")
 
expect(page).to have_link href: login_path
end


it "valid signup information with account activation" do
 
 
visit edit_account_activation_path(@user.activation_token,email:@user.email)
expect(current_path).to eq(user_path(@user))
expect(page).to have_content("Account activated!")
find(".dropdown-toggle").click
 
expect(page).to have_link href: logout_path
 
system specに関してはログインしているかどうかをsesssion[user_id]を使ったりして判断できない
     そういうのはrequest specで。systemに関しては目に見えるとこで流れを追ってテストしていく感じだと思う。
     今回だとアカウント有効化されたらshowページに行って、Account activated!という文字(flash)
が表示されていてログアウトリンクがあるということで、ログインしていることを伝えている。

end
end

 

 

 

Railsチュートリアル10章 

Railsチュートリアル10章について大事だと思ったことをメモっときます。

テストコードはRspecを使っています。

 

フレンドリーフォワーティング

ログイン前にそのページに行こうとしていたら、ログインした後は行こうとしたページになっていること。

Sessionを使ってurlを保存してあげる。

ログインする前にurlをsessionに保存(ログイン前、ページに行こうとした時)

ログインした後にそのurlにリダイレクト。行こうとしていたページがない場合はそのまま指定されたページ(デフォルト)。デフォルトのページは引数で渡されている。

sessions_helper.rb


# 記憶したURL(もしくはデフォルト値)にリダイレクト
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end

# アクセスしようとしたURLを覚えておく こっちが先に行われる!!
def store_location
session[:forwarding_url] = request.original_url if request.get?
end

url保存はusersコントローラーのbeforeアクション

def logged_in_user
unless logged_in?
store_location ここ!!
flash[:danger] = "Please log in."
redirect_to login_url
end
end

保存されたurlに行くのはsessionsコントローラーのcreateアクション(ログインする時)

def create
user = User.find_by(email: params[:session][:email].downcase)
if user&.authenticate(params[:session][:password])
# 元々はこう user && user.authenticate(params[:session][:password])
# このauthenticateはhas_secure_passwordが持つ特性なので定義しなくても使える。
# 一方remember_tokenとかはhas_secure_passwordとは関係ないのでauthenticateメソッドを定義する必要がある
log_in user
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
redirect_back_or user ここ!!
           defaultがuserにあたる。 つまりはuser_path showにあたる。
 
 
else
 
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end

---------------------------------------------------------------------------------------

pagination ページ分割

gemを入れる。

gem 'will_paginate', '3.1.8'
gem 'bootstrap-will_paginate', '1.0.0' これはbootstrapのcssに対応するようにしている

 

ページ分割にはwill_paginateを使う。

usersビューのコードの中から@usersを自動で見つけていき他のページにアクセスするページネーションリンクを作成。

<%= will_paginate %> ここ!!
これを書くだけでページネーションリンク
1 2 3 NEXT のようなリンクを作れる。デフォルトで1ページに30こ

<ul class="users">
<% @users.each do |user| %>
<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
</li>
<% end %>
</ul>

<%= will_paginate %> ここ!!
2つ使っているのは上と下にそれぞれ置きたいから。1つでも問題ない。

 

userコントローラー

def index
@users = User.paginate(page: params[:page])
end

 

リファクタリング 上の記述をリファクタリングします。

users/index.html.erb

<% provide(:title, 'All users') %>
<h1>All users</h1>

<%= will_paginate %>

<ul class="users">
<%= render @users %> ここ!!
こう書くことでまず_user.html.erbを呼び出す。
    そして@usersに含まれているやつを1つ1つ呼び出す。
    つまりeachなしでもそれぞれ呼び出すことができる。
</ul>

<%= will_paginate %>

users/_user.html.erb

<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</li>

 

---------------------------------------------------------------------------------------

admin 管理ユーザーになる

まずはmigration

class AddAdminToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :admin, :boolean, default: false
# これは無くてもadminがnilになるのでいいらしい。
# ただ見た人にわかりやすくしている
end
end

このmigrationでadminかどうかを調べるadmin?メソッドも使えるようになる

 

---------------------------------------------------------------------------------------

ユーザーを一気に大量に作る方法

db/seedsに書く。

# メインのサンプルユーザーを1人作成する
User.create!(name: "Example User",
email: "example@railstutorial.org",
password: "foobar",
password_confirmation: "foobar",
admin: true)

# 追加のユーザーをまとめて生成する ここ!!
99.times do |n|
name = Faker::Name.name
email = "example-#{n+1}@railstutorial.org"
password = "password"
User.create!(name: name,
email: email,
password: password,
password_confirmation: password)
end

 

ちなみにテストコードでユーザーを大量に追加する方法は

RSpec.describe "Index 大量のuser", type: :system do
before do
@user = FactoryBot.create(:user)
@other_user= FactoryBot.create(:user)
@users=FactoryBot.create_list(:user, 100) ここ!! create_listでユーザーを大量に作成
                      今回だと100
@users=は別に必要ないと思う。
end

 

---------------------------------------------------------------------------------------

テストコード

テストコードはsystem,requestそれぞれに書いたので順番通りになってないです。

require 'rails_helper'
 
RSpec.describe "Users", type: :system do
before do
@user = FactoryBot.create(:user)
@other_user= FactoryBot.create(:user)
 
end
it "unsuccessful edit" do
log_in(@user)
visit edit_user_path(@user)
fill_in 'Name', with:"AAA"
fill_in 'Email', with:"aaa@111.com"
fill_in 'Password', with: "abcdef"
fill_in 'Password confirmation', with: "fbaxfe"
find('input[name="commit"]').click
expect(has_css?('.alert-danger')).to be_truthy
 
end

it "successful edit" do
log_in(@user)
visit edit_user_path(@user)
fill_in 'Name', with:"AAA"
fill_in 'Email', with:"aaa@111.com"
fill_in 'Password', with: "abcdef"
fill_in 'Password confirmation', with: "abcdef"
find('input[name="commit"]').click
expect(current_path).to eq(user_path(@user))
expect(page).to have_content'Profile updated'

@user.reload
expect(@user.name).to eq("AAA")
expect(@user.email).to eq("aaa@111.com")

end

it "should redirect edit when not logged in" do
visit edit_user_path(@user)
expect(current_path).to eq(login_path)
end

# ログインしていないupdateのテストはrequest specで書く(下)
it 'should redirect edit when logged in as wrong user' do
log_in(@user)
visit edit_user_path(@other_user)
expect(current_path).to eq(root_path)


end

it "successful edit with friendly forwarding" do

visit edit_user_path(@user)
log_in(@user)
expect(current_path).to eq(edit_user_path(@user))
fill_in 'Name', with:"BBB"
fill_in 'Email', with:"abc@111.com"
find('input[name="commit"]').click
expect(current_path).to eq(user_path(@user))
expect(page).to have_content'Profile updated'
end

it "should redirect index when not logged in" do
visit users_path
expect(current_path).to eq(login_path)
end


end


RSpec.describe "Index 大量のuser", type: :system do
before do
@user = FactoryBot.create(:user)
@other_user= FactoryBot.create(:user)
@users=FactoryBot.create_list(:user, 100)
end

 
it 'index including pagination' do
log_in(@user)
visit users_path
User.paginate(page: 1).each do |user|    ページネーションはこうやってやる
expect(page).to have_link href: user_path(user)
expect(page).to have_content(user.name)
end do~endで書かれてる
end


end






RSpec.describe "Users", type: :request do
before do
@user = FactoryBot.create(:user)
@other_user= FactoryBot.create(:user)
end

it 'should redirect update when not logged in' do
patch user_path(@user), params: { user: { name: @user.name,
email: @user.email } }
expect(response).to redirect_to login_path
end

it "should redirect update when logged in as wrong user" do
log_in_as(@other_user)
patch user_path(@user), params: { user: { name: @user.name,
email: @user.email } }
expect(response).to redirect_to root_path


end

it 'should not allow the admin attribute to be edited via the web' do
log_in_as(@other_user)
patch user_path(@other_user), params: {
user: { password: "password",
password_confirmation: "password",
admin: true } }
expect(@other_user.admin?).to be_falsy
 

end


end

RSpec.describe "Admin", type: :request do
before do
@user = FactoryBot.create(:user,:admin)
@other_user= FactoryBot.create(:user)
end

it "should redirect destroy when not logged in" do
 
expect do
delete user_path(@other_user)
end.to change { User.count }.by(0)
expect(response).to redirect_to login_url
end

it 'should redirect destroy when logged in as a non-admin' do
log_in_as(@other_user)
 
expect do              下に説明書いた
delete user_path(@user)
end.to change { User.count }.by(0)
 
expect(response).to redirect_to root_path
end


it "index as admin including pagination and delete links" do
log_in_as(@user)
 
expect do ここ!! request specでも expect do~ end.to~は使える。
          今回はdelete_pathに行くとUserのカウントが1減るよう書いてる
delete user_path(@other_user)
end.to change { User.count }.by(-1)
 
expect(response).to redirect_to users_path
end



end

 




 

以上で10章終わりです!

Railsチュートリアル9章 クッキー(remember_me)

Railsチュートリアル9章で大事なとこをメモっていきます。

テストコードはRspecを使っています。

 

ランダムトークン生成

user.rb

def User.new_token
SecureRandom.urlsafe_base64
ここ!!これで22文字のランダムな文字列を作っている。
end

user.rb

def remember
self.remember_token = User.new_token
先ほど生成したやつをトークンとしている
update_attribute(:remember_digest, User.digest(remember_token))
remember_tokenをdigestすることでハッシュ化している。ハッシュ化したremember_tokenを
 regember_digestカラムに入れている
end

---------------------------------------------------------------------------------------

クッキーにuser_id, remember_tokenを入れる

sessions_helper.rb

def remember(user)
user.remember *上のremember(userモデル内)
cookies.permanent.signed[:user_id] = user.id
     permanentで永続化している。
     signedは署名付きクッキー。cookiesをブラウザに保存する前に安全に暗号化している。セキュリティー対策
   idの取り出し方:cookies.signed[:user_id]で自動で暗号が解除できる
cookies.permanent[:remember_token] = user.remember_token
end

 

---------------------------------------------------------------------------------------

authenticateメソッド

def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
newここ!
          ハッシュ化されたremember_digestとハッシュ化されていないremember_tokenが合致するかを
          行っている
end

 

ちなみに前章ではハッシュ化するメソッドを取り扱った。

digestメソッドである。

def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
        ここに注目!!crateである。

newとcreateの違いがあることに気がついた。

 

---------------------------------------------------------------------------------------

モデルとヘルパーについて

モデルに書いたり、ヘルパーに書いたり行ったり来たりしている。なぜだろうか。

 

UserにまつわるメソッドはUserモデルに書かなければならない。

Sessionコントローラーで使うメソッドはSession関連に書かなければならない。

Sessionモデルは存在しない。Sessionヘルパーに書く。UserモデルはSessionじゃないので書くのはおかしい。

だからモデルとヘルパーそれぞれに書かないといけない。

 

---------------------------------------------------------------------------------------

テストコード

sessionやcookiesはsystem specでの書き方がわからなかったので(目に見えないから)そのため今回はrequest spechelper specも使用した。

request spec: コントローラーにまつわるテスト

helper spec: ヘルパーにまつわるテスト

 

まずはモデルテスト1つ追加

user_spec.rb

it "authenticated? should return false for a user with nil digest" do
expect(@user.authenticated?('')).to be_falsy 
                      ここfalthyじゃないので注意ね。trueはtruthyだけど。
end

 

追加!!複数のタブでログアウト

ログインしていないとログアウトリンクが見当たらないためsystemでは書けなかった。

visitはできない。destroyはビューないため。

 

サポートモジュール追加した。ログインしているかどうか判断する。

is_login?メソッド。ログインしているかどうかを判断するメソッドはヘルパーのメソッドであったため、サポートモジュールに入れて使えるようにする。

 

module LoggedIn
def is_login?
!session[:user_id].nil?
end

sessions_spec.rb

RSpec.describe "Sessions", type: :request do
                    ここ!
before do
@user = FactoryBot.create(:user)
end
# let(:user) { FactoryBot.create(:user) }

it '二つのタブでログアウト' do
delete logout_path
expect(response).to redirect_to root_path
expect(is_login?).to be_falsy
     ここね。

end

 

request spec と helper spec

 

サポートモジュール(ログイン用)

module LoggedIn
ここからはsystem用
def log_in(user)
visit login_path
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
check 'Remember me on this compute'
find('input[name="commit"]').click
expect(current_path).to eq(user_path(user))
 
end

 
 
ここからrequest用
# request
def log_in_as(user, remember:'1')
post login_path, params:{session:
{email: user.email,password: user.password,remember_me: remember}
}
end

end

 

system/sessions_spec.rb

requestやhelperも system内に書いちゃっておk

RSpec.describe "Sessions", type: :request do
                   ここ!!
before do
@user = FactoryBot.create(:user)
end
# let(:user) { FactoryBot.create(:user) }
記事にはlet使われてるけどbeforeで全然問題ない

it 'login with remembering' do
log_in_as(@user, remember:'1') サポートモジュールで定義したやつ使う
expect(cookies[:remember_token]).not_to eq nil
end

it "login without remembering" do
log_in_as(@user, remember:'0') こっちでは0にしてチェックを入れないようにしている
expect(cookies[:remember_token]).to eq nil
end

end

RSpec.describe SessionsHelper, type: :helper do
       これ文字列じゃないので注意   ここでヘルパーテストするよ〜
# SessionsHelperについてテストしますよ typeはhelperで
 SessionsHelperを入れてヘルパーテストをする理由は
 current_userを使いたかったから。でもこれもサポートモジュールに入れればヘルパーテストじゃなくてもいけるかと思う。
before do
@user = FactoryBot.create(:user)
remember(@user)
end
 

it 'current_user returns right user when session is nil' do
expect(current_user).to eq @user
expect(is_login?).to be_truthy
end

it "current_user returns nil when remember digest is wrong" do
@user.update_attribute(:remember_digest, User.digest(User.new_token))
expect(current_user).not_to eq @user
expect(is_login?).to be_falsy
end

end

 

以上で9章終わりです!

Railsチュートリアル8章 セッション

Railsチュートリアル8章について大事なとこメモっときます!

テストコードはRspecで書いてます。

 

Sessionとは・・・

ログイン情報を保持する。

sessionはブラウザを閉じると自動で終了する。

Google Chromeの場合は、ブラウザを閉じてもログイン情報保持されたが、これはあくまでブラウザ依存。他のブラウザでは保持しない場合がある。その為次にクッキーを設定する必要がある。(これは次章)

---------------------------------------------------------------------------------------

 

flashメッセージ

エラーメッセージはActive Recordによって自動生成されていたが(User新規登録時の情報が正しくない時)、セッションはActive Recordではないのでエラーメッセージを表示しない。

そこでflashでエラーを表示する。

 

flashを使うにおいて renderとredirectの違い

ーーーーーーーーーーーーー

・renderの場合

flash[:danger]

render ___

このままではだめ。他のページに行ってもエラー文(flash)が出る。これはrenderされているから。

flash.now[:danger]に変更する必要がある。

こうするとその後リクエストが発生した時にエラー文は消える

 

・一方redirectの場合は

flash[:success]

redirect to _____

リダイレクトされるのでこのままでいい。

---------------------------------------------------------------------------------------

 

form_with セッションの場合

今まではモデルで使ってきた。

例)users/new

<%= form_with(model: @user, local: true) do |f| %>

 

sessionにはモデルがない。

しかしurlscopeを置けば問題なく使える

<%= form_with(url: login_path, scope: :session, local: true) do |f| %>

 

--------------------------------------------------------------------------------------

digest    

この章では出てきたが使わなかった。しかし次章以降で大事になるので。

user.rb

def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost) ここが大事!!
 
BCrypt::Password ハッシュ化
# 渡された引数をハッシュにしている(string)
# このbcryptというのはhas_secure_passwordを使うために入れたgemである。
# よってやってること自体は一緒
end

          

 -------------------------------------------------------------------------------------

テストコード(Rspec)

spec/system/sessions_spec.rb

require 'rails_helper'

RSpec.describe "Sessions", type: :system do
before do
@user = FactoryBot.create(:user)
end

it 'should get new' do
visit login_path
expect(current_path).to eq(login_path)
end

it "login with invalid information" do
visit login_path
fill_in 'Email', with: ""
fill_in 'Password', with: ""
 
find('input[name="commit"]').click
 
expect(page).to have_content("Invalid email/password combination")
visit help_path
expect(page).not_to have_content("Invalid email/password combination")
end

it "login with valid information" do
visit login_path
fill_in 'Email', with: @user.email
fill_in 'Password', with: @user.password
find('input[name="commit"]').click
expect(current_path).to eq(user_path(@user))
find(".dropdown-toggle").click
# ドロップダウンをクリック クラス名
expect(page).to have_link href: logout_path
expect(page).to have_link href: user_path(@user)
expect(page).not_to have_link href: login_path
end

it "login with valid email/invalid password" do
visit login_path
fill_in 'Email', with: @user.email
fill_in 'Password', with: "abcdef"
 
find('input[name="commit"]').click
 
expect(page).to have_content("Invalid email/password combination")
visit help_path
expect(page).not_to have_content("Invalid email/password combination")
end

it "login with valid information followed by logout" do
visit login_path
fill_in 'Email', with: @user.email
fill_in 'Password', with: @user.password
find('input[name="commit"]').click
expect(current_path).to eq(user_path(@user))
find(".dropdown-toggle").click
 
expect(page).to have_link href: logout_path
click_link 'Log out'
# リンクをクリックする
expect(current_path).to eq(root_path)
expect(page).to have_link href: login_path

 
end
end

 

   新規登録時にログインしている(追加)

spec/system/users_spec.rb

it "valid signup information" do
visit signup_path
fill_in 'Name', with:"111"
fill_in 'Email', with:"111@111.com"
fill_in 'Password', with: "101010"
fill_in 'Confirmation', with: "101010"
expect do
find('input[name="commit"]').click
end.to change { User.count }.by(1)

expect(has_css?('.user_info')).to be_truthy
# showページにあるCSS これなくてもいいよ

expect(page).to have_content'Welcome to the Sample App!'
ここから追加!!
# ログインしているかどうかは
# ログアウト等があることで証明できると思う
find(".dropdown-toggle").click
# ドロップダウンをクリック クラス名
expect(page).to have_link href: logout_path
# expect(page).to have_link href: user_path(@user) これはだめか
expect(page).not_to have_link href: login_path

 

以上で8章を終わります!

Railsチュートリアル7章

Railsチュートリアル7章大事なところメモっときます

テストコードはRspecで書いています。

 

画像   Gravatar

Gravatarは無料のサービスで、プロフィール写真をアップロードして、指定したメールアドレスと関連付けれる。

users/show.html.erb

<% provide(:title, @user.name) %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<h1>
<%= gravatar_for @user %>
ここ!! これでhelperメソッドを呼び出しているので、helperに行く。
<%= @user.name %>
</h1>
</section>
</aside>
</div>

users_helper.rb

module UsersHelper
# 引数で与えられたユーザーのGravatar画像を返す
def gravatar_for(user,size: 80 )
 
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
# emailをハッシュ化している
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
これが画像
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end

 

そもそもhelperとは・・・

モデルのメソッドと何が違うの??

 

モデルのメソッドはコントローラーで使う感じ。

helperは全ビューで共通なので、ビューでも使えるという感じ。

実際に今回はshowのビューで使っている。

今のところはこういう理解です。

---------------------------------------------------------------------------------------

plurialize

勝手に複数の時にsをつけてくれたりする

例)

>> helper.pluralize(1, "error")

=> "1 error"

>> helper.pluralize(5, "error")

=> "5 errors"

 

---------------------------------------------------------------------------------------

 

flash

ユーザー登録完了後にメッセージを表示する

 

コントローラー

def create
@user = User.new(user_params)
if @user.save
flash[:success] = "Welcome to the Sample App!"
ここ!!
redirect_to @user
else
render 'new'
end
end

 

ビュー

application.html.erb

<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= render 'layouts/rails_default' %>
<%= render 'layouts/shim' %>
</head>

<body>
<%= render 'layouts/header' %>
<div class="container">
ここ!!
<% flash.each do |message_type, message| %>
コントローラーで引数渡されてる。message_typeがsucess, messageが"Welcome to the Sample App!"
<%= content_tag(:div, message, class: "alert alert-#{message_type}") %>
<% end %>
!!
 
** 元々はこの形
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
                          ↑ここまでクラス
<% end %>
**
 
<%= yield %>
<%= render 'layouts/footer' %>
<%= debug(params) if Rails.env.development? %>
</div>
</body>
</html>

 

---------------------------------------------------------------------------------------

 

テストコード(Rspec)

 

require 'rails_helper'


RSpec.describe "Users", type: :system do

it 'should get new' do
visit signup_path
expect(current_path).to eq (signup_path)
end
本章はここからーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
context 'Signup' do
it "invalid signup information" do
visit signup_path
fill_in 'Name', with:""
fill_in 'Email', with:"111@111.com"
fill_in 'Password', with: "101010"
fill_in 'Confirmation', with: "101010"
expect do
find('input[name="commit"]').click
end.to change { User.count }.by(0)

expect(page).to have_content('Sign up')
# これは違う
# expect(current_path).to eq(new_user_path)
 
render'new'はnewアクションを呼び出しているわけではない。
表示されるviewだけを切り替えている。
そのためrender'new'後のpathはnew_pathというわけではない。
expect(has_css?('.alert-danger')).to be_truthy
 
end

it "valid signup information" do
visit signup_path
fill_in 'Name', with:"111"
fill_in 'Email', with:"111@111.com"
fill_in 'Password', with: "101010"
fill_in 'Confirmation', with: "101010"
expect do
find('input[name="commit"]').click
end.to change { User.count }.by(1)

expect(has_css?('.user_info')).to be_truthy
# showページにあるCSS これなくてもいいよ

expect(page).to have_content'Welcome to the Sample App!'
application.html.erbにあるからわかりずらいけどflashの中身
 

 
end

end

 



end

 

以上7章は終わりです!

Railsチュートリアル6章

Railsチュートリアル6章について大事だと思ったことをまとめます!

テストコードはRspecを利用して書いております。

 

・特定の属性のみ更新したい場合はupdate_attributeを使う

 user = User.new(name: "The Dude", email: "dude@abides.org")

user
.update_attribute(:name, "BBB")

-------------------------------------------------------------------------------------- 

テストコード 正しくないことをテストする

 

まずは正しいことをテストする場合

expect(@user).to be_valid

 

次に正しくないことをテストする場合

expect(@user).not_to be_valid

 

---------------------------------------------------------------------------------------

 

データベースのインデックス migrationにadd_index

これは本の索引みたいなもの。情報を調べに行く

索引がなければ最初から最後までみていかなければならないuser.firstからuser.lastまで(full scan)

索引があれば1回の手間で済む。

 
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
t.string :name, null:false
t.string :email, null:false
 

t.timestamps
end
add_index :users, :email, unique: true
ここ!! emailを調べにいける。 unique: trueは別
end
end

 

---------------------------------------------------------------------------------------

メールアドレス 大文字小文字を区別しないようにする

userを保存する前にモデル内のbefore_saveでemailをdowncaseにする!

class User < ApplicationRecord
before_save { self.email = email.downcase }
ここ!!
# before_save { email.downcase! } こっちでもいいよ
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: true
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
end

 

---------------------------------------------------------------------------------------

has_secure_password

 

・ハッシュ化したパスワードをpassword_digestという属性に保存できる。

・passwordとpassword_confirmstionが使えるようになる。

・authenticateメソッドを使えるようになる。

 これはpasswordと、ハッシュ化されたpassword_digestを比較できる。

 

**has_secure_passwordを使うためにはbycryptというgemを導入する必要がある。

gem 'bcrypt', '3.1.13'

 

---------------------------------------------------------------------------------------

テストコード(Rspec使用)

 

require 'rails_helper'

RSpec.describe User, type: :model do
before do
@user = User.new(name: "Example User", email: "user@example.com",password: "foobar", password_confirmation: "foobar")
 
end

it 'should be valid' do
expect(@user).to be_valid
end

it "name should be present" do
@user.name = " "
expect(@user).not_to be_valid
end

it "email should be present" do
@user.email = " "
expect(@user).not_to be_valid
end

it "name should not be too long" do
@user.name = "a" * 51
expect(@user).not_to be_valid
end

it "email should not be too long" do
@user.email = "a" * 244 + "@example.com"
expect(@user).not_to be_valid
end

it "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
expect(@user).to be_valid
# @user.valid?, "#{valid_address.inspect} should be valid"
end
end

it "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 foo@bar..com]
invalid_addresses.each do |invalid_address|
@user.email = invalid_address
expect(@user).not_to be_valid
end
end

it "email addresses should be unique" do
duplicate_user = @user.dup
dupは同じ属性を持つデータを複製するメソッド
# duplicate_user.email = @user.email.upcase
# モデル内のbefore actionでdowncaseにするようにしたので必要なくなった
@user.save
expect(duplicate_user).not_to be_valid
end

it "email addresses should be saved as lower-case" do
mixed_case_email = "Foo@ExAMPle.CoM"
@user.email = mixed_case_email
@user.save
expect(mixed_case_email.downcase).to eq(@user.reload.email)

end


it "password should be present (nonblank)" do
@user.password = @user.password_confirmation = " " * 6
expect(@user).not_to be_valid
end

it "password should have a minimum length" do
@user.password = @user.password_confirmation = "a" * 5
expect(@user).not_to be_valid
end


 
end

 

以上で6章終わりです!

Railsチュートリアル 5章 

Railsチュートリアル5章についてまとめる。

 

Bootstrap

Twitterが作成したフレームワーク

Webデザインとユーザーインターフェイス要素を簡単に導入できるCSSフレームワークである。

 

gemを入れる必要がある。

gem 'bootstrap-sass', '3.4.1'

 

@importを使ってcssにBootstrapを入れ込む。

cssファイル内

@import "bootstrap-sprockets";
@import "bootstrap";

 

Sass

 

cssの上位版?

ネストと変数を使える

 

ネスト

 

.center {

  text-align: center;

}

 

 

.center h1 {

  margin-bottom: 10px;

}

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

 ⏬

 

.center {

  text-align: center;

  h1 {

    margin-bottom: 10px;

  }

}

これがネスト

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

変数

 

h2 {

  .

  .

  .

  color: #777;

}

.

.

.

footer {

  .

  .

  .

  color: #777;

}

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

$light-gray: #777;

これが変数

.

.

.

h2 {

  .

  .

  .

  color: $light-gray;

}

.

.

.

footer {

  .

  .

  .

  color: $light-gray;

}

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

名前付きルート 

 

Rails.application.routes.draw do
root 'static_pages#home'

get '/help' ,to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
上4つに注目
それぞれhelp_pathのように使える!
,忘れないで。
to以下はrootと書き方一緒。コントローラー名#アクション名
resources :users

end

 

テストコード

# 5章
# トップページにリンクがあるかどうか
it "layout links" do
visit root_path
expect(page).to have_link href: root_path, count:2
expect(page).to have_link href: help_path
expect(page).to have_link href: about_path
expect(page).to have_link href: contact_path
expect(page).to have_link href: signup_path

 リンクがあるかどうかは have_link href: パス名を使うことでテストできた。
 
expect(page) to have_link 'Help', href:help_path
こんな風に書くこともできるよ。'Help'はリンクの文字で、href以降はパス名
end