見出し画像

Ruby on Rails5備忘録

勉強しながらメモしたことをそのまま記述しています。

・Ribu on Railsとは
railsはレール。電車の下にあるやつのレールと同じ意味
レールの上に乗っかったruby
Webアプリケーション開発を楽にする道具
Twitterのようなものが作れるらしい
コマンドだけでサクっとWebページ制作に必要なものがドカっと作られ、あとは
ちょこちょこ修正していくだけでオリジナルWebページが作れる

・railsアプリケーションを作成する方法
ターミナルで以下のコマンドを実行する
rails new アプリケーション名

例rails new tweet_app

・サーバーを立ち上げる必要がある
ターミナルで以下のコマンドを実行する
rails server

・トップページを自動生成する
rails generate controller home top

・ページの作成に必要なもの
ビュー view
HTMLファイル
app/views/xxx/xxx.erb

コントローラ controller
ルビー形式
コントローラ内のメソッドをアクションって言う
コントローラを経由してビューにあるデータをブラウザに返す
app/controllers/xxx.rb

ルーティング routing
ビューは先にルーティングを通ってコントローラに渡す
URLとコントローラ名#アクション名を対応させるコマンド
get "URL" => "コントローラー名#アクション名"
ルーティングできないとエラーになる
config/xxx.rb

・Webページをサクっと作るコマンド
rails generate controller コントローラ名 アクション名
※重複したコントローラ名はもう使えない
※重複したアクション名はもう使えない

・VCRを追加する方法
Rで行コピペして最初と最後を変更する
Cでブロックコピペしてメソッド名を変更する
Vはフォルダに新規ファイル追加

・CSSの場所
app/assets/stylesheet

・画像の保存場所
app/public
.jpgとかpngとかおける

画像名の指定
"/hoge.jpg"
"/hoge.png"

・トップページのURLの変更
ルーティングでできる
localhost:3000で表示されるもの
get "/" => "home#top"
左を変えれば右は変えなくてよい

・リンクの指定
ルーティングで作ったやつにする
"/"
"/about"

・コントローラは目的別に作成したほうがよい

・コントローラの作成省略形
rails g controller コントローラ名 アクション名

rails g controller posts index

rails g controller users index

・viewファイル内で変数を定義する
<% %>

<% post1 = "hoge" %>

・erbとは
「Embedded Ruby(埋め込みRuby)」の略

・定義した変数を表示する
<%= %>

<%= post1 %>

・viewファイル内で配列を用意
<%
hoges=[
"huga",
"piyo"
]
%>

※セミコロンはいらない

・each文
<% hoges.each do |hoge| %>
<%= hoge %>
<%end%>

・アクションで変数を定義する
@hoges=[
"huga",
"piyo"
]
※セミコロンはいらない
@をつける理由は、コントローラで定義したものをビューで使いますよのマーク

・データベースにテーブルを作成する
rails g modelコマンドを使う
rails g model Post content:text
postsテーブルを作成する場合はPostと単数形にする
contentはカラム名、textはデータ型
カラムにid,create_at,update_atが自動的に追加される
app/db/migrate/数字の羅列.rbというマイグレーションファイルが作られる
データベースへの変更内容が記載されてる
app/models/モデル名.rb(単数形のファイル名)が作られる
モデル名のクラスがApplicationRecordを継承して定義されている

複数のカラム名とデータを指定する
rails g model User name:string email:string

stringは短い文字列
textは長い文字列

・データベースに変更を反映する
rails db:migrate

rails g modelのあとに実行することで変更してくれる

・rails consoleの使い方
rails console
ターミナルでrails consoleと打つと変数とか作れるようになる
変数は終了するまで使える
終了するにはquitと打つ
終了したら変数は使えない

rails g modelとか実行するときは打たなくていい

・rails console中とそうでないときの違い
rails console中は変数が作れますよー
rails console中でないときはあらかじめ用意されたライブラリが使えますよー

・テーブルに投稿データを保存する
①newメソッドでPostモデルのインスタンスを作成する
②postsテーブルに保存する

・インスタンスを作成する方法
変数 = カラム名(先頭大文字).new(カラム名: 値)
post = Post.new(content: "Rails勉強中!")

・インスタンスをテーブルに保存する方法
変数.save
post.save

保存に成功した場合はtrue
保存に失敗したはfalse

なぜ使えるか?
→ApplicationRecordを継承しているから

