LoginSignup
1
1

More than 3 years have passed since last update.

Rails学習 2日目

Posted at

Ruby on Rails5速習実践ガイド chapter4

4-2-1 データ型

データベースのカラムにはそれぞれデータ型というものが必要になってくる。
データ型というのはその中に入る値を特定の条件付きで指定するものである。

データ型 説明
:boolean 真偽値
:integer 符号付きの整数
:float 浮動小数点数
:string 文字列(短い)
:text 文字列(長い)
:date 日付
:datetime 日時

それぞれのカラムに上記のデータ型を付け加えることで中に入るデータを区別する

4-2-2 NOT NULL制約

カラムは値のない場合NULLとして値を設定しテーブルとして保存するがNOT NULLを使うことによってカラムには必ず何らかの値が入ることを指定することができる。

・NOT NULL制約のかけかた
NOT NULL制約には2種類のかけ方がある。1つ目がテーブルを作成する時に制約をつける方法。2つ目がテーブルを作成し終わってから制約を付け足したい時の制約をつける方法である。

1.テーブルを作成する時に制約をつける方法
テーブルを作成するためのマイグレーションファイルにそのままNOTNULL制約をかけてしまってからdb:migrateしてテーブルを作成する方法

db/migrate/XXXXXXXXXX_create_tasks.rb
class CreateTasks < ActionRecord::Migration[5.2]
 def change
  create_table :tasks do |t|
   t.string :name, null: false
   t.text :description
...

nameの部分は何か値がないと困るのでnameの後ろにnullをつける。
その後ろにnull(空白)でもいいならtrue,空白が嫌(NOTNULL)ならfalseをつける

2.テーブルを作成し終わってから制約を付け足したい時の制約をつける方法

$ bin/rails g migration ChangeTaskNameNotNull

テーブルはもう作ってしまったのでマイグレーションファイルを変更しても意味がない。なので変更用のマイグレーションファイルを作りそこに変更用のコードを書く

db/migrate/XXXXXXXXXXXX_change_tasks_name_not_null.rb
class ChangeTaskNameNotNull < ActionRecord::Migration[5.2]
 def change
  change_column_null :tasks, :name, false
 end
end

できた変更用マイグレーションファイルにchange_column_null(カラムをnullにchangeする)を使ってタスクを変更する。
change_column_null :タスク名, :カラム名, :trueかfalseか(trueはnull、falseはnotnull),

文字列カラムの長さを指定する       (changeメソッド と upメソッドdownメソッド)

文字列の長さを指定するには上記の説明である通り、テーブル作成のマイグレーションファイルに情報を追加するか、情報が決まってしまったテーブルに情報追加のためのマイグレーションファイルを作るかのどちらかである。今回は情報が決まってしまったテーブルに情報追加のためのマイグレーションファイルを作る方法を見てみる。

class ChangeTasksNameLimit30 < ActionRecord::Migration[5.2]
 def up
  change_column :tasks, :name, :string, :limit: 30
 end
 def down
  change_column :tasks, name, :string
 end
end

今回はchangeメソッドの代わりにupメソッドとdownメソッドが書かれているところに注目する。本来changeメソッドは上のupメソッドとdownメソッドを合わせて作られるメソッドである。なぜ今回changeメソッドを二つに分けたかというと、答えは[change_column]にある。change_columnをchangeメソッドで使うと何かあった時に元に戻せなくなるのだ。バージョンを戻す時には上げたバージョン(upやchange)を見ながらそれと逆の操作をしてバージョンを戻す。しかしchangeメソッドだとそれがうまくいかないのである。

4-2-4 ユニークインデックスを作成する

ユニークインデックスも上記のようにテーブル作成のマイグレーションファイルか追加変更用のマイグレーションファイルに書かれる。

class AddNameIndexToTasks < ActiveRecord::Migration[5.2]
 def change
  add_index :task, :name, unique: true
 end
end

ユニークインデックスをつけると値(この場合はname)の重複が無くなる(被らなくなる)

4-3-6 オリジナルの検証コードを書く       (自分でvalidatesを作る)

app/models/task.rb
validate :validate_name_not_including_comma

まず自分で作ったvalidateの名前をvalidateに入れる。

app/models/tasks.rb
private

def validate_name_not_including_comma
  errors.add(:name,'にカンマを含めることはできません') if name&.include?(',')
end

自分の作ったvalidateの内容をprivateメソッドのなか(外部からいじられたらダメなので)で定義。
if name&.include?(',') もしカンマがついた名前があると普通に実行するがカンマがない名前になると結果はnilになりエラーが出てしまう。ぼっち演算子ならnilが出てエラーにならずにnilという言葉だけ出てくる。

4-5-1 セッション

セッションがあることによってどんなページへ何回とんでも自分が操作しているという状態は保たれる(ログイン状態になる)

session[user_id] = @user.id

@user.id = session[user_id]

上がセッションに情報を入れる操作。下がセッションの値を取り出す操作になっている。

4-5-2 Userモデルを作る(password-digest)

password-digestを使うとパスワードが暗号化されパスワード漏洩や不正アクセスの心配が無くなる
password-digestを対応させるにはhas_secure_passwordというコードを書くと使えるようになる。

