Webエンジニア目指して#46
どうも激太りマンです。
前職のときは晩飯食わないことが多かったんですが、実家だと毎日出してくれるおかげでカロリー収益が鰻上りでございます。ヤバい。
Rails道場編も最後まで終わらせました。
bcrypt導入の流れで、passwordの初期値のケアの指示が無くてつまづく人多そうですね
挫折する人が多いと聞く中で割とすんなり終わったなあと思います。
githubは特に書き残すことはありませんでした。ついでにProgateのgitやります
gitとは
バージョン管理ツールで、保存履歴からバージョン復元や統合ができるため他人と共同開発をするのに使うらしい
gitにファイルをアップロードする(pushする)
ターミナルで開発アプリケーションのルートフォルダに移動して、以下のようにコマンドを実行する
git init
git使用準備初期化
|
git add ファイル名
ファイル選択
|
git commit -m "伝えたいこと"
ファイル記録(commit)と伝言(commit message)
|
git remote add リモートリポジトリ名 URL
共有する場所であるリモートリポジトリとやらを登録する。
URLは用意する必要あり
|
git push リモートリポジトリ名 master
対象リポジトリにファイルをアップロードする。プッシュするというらしい
ここで初めて相手と共有できるようになる。
gitからファイルをダウンロードする(pullする)
プル側もgit init
とgit remote add
は必要。
準備が終わった上で、git pull origin master
を実行すると、リモートリポジトリからファイルがダウンロードされる
変更を加えたファイルを確認する
push前に、ローカルで自分がどのファイルに変更を加えたか確認するには
git status
を実行する。
リモートリポジトリと差異がある、つまり変更があるファイルは以下のようにコマンドラインに表示される。
赤はgit add
されてない状態、
緑はgit add
されている状態。
modified: index.html
modified: stylesheet.css
変更内容の詳細はgit diff
で見れる。
赤が変更前、緑が変更後の内容。
緑だけの場合は追加された内容。
- <p>test</p>
+ <p>こんにちは</p>
commit履歴を見る
git log
でcommit履歴が見れる。
様々なオプションがあり、git log -p
で変更内容も見れる。
ログが多いと上下キーでスクロールできるようになり、Qキーで終了できる。
さて残るはrails tutorialですね。ではでは
Webエンジニア目指して#45
どうもエアコンのカビが辛いマンです。早う一人暮らしがしたいのう... 最近スプラも飽き気味なのでリフレッシュはぷよぷよに移行しつつあります。弥生時代習得したはずなのに反復してなさすぎて抜けちゃった〜と嘆いてたんですが、ぷよスポは先折GTRの時代らしくて助かった
さてやっていきましょうRails XIです。Railsもいよいよラスト
目標
パスワードを文字列そのまま保存しておくと盗まれたら大変なため、盗まれたとしても使い物にならないようハッシュ化する
ハッシュ化用gemのインストール
gemとはrubyの拡張パッケージ。
gemfileの記述
gemfileとは、アプリのルートディレクトリにある、railsにインストールしたいgemを記述するファイル。
中身を見てみると、gem 'gem名' , 'バージョン'
の形でたくさん並んでいる。
これらはrails new
した時に最初にインストールされたものらしい
バージョンの頭に比較演算子みたいなのがついている。
これには以下のようなルールがある
・ x.0.0 : バージョン固定
・ >= x.0.0 : 演算子通り(x.0.0以上)
・ ~> x.0.0 : x.0.0以上X+x.9.9以下(一桁目固定)
・ '>= x.0.0' , '< x.3.0' : 演算子通りの複合
・ 記述なし : 最新バージョン
さて、今回は使いたいハッシュ化用gem"bcrypt"を記述する。
gem 'bcrypt', '~> 3.1.7'
既にgemfileにコメントアウトしてあった。
これを追加し保存したら、ターミナルでbundle install
と入力するとgemのインストールが始まる。
...はずだった。
bundle install
すると予期せぬエラーが返ってきた。
gem install 'bcrypt'
で切り分けてみたら、permission deniedが返ってきた。
sudoすることで解決できたが、rootでbundler使うなと警告された。
色々調べてみると、過去にどこかしらでsudoでgem入れたことでメインユーザーディレクトリのアクセス権がsuになってたみたい
先人の知恵を借りてchownコマンドで対象ディレクトリのアクセス権を直した。
これでgem install 'bcrypt'
が成功した。
改めてbundle install
してみたが、gem揃ってるぜ!みたいな感じだった
何も知らないままsudoしただろうからどのタイミングでやらかしたか分からないが、system領域でもないのに権限弾かれた時は対象のフォルダ権限を参照してみるのがいいかも
さて解決したところで次
bcryptの使い方
対象モデルクラスにhas_secure_password
を定義する
has_secure_password
はpasswordが存在するか自動チェックするため、
passwordカラムに対してのpresence:true
は不要になる。
class User < ApplicationRecord has_secure_password #削除 validates:password,{presence:true} 以下略
password_digestカラムの作成
bcriptはハッシュ化したパスワードをpassword_digestカラムへ保存するため、それ用にmigrationする。passwordカラムは不要になるため削除する
以下のようにremove_column
でカラムの削除ができる
class ChangeUsersColumns < ActiveRecord::Migration[6.1] def change add_column :users, :password_digest, :string remove_column :users, :password, :string end end
password_digestの自動生成
下図のように、passwordに値が与えられるとbcryptによって自動でハッシュ化され
password_digestに代入される。
この処理はpasswordカラムがなくても動作する。
そのため、今まで書いたコードでpasswordに代入していた処理をpassword_digestに置換する作業はいらない。 ログイン処理については変更があるので次項で。
ハッシュ化passwordでのログイン
has_secure_passwordを付与したモデルクラスはauthenticateというメソッドが使えるようになる。
authenticateメソッドは@user.authenticate("neko")
のように記述し、
引数の文字列をハッシュ化しpassword_digestと一致するかどうかT/Fで判定する。
これを使ってログイン処理を書き替える。
以前書いたログイン処理はemailとpassがそれぞれ入力と一致した@userが存在すればログインする記述だった
def login @user=User.find_by(email: params[:email], password: params[:password]) if @user 以下略
今回はemailが一致する@userが存在し、且つその@userのauthenticateがTrueの場合にログインするようにする。
def login @user=User.find_by(email: params[:email]) if @user && @user.authenticate(params[:password]) 以下略
これでログインしてみる。viewは代わり映えしないのでサーバーログを見る authenticity_token辺りがそれっぽい。ログインは成功
ちなみにgemを入れたらサーバーは再起動しないとこんなエラーが出るみたい bcryptないわけないじゃん、bundle installでも確認したしと思って一発で再起動思いついたのえらいぞお
bcryptのセキュリティ性の高さは、平文にsalt(ランダムな文字列)を加えて文字数をかさ増ししてからハッシュ化することで総当りに強くなるところらしい。確かにnekoの4文字からでも大変な事になってた
ただ、専門的な突破口はあるみたいなので、お手軽セキュアって感じ?本格的に実装するなら他にもやらないとダメそう
Webエンジニア目指して#44
どうも金欠マンです。 貯金して転職に備えたので金欠っていうほどそうではないんですけど、スマホ割れたり健康保険料や市民税だったりとお金がなくなっていくことに焦燥感を覚えます。せっかくの無職期間だしゆったりするか〜と思ってたけどあんまり悠長にしてられないですね。
というわけでやっていきましょうProgateのRails X!!!!!!!!!!!!!!
目標
イイネ機能の実装
イイネ用テーブルの用意
誰がどのツイートにイイネをしたか、user_idとpost_idを格納するLikeテーブルをいつもの感じで作る
投稿詳細でのイイネの表示
ログインユーザーがイイネした/してないを表示させる
post/details.html.erb
<% if Like.find_by(user_id:@current_user.id,post_id:@post.id) %> <p>♥</p> <% else %> <p>♡</p> <% end %>
よくある表現で書いた
即席なので文字だが、cssか画像素材でやるのが良さそう
イイネボタンの実装
routing
post 'likes/:post_id/save' => `likes#save`
post/details.html.erb
<% if Like.find_by(user_id:@current_user.id,post_id:@post.id) %> <p>♥</p> <% else %> <p><%= link_to("♡","/likes/#{@post.id}/save",{method:"post"}) %></p> <% end %>
未イイネのテキストをlink_to
でイイネ登録actionに飛ばす
likes_controller.rb
def save @like=Like.new(user_id:@current_user.id, post_id:params[:post_id]) @like.save redirect_to("/post/#{params[:post_id]}") end
対象の投稿params[:post_id]
にログインユーザー@current_user.id
がイイネした、となるよう書いた
結果
イイネ取り消しボタンの実装
イイネ登録のノリでdestroyするだけ!割愛!
link_toメソッドにhtml要素を仕込む
従来のlink_toだとlink_to("text","URL")
のように文字列しか表示させることができない
以下の書き方だとhtmlタグを用いて表示させることができる
<%= link_to("URL") do %> <div class="sample"></div> <% end %>
せっかくなのでこれでイイネのハートマークをアイコンで置き換える
<% if Like.find_by(user_id:@current_user.id,post_id:@post.id) %> <%= link_to("/likes/#{@post.id}/delete",{method:"post"}) do %> <span class="fa fa-heart btn unlike"></span> <% end %> <% else %> <%= link_to("/likes/#{@post.id}/save",{method:"post"}) do %> <span class="fa fa-heart btn like"></span> <% end %> <% end %>
結果
countメソッドを使ってイイネ数を表示させる
countメソッドはモデルクラスに対してSQLのcountと同じ感じで使う
例
これを使ってイイネ数を表示させる
投稿詳細actionに対象投稿idのイイネ数@likes_countを定義
@likes_count=Like.where(post_id: @post.id).count
投稿詳細viewで@likes_countを表示
<%= @likes_count %>
結果
何故かアンダーバーが割り込む。アイコンのボックスでもカウントのでも違くて急に現れる謎のアンダーバー。誰ですかあなた?????help????
aタグらしい。ということはlink_toが悪さをしている...?
よく見たらアンダーバーじゃなくてtext-decorationの下線だった。
普通にaタグの下線消して解決
ユーザーがいいねした投稿一覧をユーザー詳細に表示する
routing
get 'users/:id/likes' => 'users#likes'
users.controller
def likes @user=User.find(params[:id]) @likes=Like.where(user_id: @user.id) end
users/likes.html.erb
<p>このユーザーのイイネ</p> <% @likes.each do |like| %> <% post=Post.find(like.post_id) %> <img src="<%= "/user_images/#{post.user.image_name}" %> "> <%= link_to(post.user.name,"/post/#{post.user.id}") %> <%= link_to(post.message,"/post/#{post.id}") %> <% end %>
@usersに詳細表示中ユーザーidのレコードを取得して、
@likesでそのユーザーがイイネした投稿を全て取得する
viewで@likes.eachの中に各@likesから取り出されたレコードに対してpost_idの紐付けからpostsテーブルの投稿データを表示させる
結果
これでRuby Xは終わり!
今まで知らなかったんですが、RailsにはCRUDという概念があるらしく
全くそれに沿わずaction名をcreate=>save, show=>details, destroy=>deleteと定義してました。他の技術者と意思疎通する際に困りそうなので次回構築するときはそれぞれ合わせていきたいですね
ではでは。
Webエンジニア目指して#43
どうもアニメマンです
ウマ娘めちゃくちゃ面白いですね。1期スルーしてましたが最近の盛り上がりがすごくて見てみたらハマりました。スマホゲーはやらないけど...
さあやっていきましょうProgateのRails IXです。
の前に、Rails道場編IIIの反省を書こうと思いましたが特にありませんでした。括弧の自動有力に慣れてしまってて、Progateでは{}が自動で閉じられなくてsintax errを出すみたいなしょうもないのくらいですね
あと、ログインユーザー本人のアカウント情報以外編集出来ないようにするメソッド作りましたが、postアクションだけ何故かリダイレクトせず、no routeエラーを返すようで困りましたが次触る時に調べることとします →ほっとくのはまずいと思って探ってみたらわかりました!!!!
エラー画像
よく見たら[GET]ってあるんですよね。updateメソッドはpostでroutingしてあるのでgetはおかしい
考えてみたらURLの直接入力はget扱いになるので当然のエラーでした。postは特定の処理しないとできないからね
get用のrouting作ってダミーactionで不正な処理として適当なページにリダイレクトさせようかな、と考えましたが、意図しないURLは全部こうなるんだから気にしないことにしました。
はい、というわけで今度こそRails IXやっていきます
目標
投稿とユーザーの紐付け、対応データの表示
投稿テーブルにユーザーidカラムを追加する
いつもの通りmigrationファイル作ってadd_column
してdb:migrate
からのvalidates
で{presence:true}書いてfinish
ユーザーidは数字のため型はintegerにする
ここで1点反省、最初の方に"post"でrails g controllerを実行してpost-modelが生成されているが、テーブル名はpostsで生成されていてめちゃくちゃ紛らわしい。
なので次回からはcontrollerやmodelを作るときは複数形で統一したい
投稿actionにログイン中のユーザーidを付与
def save @post=Post.new( message: params[:message], user_id: @current_user.id )
投稿詳細にユーザー情報を表示する
post.controller
def details @post=Post.find_by(id: params[:id]) @user=User.find_by(id: @post.user_id) end 以下略
post/details.html.erb
<img src="<%= "/user_images/#{@user.image_name}" %>" > <%= link_to(@user.name,"/users/#{@user.id}") %>
結果
postモデルにインスタンスメソッドを定義する
class Post < ApplicationRecord def user return User.find(self.user_id) end 以下略
selfメソッドによって、インスタンスの値を利用できるため、
レコードを読み込ませた@post
インスタンスに対して@post.user
と扱うことで簡単にUserテーブルを参照できる
投稿一覧にユーザー情報を表示する
post/index.html.erb
<% @posts.each do |post| %> <img src="<%= "/user_images/#{post.user.image_name}" %> "> <%= link_to(post.user.name,"/post/#{post.user.id}") %> <%= link_to(post.message,"/post/#{post.id}") %> <% end %>
先程の@post.user
によって、@userを定義しなくても以下のように@postだけでUserテーブルの情報を持ってこられる
結果
whereメソッドを使ってユーザー詳細ページに投稿を表示する
whereメソッドとは、SQLでいうwhereのようにテーブルに対し特定のカラムでフィルターをかけ、そのレコード群を配列として返すもの。
rails consoleでの例
これを使って、対象のユーザーidの投稿を取得するインスタンスメソッドをUserモデルに定義する
class User < ApplicationRecord def posts return Post.where(user_id: self.id) end 以下略
そしてユーザー詳細viewで@user.posts
の配列に対してeachメソッドを使って投稿データを並べる
<% @user.posts.each do |post| %> <img src="<%= "/user_images/#{post.user.image_name}" %> "> <%= link_to(post.user.name,"/post/#{post.user.id}") %> <%= link_to(post.message,"/post/#{post.id}") %> <% end %>
結果
投稿詳細画面で投稿者以外に編集制限をかける
基本的にはユーザー編集画面と同じ処理
せっかくなので@current_user.id
と@post.user.id
で照合させる
post/details.html.erb
<% if @current_user.id == @post.user.id %> <%= link_to("編集","/post/#{@post.id}/edit") %> <%= link_to("削除","/post/#{@post.id}/delete",{method:"post"}) %> <% end %>
post.controller
before_action :check_incorrect_user,{only:[:edit,:update,:delete]} def check_incorrect_user @post=Post.find(params[:id]) if @current_user.id != @post.user.id flash[:notice]="権限がありません" redirect_to("/post/index") end end
結果
これでRails IXはおわり!ではでは
Webエンジニア目指して#42
どうもギター売りマンです strandbergというメーカーの7弦ギターを何故か2本持っているので片方出品しました。何故でしょうねえ・・・ 手放すのが惜しいので元値からあまり下げてないけど、売れて欲しい、売れて欲しくない、売れて欲しい
そんな感じでやっていきましょう、ProgateのRails VIIIです
目標:ユーザーアカウント機能実装
ログインページの作成
view
<h1>ログイン</h1> <% if @error_message %> <%= @error_message %> <% end %> <%= form_tag("/login") do %> <p>e-mail</p> <input name="email" value="<%= @email %>"> <p>パスワード</p> <input type="password" name="password" value="<%= @password %>"> <input type="submit" value="ログイン"> <% end %>
冒頭の記述でログインに失敗したとき用の@error_message
を表示させるようにする
後は今まで通りフォームを記述
input
のtype属性をpassword
にすることで以下の画像のように入力時に隠れるようになる
パスワードの欄を増やしたので前回と同じようにデータベースにも専用のカラムを増やしておく。また、usersモデルにvalidates:password,{presence:true}
のvalidationを設ける
routing
get 'login' => 'users#login_form' post 'login' => 'users#login'
getとpostは同じURLにしても大丈夫らしい(自作するなら分けるかなあ)
action
def login @user=User.find_by(email: params[:email], password: params[:password]) if @user flash[:notice]="ログインしました" redirect_to("/post/index") else @error_message="メールアドレスかパスワードが間違っています" @email=params[:email] @password=params[:password] render("users/login_form") end end
find_by
でフォームに入力されたemailとpassが一致したレコードを取得し、取得の結果でif文を書く
このようにif 変数
という書き方をすると変数がnilかどうかで分岐してくれるみたい(nilの場合にelseになる)
elseにはviewで言及したログイン失敗メッセージ用の変数とフォームの初期値に代入
結果
ユーザー認証は出来たのでログインページは完成
ログイン処理
先程のユーザー認証はユーザーを特定したが飛んだページはただの投稿一覧なので、「このユーザーでログインしてますよ」という処理を書いていく
session変数
session[:キー名]
の形で使う
この変数はブラウザが記憶してくれるらしく、ユーザーidなどを代入しておけばログイン中のユーザー名表示や権限などの実装ができる
action
先程のユーザー認証actionに、認証が成功したときにそのユーザーの情報をsession変数に代入させる
def login @user=User.find_by(email: params[:email], password: params[:password]) if @user session[:user_id]=@user.id session[:user_name]=@user.name flash[:notice]="ログインしました" redirect_to("/post/index") else @error_message="メールアドレスかパスワードが間違っています" @email=params[:email] @password=params[:password] render("users/login_form") end end
ユーザーidとユーザー名を取得させた。
ユーザー名を後述のviewで使う
ユーザーidは、まあそのうちなんか使い道あるでしょ
application.html
ヘッダーにその時ログインしているユーザーの名前を表示させる
<p>ログイン中のユーザー:<%= session[:user_name] %></p>
結果
右上のログイン中に注目
割愛するが、新規登録の際にもパスワードを取得し、登録完了したらそのままログインできるようにする
ログアウト処理
session変数にnilを代入すればブラウザに記憶されたユーザーがリセットされる
view
ログアウトのlink_to
に`{method:"post"}を書いている。フォームデータのやりとりをする場合以外に、session変数に変更を加える場合もpostでroutingする必要がある
また、先程のif 変数
を利用してsession変数の中身があるかないか、つまりログイン状態かログアウト状態かどうかでヘッダーに表示させる項目を変えている
<% if session[:user_id] %> <div class="header-info"> <p>ログイン中のユーザー:<%= session[:user_name] %></p> </div> <ul class="header-menu"> <li><%= link_to("投稿一覧", "/post/index") %></li> <li><%= link_to("新規投稿", "/post/new") %></li> <li><%= link_to("ユーザー一覧", "/users/index") %></li> <li><%= link_to("ログアウト", "/logout",{method:"post"}) %></li> </ul> <% else %> <ul class="header-menu"> <li><%= link_to("新規登録", "/users/new") %></li> <li><%= link_to("ログイン", "/login") %></li> </ul> <% end %>
routing
post 'logout' => 'users#logout'
action
def logout session[:user_id]=nil session[:user_name]=nil flash[:notice]="ログアウトしました" redirect_to("/login") end
結果
変数にログイン中ユーザーのレコードを代入する
上記までsession変数をid用name用で2つ用意していたが、session変数でユーザーid1つ取得しておけば下記のように同一レコードの他のデータを参照できる
<% current_user=User.find_by(id:session[:user_id]) %> <% if session[:user_id] %> <div class="header-info"> <p>ログイン中のユーザー: <%= link_to(current_user.name,"/users/#{current_user.id}") %></p> </div> -----以下略-----
ただ、この書き方だとユーザーデータを参照する全てのviewでレコード用の変数を定義する必要ができてしまう
そこで、下記のようにcontrollerに対してbefore_action :共通処理のaction
と書くことでそのcontrollerの全てのactionの前に、指定した処理をさせるシステムを利用する
class ApplicationController < ActionController::Base before_action :set_current_user def set_current_user @current_user = User.find_by(id: session[:user_id]) end end
こんな感じでクラスの直下に書く。 ApplicationControllerに書いて全てのviewに対してログイン中のユーザーデータを利用、ということもできる
@current_userで定義したところで、先程viewに書いたcurrent_userを書き替える
<% if @current_user %> <div class="header-info"> <p>ログイン中のユーザー: <%= link_to(@current_user.name,"/users/#{@current_user.id}") %></p> </div> -----以下略-----
ついでにifの条件も書き替えた。ログイン/ログアウトactionで定義していたsession[:user_name]は使わないため削除しておく
アクセス制限
ユーザー認証メソッドを作る
application.controllerに以下のメソッドを追加する
def authenticate_user if @current_user == nil flash[:notice]="ログインが必要です" redirect_to("/login") end end
先程before_actionで仕込んだメソッドによって、先に@current_userが定義されるため使い回しができる
before_actionにonlyを指定する
application.controllerにメソッドを作っただけでは作動しないため、users.controllerに以下のように書く
class UsersController < ApplicationController before_action :authenticate_user,{only: [:index,:show,:edit,:update]} ----以下略----
全てのcontrollerはapplication.controllerを継承しているため、このようにusersでも先程の認証用のメソッドを仕込める
また、before_actionの第2引数に{only: [:メソッド1, :メソッド2]}
のように書くとそれらのメソッドに対してのみbefore_action処理が行われるようになる
これによって、ログインが必要な機能、不要な機能を分けることができる。
例えばログインや新規登録にログインが必要だったら困るため、それらを除外してbefore_action処理を行わせるように書く。
逆に、ログイン済でログインや新規登録の画面は表示させたくないのでログイン済みなら弾くメソッドを用意してbefore_actionで各actionに適用させておく
post.controllerは全てログインを必要とさせたいためonlyを使わずbefore_actionで認証用メソッドを仕込んでおく
結果
他のユーザーにユーザー情報を編集させないようにする
ログイン中ユーザーとユーザー情報ページのidが一致している場合だけ編集と削除を表示させる
<% if @current_user.id == @user.id %> <%= link_to("編集","/users/#{@user.id}/edit") %> <%= link_to("削除","/users/#{@user.id}/delete",{method:"post"}) %> <% end %>
表示は消したがURLに入力すれば編集ページに入れてしまうため、そこもカバーしていく
ログイン中のユーザーidとURLに入力されたidが違うなら弾くメソッドを作成し、 編集ページとactionに対して適用する
before_action :check_incorrect_user, {only: [:edit,:update]} def check_incorrect_user if @current_user.id != params[:id].to_i flash[:notice]="権限がありません" redirect_to("/post/index") end end
params[:id]は文字列として取得してしまうため、いつかしらのパートで使ったto_iメソッドで数値へ変換して比較演算にかける
結果
ということでRails VIIIはおわり! 書きすぎて長引いちゃった ではでは。
Webエンジニア目指して#41
どうも特に無いマンです。
暇ではないんですが、仕事ないとなんか足りないですね〜
腹が減ったときの飯が美味いのと同じで、ある程度ストレスないと娯楽も楽しみが減りますね。フリマに断捨離以外はやり残したことなくなってきたんで学習時間の増やしどころかも
さてやっていきましょうProgateのRails VIIです
目標は画像の投稿機能実装
テーブルへカラムを追加する
migrationファイルのみ作成しデータベースへ反映させる
$rails g migration ファイル名
試しに作ってみたものの中身がこれ
class AddImageNameToUsers < ActiveRecord::Migration[6.1] def change end end
今回は空だが、実は今まで使っていた$rails g model
を実行した場合はchangeメソッドの中身は自動生成されていた
カラムを追加したい場合は以下のように書く
class AddImageNameToUsers < ActiveRecord::Migration[6.1] def change add_column :テーブル名, :カラム名, :データ型 end end
次に$rails db:migrate
を実行するとchangeメソッドが実行され、対象のテーブルにカラムが追加される
試しに実行してみた
比較画像:実行前 比較画像:実行後 image_nameカラムが増えたので成功
画像とリンクさせる
テーブルに追加したカラム名の文字列と画像ファイル名をレコードごとに一致させ、後はhtmlで参照するだけ
データベース
既存のレコードはimage_nameカラムが空だったので追加しておく
画像ファイルの保存場所
画像ファイル名とimage_nameカラムの値を一致させる
html
imgタグの参照先に先程一致させた値を使ってパスを埋める
railsを使っているときはimgタグは/public
フォルダから参照されるため、それに合わせて記述する
<img src="<%= "/user_images/#{@user.image_name}" %>">
結果
画像の投稿フォーム
html
<%= form_tag("/users/#{@user.id}/update",{multipart:true}) do %> <p>ユーザー名</p> <input name="name" value="<%= @user.name %>"> <p>e-mail</p> <input name="email" value="<%= @user.email %>"> <p>プロフィール画像</p> <input type="file" name="image"> <p>-</p> <input type="submit" value="変更"> <% end %>
inputタグのtype属性をfile
にするとファイルを選んで送信できる
また、name属性も指定しているため画像のデータが[:image]
として送信される
ファイルの送信フォームがあるときは、form_tagの第2引数に{multipart:true}
を入れる必要がある
見た目はこんな感じ
画像を受け取り保存する
if params[:image] @user.image_name="#{@user.id}.jpg" image=params[:image] File.binwrite("puclic/user_images/#{@user.image_name}","image.read") end
まずif params[:image]
でファイルが選択されている場合のみの処理とし、
@user.image_name="#{@user.id}.jpg"
でデータベースへファイル名を登録
image=params[:image]
でファイルを受け取り、
File.binwrite("puclic/user_images/#{@user.image_name}",image.read)
で
指定ディレクトリへファイルを作成する。
画像データを受け取りファイル作成する場合は受け取ったハッシュに対してreadメソッドというものを使う
いやそもそもFile.binwrite
ってなんやねん、となるので説明
File.write("ファイル名のパス","ファイルの中身")
このようにFileクラスというものがあり、writeメソッドを使うことで指定のディレクトリへファイルを作成できる。
(パスはアプリケーションのルートディレクトリから参照するので注意)
File.write("public/test.txt","aiueo")
を実行した場合は、/public/test.txtというファイルが作成され、その中身がaiueo、ということになる
File.binwrite
はその中身が2進数のバージョンであり、readメソッドを使って受け取った画像ファイルを2進数のデータに変換してファイルを作成している。
失敗談だがimage.read
は変数.メソッドなので"image.read"
と書かないように注意(ファイル生成がうまく出来ていなかった)
結果
これ、簡易的にtwitter作れるんじゃね・・・?
ってなわけでRails VIIはおわりです ではでは
Webエンジニア目指して#40
どうもダンレボ2クレで消費カロリー200kcal、すなわちリングフィット1時間分であることを知ったマンです。
体力がないのでこれだけで足の疲れが翌日に持ち越されてしまいます...三重にいた頃は手軽に行ける銭湯があってよかったなあ
というわけで引き続きProgate Rails VIです。 Rails道場編IIをやりましたが反復なので割愛しました。
重複バリデーション
class User < ApplicationRecord validates:email,{uniqueness:true} end
{uniqueness:true}
はデータベースに対して特定のカラムの重複登録を防いでくれる
できたもの
VIはpostビューでtextareaだったものがinputになった以外はほぼ同じことをやってるのであんまり書くことありませんでした
ではでは