・テーブルから1つのデータを取り出す
post=Post.first
これは先頭のものが取れる

とってきたものは、以下のような感じで使える
post.content

なぜ使えるか?
→ApplicationRecordを継承しているから

・テーブルからすべてを取り出す
posts=Post.all

・テーブルからインデックスを使って1つだけを取り出す
post=Post.all[0]

・テーブルからインデックスを使って1つだけを取り出し、表示する
Post.all[0].content

・データベースのデータを表示する
テーブルからすべてを取得するのはコントローラーrb
それを使用するのはビュー

・レイアウトを共通化するには
<%= yield %>を使う

・link_to
htmlに<a>を作成することができる
<%= link_to("About", "/about") %>
第1引数は表示文字列、第2引数はリンク

link_toの第2引数での変数展開はたとえば以下のような感じ
"/posts/#{post.id}"

第3引数をつけると、getだけではなくpostも探してくれるようになる
<%= link_to("削除", "/posts/#{@post.id}/destroy", {method:"post"}) %>

・id,created_at,updated_atカラム
上からの順、作成日時、更新日時

・find_by
テーブルから検索して取得できる
モデル名.find_by(カラム名:値)
post=Post.find_by(id:3) id=3の行を取得する

ちなみに引数は複数指定でき、コンマ,で区切る


・ルートで:idを加えると違うリンクで同じページに飛べる
ただし、:idを使う場合は下のほうに書かないと変なページに飛ばされる
ルートは上から順に探してるから。

・コントローラでURLからidを取得する方法
:id
params[:id]でidを取得できる。

・投稿を保存するまでの流れ
①ルーティングでpostにする
②コントローラーでcreateアクション
③ビューで送信先指定


<%= form_tag("/posts/create") do %>
<textarea></textarea>
<input type="submit" value="投稿">
<% end %>

・他のURLに転送する方法
コントローラでredirect_toを使う
redirect_to("URL")
redirect_to("/posts/index")

・投稿を保存する方法
①投稿がcreateアクションに送信されるようにする
textareaにname属性を追加する(="content")
アクションでparams[:content]
②送信内容を受け取り保存する
アクションで@post = Post.new(content: params[:content])
アクションで@post.save

・並べ替えるには
orderを使う
Post.all.order(created_at: :desc)

・テーブルを編集するには
①データ取得
②上書き
③保存

post = Post.find_by(id:1)
post.save

・投稿を削除するには
①投稿を取得する
②destroyメソッドで削除
※rubyの場合は引数なし関数は()いらない

post = Post.find_by(id:2)
post.destroy

"/posts/#{@post.id}/edit"

・フォームに初期値を用意する
textareaタグで初期値をはさむ
<textarea>初期値として入力したいもの</textarea>

・入力フォームに初期値を入れる
①コントローラで
@post = Post.find_by(id: params[:id])

②ビューで
<textarea><%= @post.content %></textarea>

・編集内容を保存する
①ルートでpost updateを作成する
post "posts/:id/update" => "posts#update"
②コントローラでリダイレクトで投稿一覧に飛ぶ
def update
redirect_to("/posts/index")
end

③ビューでフォームの送信先を指定する
<%= form_tag("/posts/#{@post.id}/update") do %>
hogehoge
<% end %>

・投稿をテーブルに保存する
①URLに含まれたidを用いてデータベースから投稿データを取得する
②フォームから編集内容を受け取り、投稿データを更新する

・削除機能を作成する
post用のlink_toをビューに書く必要がある
ほんで、投稿を取得して
投稿をdestroyで削除

・投稿を制限する
バリデーションする
バリデーションは、データをチェックすること
コントローラ?
app/models/post.rb

validates :検証するカラム名, {検証する内容}

・空のカラムを弾く
validates :content, {presence: true}

・最大文字数を超えるカラムを弾く
validates :content, {length: {maximum: 140}}

・検証する内容を複数指定する
validates :content, {presence: true, length: {maximum: 140}}

・投稿に失敗した文字列を復活させる方法
①コントローラでparams[:content]して直前の投稿内容を取得する

・renderメソッド
別のアクションを経由せずに直接ビューを表示できる
render("posts/edit")
フォルダ名/ファイル名

・エラーメッセージを表示する
実は自動的にエラーメッセージが保存される

post.errors.full_messages => ["Contentを入力してください"]
みたいな感じで

・フラッシュ
ページに一度だけ表示されるメッセージ