app/models/user.rb
class User < ApplicationRecord
  has_secure_password
end

モデルにhas_secure_passwordをかく。そうするとpasswordカラムの下にpassword_confimationというカラムができる。これはパスワード確認のために2回入力させるためのやつ。この2つのパスワードがpassword-digestで暗号化された時に一致しているかどうかで判断する。

4-5-8 ログイン情報の取得を簡単にする

User.find_by(id:session[user_id])

今セッションしているidを探すというコードのなのでログインをしていればこのコードでログインしているユーザーを特定できる。
これをApplicationControllerのなかでメソッドとして定義してやるとどこのアクション内でもUser.find_by(id:session[user_id])が働き、ログインしているという情報がついてくる。
なので新しくメソッドを作る

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  helper_method :current_user

 private

 def current_user
   @current_user||=User.find_by(id:session[user_id]) if session[:user_id]
 end
end

「もし@current_userが機能しているなら@current_userを、そうじゃない場合はもしuser_idがセッションしている状態ならそのセッションしているユーザーの情報を探して、それを変数@current_userとする」という動作をcurrent_userメソッドと定義する。このメソッドは外部から操作されてはいけないのでprivateメソッドのなかに入れる

4-5-9 ログアウト機能を実装する

ログイン状態はreset_sessionでログアウト状態になる

app/controllers/session_controller.rb
 def destroy
   reset_session
   redirect_to root_url, notice: 'ログアウトしました'
end

なのでreset_sessionはdestryコントローラーの中に定義する。

4-5-11-1 データベース上でUserとTaskを紐付ける

UserとTaskを紐づける上で重要になってくるのは【1対多】という関係。User一人に対しTaskは複数存在するといった状況のことである。具体的な紐付けについて説明する。

1.まずtaskのユーザー情報のuserカラムがNOTNULLな状態にならなければいけない。

db/migrate/XXXXXXXXXX_AddUserIdToTasks.rb
class AddUserIdToTasks < ActiveRecord::Migration[5.2]
 def up
   execute 'DELETE FROM tasks;'
   add_reference :tasks, user, null: false, index: true
 end

 def down
   remove_reference :tasks, :user, index: true
 end
end

remove_reference:カラムの中の制約を付けたい時にreferenceを使う。
remove_reference :tasks, :user, index: true←このデータを
add_reference :tasks, user, null: false, index: true←userがnull:falseのなるように制約を付け加えた。
execute 'DELETE FROM tasks;'←制約をつける前にuserがnull:falseだったデータがあるかもしれない、もしあったらエラーになる。なのでこのコードを使いテーブルにあるデータを全削除した。

2.1対多の関係を表すhas_many :tasksとbelongs_toを使って関係性を構築する。

app/models/user.rb
 has_many :tasks
end
app/models/task.rb
 belongs_to :user
end

データベース間の関係はモデルが行うのでモデルに記入。
user has many tasks
tasks belongs to user
の関係になるので
userモデルにhas_many :tasks
tasksモデルにbelongs_to :user
を加える。

4-5-11-3 ログインしているユーザーのTaskデータの登録

ログインするためのcreateアクションは以下のようになっている

app/controller/tasks_controller.rb
 def create
   @task = Task.new(task_params)
  ・
  ・
  ・
  ・
  ・
 private

 def task_params
   params.require(:task).permit(:name, :descrition)
 end
end

このままだと@taskで新規タスクは作られるがログイン中のユーザーのタスクだということがわからなくなる。なので上のコードを書き換える

app/controller/tasks_controller.rb
 def create
   @task = current_user.task.new(task_params)
  ・
  ・
  ・
  ・
  ・
 private

 def task_params
   params.require(:task).permit(:name, :descrition)
 end
end

current_userがつくことによって「現在ログイン中の」という意味のtaskになる。
つまり先頭にcurrent_userをつけると何でも「ログイン中の」という意味がついてくる。
例えば
Task.find(params[:id])→指定したidのタスクを取ってくる
current_user.tasks.find(params[:id])→ログイン中の人のタスクの中から指定したタスクを取ってくる。

4-8 scopeを活用する

order(created_at: :desc)などはscopeを使うともっとシンプルな名前に変えることができる。

scope :recent, -> {order(created_at: :desc)}

このコードでorder(created_at: :desc)はrecentに書き換えることができる。

その他勉強になったこと

task.errors.full_messages

taskのエラー情報が表示される

task.persisted?

taskがデータベースへ登録済みかどうか確認できる。

if task.errors.present?
  ul#errors_explanation
   -task.errors.hull_messages.each do |message|
      li= message

errors.present?でエラーがあるかないかを判断する。

if user&.authenticate(session_params[:password])

private
 def session_params
   params.require(:session).permit(:email, :password)
 end

本来はuser(session_params[:password])だがpassword-digestで暗号化した場合は
user&.authenticate(session_params[:password])になる。

if current_user.admin?

adminでユーザー管理権限を持っているかを確認することができる。そこにcurrent_userが加わり、「ログインしている人はそのユーザーの管理権限を持っているのか?」というif文になる。

@task = current_user.task.order(created_at: :desc)

orderは指定した基準で一覧を並び替える操作
今回はcreated_at(作成日時)を基準で並ぶ順番が変わっている

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1