・ユーザーを作成できる

・invokeの意味
呼び出す

・バリデーションでemailが重複していないかのコマンド
validates :email, {uniqueness: true}
①ユーザー登録ページの作成
②ユーザーの保存
③サクセス・エラーメッセージの表示

・新規登録は英語でsignupという
/signupでURL

・inputのname属性
入力内容を次のアクションで受け取るために必要

・テーブルのデータを作成したらセーブしないと使えない

・input のvalue属性でrubyの変数名が使いたくなったら
"<%= @user.name %>"とする


①ユーザー編集ページの作成


②変更の保存


③サクセス・エラーメッセージの表示

・すぐ消すコマンド
user = User.new(name: "にんじゃわんこ", email: "wanko@prog-8.com")
user.save

・プロフィール画像を変更できるようにする
テーブルに画像名が保存できる
その保存した画像は、以下にしまわれる
tweet_app/public/user_images/default_user.jpg

・マイグレーションファイルのみを作成する方法
rails g modelコマンドだと、モデルとマイグレーションファイルが作成されてしまう。
rails g migrationで、マイグレーションファイルのみ作成することができる。

rails g migration add_image_name_to_users
そうするとdb/migrateに、AddImageNameToUsersクラスのchangeメソッドのみ記載されたものができあがる

rails g migration add_user_id_to_posts

・既存のテーブルにカラムを追加する方法
add_columnコマンドを利用する
add_column テーブル名 カラム名 データ型
add_column :users, :image_name, :string
add_column :posts, :user_id, :integer
今までは、自動生成されたものをrails g db:migrateで変更すればよかった。
今回は違う。
マイグレーションファイルを編集する必要がある。

終わったら以下のコマンドでテーブルが更新される
rails db:migrate

・初期画像を設定する方法
tweet_app/public/user_images/に初期設定の画像を置く

コントローラファイルで、テーブルに設定する初期ファイルのファイル名を設定することができる
image_name: "default_user.jpg"

・ビューに画像を表示する方法
rubyから変数を持ってきます。
<img src="<%= "/user_images/#{@user.image_name}" %>">
※注意 そのアットマーク、本当に要りますか?
※注意 各ページで@userかuserかきちんと判別すること

・画像選択ボタンを追加する
typeをファイルにします。
<h2>画像</h2>
<input name="image" type="file">

・画像の送信をする場合
特殊なのでform_tagに以下をつける必要がある
multipart: true

<%= form_tag("...", {multipart: true}) do %>

・rubyのコードでファイルを作成する
File.write( "ファイルの場所", "ファイルの中身" )

File.write( "public/sample.txt", "Hello World" )

・画像を保存する
コントローラーのupdateで、画像のファイル名をid.jpgのような形にする
@user.image_name = "#{@user.id}.jpg"

・画像をコントローラで受け取る
送信元のページのinputのnameに指定したものを、送信先のコントローラでparams[:(名前)]として取得する

・画像を保存する
バイナリで保存する
@user.imamge_name="#{@user.id}.jpg"
image = params[:image]
File.binwrite("public/user_images/#{@user.image_name}", image.read)

・画像が送信されたかどうかを判定する
if params[:image]
@user.image_name = "#{@user.id}.jpg"

end

みたいな感じ

・ログインの流れ
送信されたメールアドレスやパスワードをもとに、データベースからユーザーを特定する

ログインページを作成する
①ルーティング login
②コントローラ作成 login_form
③ビュー

・パスワード用のフォーム作成
<input type="password">

・フォーム名の送信
ルーティング
post "login" => "users#login"
コントローラ
def login
end
ビュー
<%= form_tag("/login") do %>
<p>メールアドレス</p>
<input name="email">
<p>パスワード</p>
<input type="password" name="password">
<% end %>

・ルーティングについて
getとpostが分かれていれば別物として扱われる

・ユーザーを特定する
①ユーザーを特定する
@user = User.find_by(email: params[:email], password: params[:password])

find_byは見つからなければfalseになる

②特定したユーザーでログインする
if @user
flash[:notice] = "ログインしました"
redirect_to("/posts/index")
else
render("users/login_form")
end

・ユーザーが存在しない場合の処理
エラーメッセージを自作する

@error_message = "メールアドレスまたはパスワードが間違っています"

<%= @error_message %>

・初期値の設定
コントローラー
@email = params[:email]
@password = params[:password]
render("users/login_form")

<p>メールアドレス</p>
<input name="email" value="<%= @email %>">

<p>パスワード</p>
<input type="password" name="password" value="<%= @password %>">

・session
セットしておくと、ログイン後ずっとブラウザから同じ値を取得できる仕組み
session[:user_id] = 1

・session[:user_id]の値を空にする方法
def logout
session[:user_id] = nil
end

・ログアウトを作成
ルーティング
post "logout" => "users#logout"
コントローラ
def logout
session[:user_id] = nil
flash[:notice] = "ログアウトしました"
redirect_to("/login")
end

・getとpostについて
postはsessionの値を変更する場合にも使用される

・ログイン状態の切り替え
<% if session[:user_id] %>
<li>
<%= session[:user_id] %>
</li>
<% else %>
<li>
<%= link_to("...", "/about") %>
</li>
<% end %>

ログイン状態で表示する項目
id 投稿一覧 新規投稿 ログアウト

ログアウト状態で表示する項目
TweetAppとは ログイン

・パスワードを保存する
newビューで
value="<%= @user.password %>"

コントローラー
password: params[:password]

・ユーザー登録時にログイン状態にする
コントローラー
create
save
session[:user_id] = @user.id

・ユーザー名を表示する方法
<% current_user = User.find_by(id: session[:user_id]) %>

<li>
<%= link_to(current_user.name, "/users/#{current_user.id}" ) %>
</li>

・application.html.erbについて
これは共通のページを書いておけるもの

・before_actionコマンド
アクションが実行される前に実行されるものを指定できる

・applicationコントローラ
全てのコントローラで共通する処理はapplicationコントローラにまとめることができる。
before_action :set_current_user

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

・アクセス制限

def new
if @current_user == nil
flash[:notice] = "ログインが必要です"
redirect_to("/login")
end
end

・authenticate_user
authenticateは認証

def authenticate_user
if @current_user == nil
flash[:notice] = "ログインが必要です"
redirect_to("/login")
end
end

・before_actionを特定のアクションのみで実行する
適用したいアクションを配列形式で指定できる

before_action :authenticate_user, {only: [:edit, :update]}

・ログイン中は入れないページを作成する
redirect_toで代わりのページを表示するイメージ
forbidは禁じる

def forbid_login_user
if @current_user
flash[:notice] = "すでにログインしています"
redirect_to("/posts/index")
end
end

homeコントローラー
before_action :forbid_login_user, {only: [:top]}

usersコントローラー
before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]}

・ユーザーの編集を制限する

<% if @user.id == @current_user.id %>
<%= link_to("編集", "users/#{@user.id}/edit") %>
<% end %>

・ユーザーの編集を制限する
notice 通知

before_action :ensure_correct_user, {only: [:edit, :update]}
def ensure_correct_user
if @user.id != @current_user.id
flash[:notice] = "権限がありません"
redirect_to("/posts/index")
end
end

・to_iメソッド
文字列から呼び出せる。数値に変換できる。
paramsは文字列で保存しているのでto_iで数値に変換する必要がある。

・ensureは確保する


rails g migration add_user_id_to_posts

app/db/migrate/↑
add_column :posts, :user_id, :integer

rails db:migrate

app/models/post.rb
validates :user_id, {presence: true}

・新規投稿をログインユーザーに紐づける
投稿したユーザーのidを保存する
ポストのコントローラー
def create
@post = Post.new(
content: params[:content],
user_id: @current_user.id
)
end


・user_idからユーザー情報を取得する
ポストコントローラー
def show
@post = Post.find_by(id: params[:id])
@user = User.find_by(id: @post.user_id)
end
ポストのSHOWのビュー
<img src="<%= "/user_images/#{@user.image_name}" %>">
<%= link_to(@user.name, "/users/#{@user.id}")%>

・インスタンスメソッドとは
クラスの中の関数

・インスタンスメソッド内でselfを使うとき
User.find_by(id: self.user_id)

・where
複数のデータを取得する場合はwhereを使用する。
find_byは1つしかとってこない

・userモデルにpostsメソッドを定義する
def posts
return Post.where(user_id: self.id)
end

・投稿をすべて表示するループ
<% @user.posts.each do |post| %>
#ここに表示する内容を書く
<% end %>

・投稿者のみに編集・削除リンクを表示しよう
<% if @post.user_id == @current_user.id %>
<%= link_to("編集", "/posts/#{@post.id}/edit") %>
<%= link_to("削除", "/posts/#{@post.id}/destroy", {method: "post"}) %>
<% end %>

・投稿の編集・削除を制限しよう
before_action :ensure_correct_user,{only: [:edit, :update, :destroy]}

def ensure_correct_user
@post = Post.find_by(id: params[:id])
if @post.user_id != @current_user.id
flash[:notice] = "権限がありません"
redirect_to("/posts/index")
end

・いいね機能を作ろう
likesテーブルを作成する
likesテーブルには、user_idがpost_idにいいねしたことを保存する

likesテーブルを作成する
rails g model Like user_id:integer post_id:integer

rails db:migrate

バリデーションを設定
app/models/like.rb
validates :user_id,{presence: true}
validates :post_id,{presence: true}

いいねデータを作成する
rails console
like = Like.new(user_id:1,post_id:2)
like.save

いいねした投稿かどうか表示する
いいね!済み
いいね!していません
find_byは見つからなかったらnilになる
posts/show.html.erb
<% if Like.find_by(user_id: @current_user.id, post_id: @post.id) %>
いいね!済み
<% else %>
いいね!していません
<% end %>

いいねボタンの準備
likesコントローラを手動で新規作成する
app/controllers/likes_controller.rb

createアクションを用意する
class LikesController < ApplicationController
def create

end
end

ルートを作成する
config/routes.rb
post "likes/:post_id/create" => "likes#create"

いいねボタンを作ろう
createアクションを完成させよう
コントローラー
@like = Like.new(
user_id: @current_user.id,
post_id: params[:post_id]
)
@like.save
redirect_to("/posts/#{params[:post_id]}")

ルーティング

ビュー
いいね!の文章をリンクにする
<%= link_to("いいね!", "/likes/#{@post.id}/create", {method: "post"}) %>

いいね取り消しボタンを作成する
コントローラ
def destroy
@like = Like.find_by(
user_id: @current_user.id,
post_id: params[:post_id]
)
@like.destroy
redirect_to("/posts/#{params[:post_id]}")
end

ルーティング
post "likes/:post_id/destroy" => "likes#destroy"

ビュー
<%= link_to("いいね!済み", "/likes/#{@post.id}/destroy", {method: "post"}) %>

・いいねボタンをアイコンにする
Font Awesomeを使う
Font Awesomeを読み込む
これはapplication.html.erbに書く
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

・いいねボタンをアイコンにする2
HTML要素に対してlink
NG例
<%= link_to('<span class="fa fa-heart"></span>', "/likes/#{@post.id}/destroy", {method: "post"}) %>
OK例
<%= link_to("/likes/#{@post.id}/destroy", {method: "post"} ) do %>
<span class="fa fa-heart like-btn"></span>
<% end %>
<%= link_to("/likes/#{@post.id}/create", {method: "post"}) do %>
<span class="fa fa-heart like-btn"></span>
<% end %>

・いいねの数を取得する
countメソッド

rails console
Like.all.count

Like.where(post_id:1).count

・いいねした投稿の一覧を表示する
ルーティング
get "users/:id/likes" => "users#likes"

コントローラ
def likes

ビュー

・いいねした投稿の一覧を表示する
likesアクションを完成させる
def likes
@user = User.find_by(id: params[:id])
@likes = Like.where(user_id: @user.id)
end

ビュー
<% @likes.each do |like| %>
<% post = Post.find_by(id: like.post_id)%>
<% end %>

・パスワードの安全な取り扱い
パスワードの暗号化にはgemというツールを使う
ジェム
Gemfileを編集する
ジェムとは、よく使う機能をパッケージ化したもの

bcryptという暗号化するためのgemを使用する

root
Gemfile
Gemfile.lock

gemのバージョン

gemを読み込む
gem 'bcrypt'

gemを書き終わったらターミナルで下記を実行する
bundle install


bundleは束という意味

・has_secure_password
Userモデルのすぐ下に以下のメソッドを書くと使える
has_secure_password

パスワードを暗号化するための準備
・password_digestカラムを追加する

マイグレーションファイルの作成
rails g migration change_users_columns
add_column :users, :password_digest, :string
remove_column :users, :password, :string

ターミナル
rails db:migrate

・authenticateメソッド
@user && @user.authenticate(params[:password])


この記事が気に入ったらサポートをしてみませんか?