- 投稿日:2020-02-18T23:25:53+09:00
SEしてるけど実はあんまりコード書いたことないんだよねって人に捧ぐ、Rails on Dockerハンズオン vol.8 - Sign up -
はじめに
第8回目です。前回、Userモデルを作り上げユーザー詳細ページを作成するところまでいきました。
今回は、ユーザーをUIから登録すべくSign upページを作っていきたいと思います。いままではRailsコンソールからモデルを操作してユーザーを作成していましたが、今回からはMVCを連携させてユーザーを作成させるようにします。
Sign upページの作成
今回はSign upページでユーザーの
name
、password
を入力してもらい、登録完了後そのユーザーのユーザー詳細ページに遷移させます。
まずは、このアプリを実現するために必要なファイルや設定を作成していきます。今回、Sign upページにアクセスするためのRouting、Action、Viewと、実際にUserをDBに登録するRouting、Actionが必要になります。
Scaffoldを思い出してみてください。
あの時、新規にユーザーを作成するには/users/new
のページにアクセスしており、new
アクションがありました。
そこで登録ボタンを押すと、/users
のURLにPOSTメソッドでリクエストが飛びcreate
アクションがDBにユーザーを保存していました。では、これらの設定を元にRouting、Action、Viewをコーディングしていきましょう!
Routing
まず、
users#new
、users#create
へのルーティングを作成します。
しかし、Sign upページと呼んでいるのですから/users/new
のようなURLでは少しカッコつきません。
今回は/sign_up
にGETリクエストしたときにusers#new
にルーティングされるように定義していきましょう。
users#create
へのルーティングも/sign_up
にPOSTリクエストしたときに定義します。config/routes.rbRails.application.routes.draw do root 'static_pages#home' get '/sign_up', to: 'users#new', as: :sign_up post '/sign_up', to: 'users#create', as: :create_user resources :users, only: [:show] end追加した行は以下の通り。
get '/sign_up', to: 'users#new', as: :sign_up post '/sign_up', to: 'users#create', as: :create_user読んでいきましょう。
これは、resouces
やroot
以外のルーティングの書き方としてとても一般的なものです。
static_pages#home
を作った時もこんな感じのルーティングが自動生成されたことを覚えていますか?書き方は以下の通りです。
[method] '[path]', to: '[controller_name]#[action_name]', as: '[route_name]'このコーディングで
「path
にmethod
でリクエストされた場合、controller_name
コントローラーのaction_name
アクションにルーティングする。アプリのコードとしてroute_name
_pathと表現された場合は、このルーティングを表すことと定義する。」
ということをRailsアプリケーションに定義立てています。
route_name
はシンボル(:sign_up
のように:
を頭につけてる文字)で書いてます。シンボルは複数あっては困るものなどに使用するそうです(「Rubyのシンボルと文字列の違い | UX MILK)。
ルートの名前も重複しては困りますので、シンボルを使っています。ルーティングの設定はこれで完了です。次はコントローラーに新しくアクションを用意しましょう。
Action
次にUserコントローラーに
new
アクションを追加します。app/controllers/users_controller.rbclass UsersController < ApplicationController def show @user = User.find(params[:id]) end # newアクションを追加する def new @user = User.new end # createアクションをとりあえず追加しておく def create end end
new
アクションでは、インスタンス変数@user
にUser.new
を代入しています。
これはView側でUserモデルを扱ってフォームを作っていくために空のモデルが必要なのです。
詳しくはView側で説明しますので、ひとまずそのままコピペでお願いします。
create
アクションはとりあえず定義だけしておきます。処理はのちのち。View
ではでは、Viewファイルを作っていきます。
new
アクションでrenderされるViewなのでnew.html.erb
ファイルを作成します。# touch app/views/users/new.html.erbapp/views/users/new.html.erb<div class="container"> <h1 class="my-5">Sign up</h1> <%= form_with model: @user, url: create_user_path, local: true do |form| %> <div class="form-group"> <%= form.label :name %> <%= form.text_field :name, class: "form-control" %> </div> <div class="form-group"> <%= form.label :email %> <%= form.text_field :email, class: "form-control" %> </div> <div class="form-group"> <%= form.label :password %> <%= form.password_field :password, class: "form-control" %> </div> <div class="form-group mt-5"> <%= form.submit "Sign up!", class: "form-control btn btn-primary" %> </div> <% end %> </div>構文自体はそこまで難しくないですね。
http://localhost:3000/sign_up
にアクセスしてみましょう。
なかなかぽいページになったんじゃないでしょうか?
password_confirmation
は使わないことにしました。「登録フォームにおけるパスワード確認用の入力欄は必要か | UX MILK」の記事を参考にしまして。
いくつかrubyコードが埋め込まれているので説明していきますね。form_with
こういうのをビューヘルパー(View helper)っていいます。
『form_with』ヘルパーはform
タグを生成してくれるヘルパーです。
model
をオプションに指定することでそのモデルオブジェクトのためのフォームを作ってくれるようになります。上のコードのようにブロック形式でform
変数を使うことで、例えばform.input_field :name
とするだけで@user
のname
属性に関するinputフィールドを作ってくれるようになるので、これは超便利です。
url
オプションはフォームの送信先を定義します。create_user_path
はroutes.rb
でusers#create
へのルーティングにつけた名前ですね。
このようにコーディングすることでcreate
アクションにフォームを送信できるようになります。また、
local: true
オプションも付けています。form_with
ヘルパーではデフォルトでAjax通信でフォームをポストします。つまり、画面遷移なしでフォームをリクエストするんです。これはこれで便利な場面もあって今時な感じなんですが、今回はユーザーの新規作成が成功したらそのユーザーのマイページに画面遷移させたいので、local: true
オプションでAjax通信をオフにしています。
ちなみに『Ajax』は『エイジャックス』または『アジャックス』と読むそうです。僕は『エイジャックス』って読んでます。今回の
form_with
は実際にクライアントに返却される場合は以下のように変換されて返却されています。<%= form_with model: @user, url: create_user_path, local: true do |form| %> ... <% end %>↓
<form action="/sign_up" accept-charset="UTF-8" method="post"> <input type="hidden" name="authenticity_token" value="xxxxxxxxxx"> ... </form>
authenticity_token
が第3回の時に少し触れた、CSRFトークンですね。XSSを防いでくれるやつです。label
label
はラベルを付けてくれるやつです。ページで『お名前』とか『メールアドレス』と出ているやつのことです。<%= form.label :name %>↓
<label for="user_name">お名前</label>text_field
text_field
はinput type="text"
タグでテキストフィールドを作り出してくれます。
使い方も簡単で、text_field [attribute_name], [options]
なだけです。
今回はBootstrapのform-control
classをオプションで付けてあげています。<%= form.text_field :name, class: "form-control" %>↓
<input class="form-control" type="text" name="user[name]" id="user_name">
name
やid
も勝手に付けてくれているのがいいですよね。
ここでid="user_name"
を付与してくれているので、label
のfor="user_name"
と紐付けができるようになっています。password_field
password
を入力するフォームのところではpassword_field
を使いました。
これはtext_field
と似ていますが、input type="password"
タグのフィールドを作ってくれるやつです。<%= form.password_field :password, class: "form-control" %>↓
<input class="form-control" type="password" name="user[password]" id="user_password">
input type="password"
はパスワード用の入力フィールドを作り出せるので、入力した文字が『●』でマスク化されるようになります。submit
submit
タグはフォーム送信用のボタンを作ってくれるタグです。input type="submit"
を作ってくれるんですね。<%= form.submit "Sign up!", class: "form-control btn btn-primary" %>↓
<input type="submit" name="commit" value="Sign up!" class="form-control btn btn-primary" data-disable-with="Sign up!">HTMLの方にある
data-disable-with
はダブルクリック抑止のためのパラメータですね。RailsのERBを使えばこういった必要だけどついつい忘れてしまいがちなHTMLオプションも自動で付与してくれるので積極的に利用するといいと思います。これ以外にもいろいろなヘルパーが用意されているので、HTMLのあのタグはどうやって書けばいいのか、と思った時は直接HTMLタグを書くのではなく一度Railsでの書き方をググってみるといいでしょう!
これでViewがいい感じに作れました。次は「Sign up!」ボタンを押した時の処理をコーディングしていきます。
Createアクションをコーディング
ここまでで
new.html.erb
のフォームからcreate
アクションにフォームをリクエストできるようになりました。
ここからはcreate
アクションでリクエストされたフォームのデータからDBにUserを登録できるようにします。では、先ほど"とりあえず"作った
create
アクションをコーディングしていきます。app/controllers/users_controller.rbclass UsersController < ApplicationController ... def create @user = User.new(user_params) if @user.save redirect_to @user else render :new end end private def user_params params.require(:user).permit(:name, :email, :password) end endはい。初見だとけっこう複雑に見えるんじゃないかなーと思います。
1行ずつみていきましょう。@user = User.new(user_params)まず、
@user
にUser.new(user_params)
を代入しています。
user_params
とは何でしょう?private def user_params params.require(:user).permit(:name, :email, :password) end
user_params
はここで定義されている関数ですね。
params.require(:user).permit(:name, :email, :password)
の部分は『ストロングパラメーター(Strong parameter)』と呼ばれています。Railsが用意しているこのストロングパラメーターは意図しないデータのPOSTを防いでくれます。params.require([model_name]).permit([attribute_names])これでリクエスト内のパラメーター(
params
)からmodel_name
モデルに紐づくデータのみを抽出し、さらにその中からattribute_names
に指定されているデータのみを抽出して返却します。
それ以外のデータはドロップします。これによってユーザーのいたずらで意図しないデータが作られてしまうことを防ぐということです。
例えばモデルにはこっそりadmin
フラグみたいなものがあって1
のユーザーはなんでもできちゃう権限を持っているとします。いたずらっ子のユーザーがそれに気づいてSign upページにdeveloper toolsとかを使ってadmin=1
のフォームを追加してきたりしたとします。ここでストロングパラメーターを使っていない場合はadmin=1
でユーザーが作成されてしまいアプリが乗っ取られてしまう、みたいなことが起きちゃうんですね。
ストロングパラメーターはそういった意図しないフォームからのリクエストを無視するようになるので、安全なアプリケーションの作成に不可欠なものなのです。今回は
User
モデルのname
、password
以外のデータは無視することを定義しています。また、この関数は
private
より下に書かれています。これはクラス内からのみアクセスできる関数であることを定義しています。さて、ここまでで
@user
にuser_params
で抽出されたデータが初期値として設定されたUser
モデルオブジェクトが代入される、ということになります。if @user.save redirect_to @user else render :new end次は、この
@user
をsave
して条件分岐しています。ModelのCRUDの時にも話がでてきましたがsave
メソッドはバリデーションを通りデータをDBに保存できた場合true
を、バリデーションに引っかかった場合false
を返却します。
その結果を元にtrue
の場合はredirect_to @user
、false
の場合はrender :new
が実行されます。redirect_to @user
redirect_to
メソッドは引数にGET
メソッドでリダイレクトします。
引数には@user
を指定してます。これは、user_path(@user)
と同義です。user_path
はshow
メソッドにつけられている名前です。@user
には今DB保存が成功したUserモデルオブジェクトが入っていますので、今保存したユーザーのユーザー詳細ページに遷移させています。render :new
false
の場合はこちらが実行されます。
render
メソッドは指定したアクションのViewファイルをレンダリングするメソッドです。(いろいろと使い方はありますが、今回はこんな説明で)
通常アクションは自分の名前と同じViewファイルをレンダリングするようになっていますが、render
メソッドを使うことで別のアクションのViewファイルをレンダリングするようにすることもできます。
この場合は、new
アクションのViewファイルがレンダリングされます。さらに@user
には今false
になったUserモデルオブジェクトが入った状態でnew.html.erb
に引き渡されます。
そのため、レンダリングされたとしても今入力してた属性データは再表示されるはずだし、@user.errors
の中にはsave
に失敗した理由も残っているわけです。new.html.erb
側を少し更新すればエラーメッセージを表示することもできます。
new.html.erb
でエラーメッセージを表示できるように更新ということで
new.html.erb
を更新して、save
でエラーが発生した場合はerrors.full_messages
が表示されるようにしてみましょう。app/views/users/new.html.erb... <h1 class="my-5">Sign up</h1> <%# ここから追加 %> <% if @user.errors.any? %> <div class="alert alert-danger"> <ul class="mb-0"> <% @user.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <%# ここまで追加 %> <%= form_with model: @user, url: create_user_path, local: true do |form| %> ...これも少し説明します。
<% if @user.errors.any? %> ... <% end %>まず一番外側を囲っている部分です。
any?
メソッドは対象が"空"でないかどうかを検証して「空でない」場合にtrue
を返します。
今回は@user.errors
に対してany?
メソッドを適用しているので、validationによるエラーがある場合にtrue
になります。<div class="alert alert-danger"> <ul class="mb-0"> <% @user.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div>
@user.errors.any?
がtrue
の場合にはこの部分が表示されることになります。
ul
タグはリストを表示するためのタグですね。li
タグがul
タグのアイテムとして『・』を頭につけた箇条書き形式で表示されるようになっています。
li
タグは以下のコードに囲まれています。<% @user.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %>
@user.errors.full_messages
はバリデーションの回でも使ったので覚えている人が多いと思います。
バリデーションでエラーが起きた時にユーザーにそのまま見せれるようなエラーメッセージが配列で格納されていたやつです。
それをeach
でひとつずつ取り出し、msg
に格納して、@user.errors.full_messages
がなくなるまでブロックの中の処理を繰り返します。
ブロックの中の処理は<li><%= msg %></li>
だけなので、ここで@user.errors.full_messages
のエラーメッセージを一つずつli
タグで囲って表示してあげていますね。
結果として、全てのエラーメッセージが箇条書きの形式で表示されるようになると期待できます。ここまでできたら実際に動作確認をしてみましょう!
動作確認(エラー編)
まずはエラーの場合の動作確認をしてみます。
以前Userモデルのバリデーションを確認したときのように、いくつかのエラーケースでエラーメッセージが表示されるかどうかを確認していきましょう。存在性チェック
Userモデルでは
name
、password
全てが入力必須(presence
)な項目です。
何も入力していなければエラーになるはず。
実際に何も入力せずに「Sign up!」ボタンを選択したページがこちらです。
「お名前」「メールアドレス」「パスワード」について、それぞれエラーが出ていてUserの作成がうまくいかなかったことがわかりますね。文字数チェック
name
と
それ以上の文字数でエラーになるか確認してみましょう。51文字と256文字の文字列は↓をお使いください。
Name aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Email bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb@sample.com
文字数制限のエラーが出ていますね。
ちなみに「パスワード」には適当にパスワードを入力して「Sign up!」ボタンを選択したので「パスワード」に関するエラーは出ていないです。「パスワード」はtype="password"
のフィールドを使っているので、エラー時に元の値が反映されないようになっているんですね。フォーマットチェック
ちゃんとエラーになっていますね。重複チェック
最後に
とりあえず
john@sample.com
の
前回までに作ったユーザーなどがいればそれを使っていただいても構いません。> User.create(name: "John Smith", email: "john@sample.com", password: "password")ユーザーを作ったので、同じメールアドレスを大文字とかにしてもエラーになるかを確認してみましょう。
ここまでチェックすれば、バリデーションはちゃんと効いていて、バリデーションエラーが起きた時のエラーハンドリングも正常に動作していることが確認できましたね。
動作確認(正常編)
ではいよいよユーザーを実際にUIから作ってみましょう。
今回は以下のユーザーを作ってみます。
name: Taro Tanaka email: taro@sample.com password: taro1234
ユーザー詳細ページに遷移しましたね!さらに今入力したユーザー情報もちゃんと表示されています!Welcomeメッセージを表示する
ユーザーが作成されて、ユーザー詳細ページにも遷移できたのですが何か物足りないですね。
そうだ、Welcomeメッセージがないんだ。ユーザー詳細ページは、Welcomeページというわけではないので今のまま装飾していけばいいのですが、会員登録した時に限ってでも「ようこそ!」みたいなメッセージがほしいですよね。
こういう一時的にページにメッセージを表示したいときに使えるRailsの機能として
flash
があります。
flash
はControllerで設定してあげます。今回はcreate
アクションでsave
に成功した時に表示されるようにしてみましょう。
create
アクションを通ってshow.html.erb
が表示された場合はWelcomeメッセージが表示されますが、通常show.html.erb
が表示される場合はcreate
アクションは通らずshow
アクションだけを通るので、例えばリロードすればメッセージが消えるという寸法です。app/controllers/users_controller.rb... def create @user = User.new(user_params) if @user.save # 以下の1行を追加する flash[:success] = "サインアップありがとう!" redirect_to user_path(@user) else render :new end end ...Controller側の設定はこんな感じです。
flash
に[:success]
のような形でメッセージのkey
を定義して= 文字列
の形でvalue
を与えます。View側でこれを受け取って、
flash
がある場合だけ表示するように、show.html.erb
も更新しましょう。app/views/users/show.html.erb<div class="container my-5"> <%# ここから追加 %> <% flash.each do |msg_type, msg| %> <div class="alert alert-<%= msg_type %>"><%= msg %></div> <% end %> <%# ここまで追加 %> <%= @user.name %> <br> <%= @user.email %> </div>今回は
flash[:success] = "サインアップありがとう!"
と定義しているので、msg_type
にsuccess
が、msg
にサインアップありがとう!
が格納されます。
alert-<%= msg_type %>
はalert-success
となるわけですね。Bootstrapでalert-success
のCSSが用意されているのでそれを適用するためにflash
のkeyをsuccess
にしていたわけです。
おんなじようにエラー系のメッセージにしたい場合はdanger
にしてあげたりするとViewファイルをいじらなくてもエラーっぽいCSSを適用することができます。では実際に試してみましょう。
次は花子さんを作ってみます。
http://localhost:3000/sign_up
にアクセスして以下のデータで登録してみましょう。Name: Hanako Yamada Email: hanako@sample.com Password: hanako1234この状態でリロードしてみてください。
メッセージが消えましたね。期待通りの動作です。パスワードの表示非表示を制御する
あとそうだ。先ほどUX的に
password_confirmation
は使いませんという話をしました。
しかし、今のままではパスワードが非表示しか対応していないので、ユーザーは自分の思ったパスワードが正しく入力できているか確認できません。
ただ、周りから見えないようにするのが目的でマスク化しているので、常に平文にすることもUX的によろしくないでしょう。ということで、「パスワードを表示する」チェックボックスを用意して、チェックが入っている間だけ表示されるようにしようと思います。
まず、new.html.erb
にチェックボックスを追加します。
今回は@user
に紐づかないフォーム要素になるのでcheck_box_tag
を利用します。これはinput type="check_box"
タグを作ってくれるやつです。app/views/users/new.html.erb... <div class="form-group"> <%= form.label :password %> <%= form.password_field :password, class: "form-control" %> </div> <div class="form-check"> <%= check_box_tag :visible_password, :visible, false, class: "form-check-input" %> <%= label_tag :visible_password, "パスワードを表示する" %> </div> ...↓
... <div class="form-group"> <label for="user_password">パスワード</label> <input class="form-control" type="password" name="user[password]" id="user_password"> </div> <div class="form-check"> <input type="checkbox" name="visible_password" id="visible_password" value="visible" class="form-check-input"> <label for="visible_password">パスワードを表示する</label> </div> ...ただ今のままではただのチェックボックスにチェックを入れたり外したりできるだけです。
このチェックボックスの状態に合わせて「パスワード」のフィールドをマスク化したりマスク解除したりしていきましょう。
どうやるかというと、今マスク化されているのはinput
のtype
がpassword
になっているからです。他のinput
のフィールドは普通に文字が見えていますが、これはtype
がtext
になっているからです。
なので、チェックボックスの状態に合わせて、チェックが入っている場合はtype="text"
、チェックが入っていない場合はtype="password"
と切り替えることができれば、パスワードの表示非表示を制御できるはずです。これを実装するには、フロントエンドで動作するjavascript(jQuery)を使います。
ごちゃごちゃするといけないので、
application.js
ではなくファイルを追加してそちらでコーディングしていきましょう。# touch app/javascript/packs/visible_password.jsapp/javascript/packs/visible_password.js$(function() { $("#visible_password").change(function() { type = "password" if ($(this).prop("checked")) { type = "text" } $("#user_password").attr("type", type) }) })まず、型として
$(function() { ~ })
で囲みまして、{}
の中に処理をコーディングしていきます。$("#visible_password").change(function() { ... })最初に
$("#visible_password").change
と書きました。これはid
がvisible_password
のinput
タグに変化が起きたときに処理されることを意味しています。こういった何かが起こったときに処理が実行されることを『トリガー』とか『発火する』とか言うので覚えておきましょう!
今回の場合はid
がvisible_password
のinput
の変化をトリガーにする、とか、変化が起きた時に発火する、みたいな表現をするってことです。type = "password"処理の中をみると、まず最初に
type = "password"
の変数定義をしていますね。if ($(this).prop("checked")) { type = "text" }その後、
if ($(this).prop("checked"))
の条件分岐を書いています。
$(this)
はjQueryの特殊な書き方だと思いますが、トリガーの元になった要素のことです。
prop("checked")
はその要素のチェックボックスがチェックされているかを取得するメソッドなので、$(this).prop("checked")
はvisible_password
のチェックボックスにチェックが入っていればtrue
、そうでなければfalse
になります。
つまりif
文の部分は、「チェックボックスにチェックが入っていればtype
変数を"text"
に更新する」、ことが記述されています。$("#user_password").attr("type", type)最後に、
$("#user_password")
、つまりid
がuser_password
の要素(パスワードのinput
タグ)にattr("type", type)
をしています。
attr
はその要素の属性を取得したり更新したりするメソッドです。引数が2つの場合は1つ目の引数の属性を2つ目の引数の値に更新します。今回の場合はid="user_password"
のtype
を変数type
に更新しています。変数
type
はデフォルトではpassword
、チェックボックスにチェックが入っている場合はtext
になるので、チェックボックスにチェックを入れるとパスワードが表示される仕組みです。さて、実際に使えるようにするには、このファイルを読み込めるようにする必要があります。
このファイルはアプリケーションの全てのページで使うのではなく、Sign upページでのみ利用するようなファイルなので、new.html.erb
で読み込みを定義してあげます。app/views/users/new.html.erb... <%= javascript_pack_tag 'visible_password' %>Sign upページをリロードして試してみましょう!
チェックなし??チェックあり
期待通りの動作になりましたね!
トップページからリンクさせる
最後にトップページの「Sign up now!」ボタンからSign upページにリンクを貼ってあげましょう。
前回時点では
app/views/static_pages/home.html.erb
の該当のボタンのコードは以下のようになっていますね。app/views/static_pages/home.html.erb... <%= link_to "Sign up now!", "#", class: "btn btn-lg btn-primary mt-5" %> ...この
"#"
の部分がリンク先になるので、これをルーティングで名前づけしたsign_up_path
に更新します。app/views/static_pages/home.html.erb... <%= link_to "Sign up now!", sign_up_path, class: "btn btn-lg btn-primary mt-5" %> ...はい、これで完了です!
トップページ(http://localhost:3000/
)にアクセスして「Sign up now!」ボタンをクリックしてみましょう。ちゃんとSign upページに遷移するはずです。後片付け
いつものように、次回に向けてデータを消します。
$ docker-compose down $ docker-compose run --rm web rails db:migrate:resetDBコンテナが立ち上がった状態だと思うのでdownさせます。
$ docker-compose downまとめ
今回は、サインアップページとユーザー登録機能を作っていきました。
今までと比べると少し複雑なControllerのコーディングをしましたね。バリデーションの結果に合わせてエラーメッセージを表示させてみたり、登録完了後のウェルカムメッセージを表示させたりしてみました。また、jQueryを使ってパスワードの表示非表示をクライアントサイドで変更するコーディングもやってみました。
jQuery(javascript)はWebアプリケーションを作る上では欠かせない技術ですのでぜひ覚えてくださいね。さて、今回はユーザー登録はできたものの、サインイン(ログイン)してそのユーザー独自の機能を提供する、ということはできていません。例えば、今のまま開発を進めてしまっては誰もが全てのユーザーの情報をみれてしまったり更新できてしまったりします。
そこで次回は、セッション管理をすることでサインイン機能を実装してみようと思います。では、次回も乞うご期待!ここまでお読みいただきありがとうございました!
Reference
- Ruby on Rails チュートリアル:実例を使って Rails を学ぼう
- 登録フォームにおけるパスワード確認用の入力欄は必要か | UX MILK
- Action Controller の概要 - Railsガイド
- jQuery 属性値を取得/設定/削除する(attr/removeAttr) | ITSakura
- jQueryでチェックボックスのチェック状態を取得する (jQuery + JavaScript プログラミング)
Links
・ Vol.1 - Introduction -
・ Vol.2 - Hello, Rails on Docker -
・ Vol.3 - Scaffold, RESTful, MVC -
・ Vol.4 - Static pages -
・ Vol.5 - Model and CRUD -
・ Vol.6 - Model validation -
・ Vol.7 - Secure password -
・ Vol.8 - Sign up - ?この記事
- 投稿日:2020-02-18T22:40:44+09:00
RailsアプリをMySQLで作成してherokuへデプロイする。
今回は初めからMySQLでRailsアプリを作成してherokuへデプロイする手順です。
こちらの記事を参考に進めました。
RailsDBをMySQLに変更してHerokuでデプロイまでする手順ありがとうございました。ほぼこの通りにすれば完璧です。自分はデプロイするときにいくつか詰まったところがあったので記載していこうと思います。
MySQLでRailsアプリを作成
こちらの記事を参考にRailsアプリのDBをMySQLにします。
【Rails/MySQL】RailsにMySQLを導入する方法【プログラミング学習149日目】
多少詰まりますがエラーメッセージ見ながら進めれば
rails s
できると思います。上記記事の①から⑥まで進める。
③は割愛。④は
heroku config
で出てきます。入力ミスに気をつけてください。この通りに進めてできなければ他の記事を参考にしてください。(クレジットカードが登録されてないパターンもある)デプロイ時
$ git push heroku master ~ error: unable to rewind rpc post data - try increasing http.postBuffer error: RPC failed; curl 56 LibreSSL SSL_read: SSL_ERROR_SYSCALL, errno 54 fatal: the remote end hung up unexpectedly Writing objects: 100% (8167/8167), 29.25 MiB | 54.00 KiB/s, done. Total 8167 (delta 988), reused 0 (delta 0) fatal: the remote end hung up unexpectedly Everything up-to-date調べたらgitのbufferが足りないということでした。容量を増やすか、既存のアプリを削除するかして突破できます。自分は他のアプリを削除しました。
デプロイ後
heroku run rake db:migrate
でheroku open
できました!と思ったらエラー発生。logを見たら記事投稿時にエラーになってました。
ローカルのフォルダからpushするとcssが反映されないことがあるらしいです。
/config/environments/production.rbconfig.assets.compile = true <=最初はfalseになってるこれで解決しました。
heroku open
できました。お疲れ様でした。参考
・RailsDBをMySQLに変更してHerokuでデプロイまでする手順
・【Rails/MySQL】RailsにMySQLを導入する方法【プログラミング学習149日目】参考にさせていただきありがとうございました。
- 投稿日:2020-02-18T22:16:10+09:00
rubyのdeviseを後付けで、ユーザー登録エラーNo route matches [POST] "/people/sign_up.person"の解決方法
deviseを最初からインストールしている記事はあるものの、追加でしかもmodel名のuserを使わない記事が皆無だったので後学者の為に。
環境
ruby 2.6.3
rails 5.2.4作業時間を報告するアプリを作成。
先にpersonをmodelとして、複数形としてpeopleを使用。
一応これで課題は終了。応用追加課題として、先のアプリに後付けで、
ログイン機能のdeviseを追加実装。以下状況
gem deviseとdevise viewをインストールし、devise controllersはインストールせず。
personモデルはそのままにして、deviseのuserモデルのカラムを利用する為、userモデルを一度インストール。
インストールしたuserのmigrationファイルに記載されているカラムとfirst_name&second_nameを追加してファイル名をrenameし、migrate。
利用し終わったので、userモデルは削除。ログイン画面と登録画面を実装して、動作確認時にエラー
エラー文
No route matches [POST] "/people/sign_up.person"
該当箇所
registration/new.html.haml= form_for(resource, as: resource_name, url: new_person_registration_path(resource_name)) do |f|devise/shared/_links.html.haml- if devise_mapping.registerable? && controller_name != 'registrations' = link_to "Sign up", new_registration_path(resource_name)$ rails routesnew_person_registration GET /people/sign_up(.:format) devise/registrations#new edit_person_registration GET /people/edit(.:format) devise/registrations#edit person_registration PATCH /people(.:format) devise/registrations#update PUT /people(.:format) devise/registrations#update DELETE /people(.:format) devise/registrations#destroy POST /people(.:format) devise/registrations#createcreate画面に飛ばすべき所をnewパスにしていた。
registration/new.html.haml= form_for(resource, as: resource_name, url: person_registration_path(resource_name)) do |f|path修正
devise/shared/_links.html- if devise_mapping.registerable? && controller_name != 'registrations' = link_to "Sign up", new_registration_path(resource_name)
こちらもルーティングに従い修正(person追加)
- if devise_mapping.registerable? && controller_name != 'registrations' = link_to "Sign up", new_person_registration_path(resource_name)修正するも次のエラー分
ActionController::UnknownFormat in Devise::RegistrationsController#new
受け取るパラメーターをfirst_nameとsecond_nameを指定していなかった為
こちらを参考にして、
https://aliceblog1616.com/devise_parameter_sanitizer%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%A8%E3%81%AF%EF%BC%9F/class ApplicationController < ActionController::Base before_action :authenticate_person! before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :second_name]) devise_parameter_sanitizer.permit(:sign_in, keys: [:first_name, :second_name]) devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :second_name]) end enddeviseのcontrollersをインストールしてないが、deviseが裏で作動しているので、if: :devise_controller?も記述。
エラー分変わらず。
ActionController::UnknownFormat in Devise::RegistrationsController#new
registration/new.html.haml= form_for(resource, as: resource_name, url: person_registration_path(resource_name)) doから
(resource_name)を消す。registration/new.html.haml= form_for(resource, as: resource_name, url: person_registration_path) do |f|修正
$ rails s再起動忘れずに。
無事開通!動作確認する前にroutesでしっかりpath確認して、parameterで追加カラムを指定する。
この工程を忘れやすいので、改めていい勉強になりました。
- 投稿日:2020-02-18T21:41:27+09:00
Rails 7つのアクション以外
7つのアクション以外でルーティングを設定する方法を説明します。
検索フォームを作成する場合、searchアクション等を利用。7つのアクション以外でルーティングを設定する方法は2つある。
collectionとmember
collectionはルーティングに:idがつかない、memberは:idがつく。
#collectionで定義 Rails.application.routes.draw do resources :tweets do collection do get 'search' end end end#collectionのルーティング Prefix Verb URI Pattern search_tweets GET /tweets/search(.:format) tweets#search#memberで定義 Rails.application.routes.draw do resources :tweets do member do get 'search' end end#memberのルーティング Prefix Verb URI Pattern search_tweet GET /tweets/:id/search(.:format) tweets#search
- 投稿日:2020-02-18T21:19:30+09:00
Rails deviseヘルパーメソッド
user_signed_in?
ユーザーがサインイン済みかどうかを判定する
例 elseの時はサインインしていない場合 app/views/layouts/application.html.erb <div class="header__right"> <% if user_signed_in? %> <%= link_to "新規投稿", new_post_path, class: "header__right--btn" %> <%= link_to "ログアウト", destroy_user_session_path, method: :delete, class: "header__right--btn" %> <% else %> <%= link_to "ログイン", new_user_session_path, class: "header__right--btn" %> <%= link_to "新規登録", new_user_registration_path, class: "header__right--btn" %> <% end %> </div>current_user メソッド
サインインしているユーザーを取得する。もし、サインイン中のユーザーidを取得したい場合、current_user.idと記述することで取得できる。
merge メソッド
2つのハッシュを結合することができる。
private def post_params params.require(:post).permit(:title, :content).merge(user_id: current_user.id) endconfigure_permitted_parameters メソッド
deviseでは初期状態でサインアップ時にメールアドレスとパスワードのみを受け取るようにストロングパラメーターが設定してあるので、追加したキー(nickname)のパラメーターは許可してない。
なので追加のパラメーターを許可したい場合は、application_controller.rbにおいてbefore_actionにconfigure_permitted_parametersメソッドを設定する。class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname]) end end上記のように記載すればnicknameも許可される。
before_action :authenticate_user!
コントローラーに設定して、ログイン済ユーザーのみにアクセスを許可する。以下の記載ならばshowはログインユーザーのみ実行可能となる。
class ArticlesController < ApplicationController before_action :authenticate_user!, only: [:show] def index end def show end end
- 投稿日:2020-02-18T20:54:07+09:00
[初歩なこと]画像投稿をしたらGithubに大量の画像が上がっちゃうのを阻止したい時
画像投稿機能をつけるときにやっておくこと
投稿した画像のデータを保存する必要がないとき、
ディレクトリの.gitignore
というファイルに以下を記入する。.gitignore#末尾に追記 public/uploads/*完了です
gitignoreとは?
コミットしたくないファイル・ディレクトリを指定できる設定ファイルのことです。
通常画像投稿の機能をつけると画像は自動的にpublic/upload
というディレクトリに
格納されます。
そこで、このファイル名をgitignoreへ追加しておくことでgithubへ画像がコミットされなくなるということです。(コミットされないだけで画像自体はフォルダへ入ってきますが。)終わりに
gitignoreのことすっかり忘れて、コミットの時に大量の画像に危く履歴を圧迫されそうになりました。
備忘録として残しておこうと思います。
- 投稿日:2020-02-18T19:52:11+09:00
RspecでDevise認証を使ったテストを行う方法【Rails5編】
背景
私は現在、渋谷の某プログラミングスクールに通っている。
チーム開発では、アジャイル開発と呼ばれるモダンな開発手法をスクラムを用いてチーム開発を行い、チームでECサイト(メルカリ)のクローンアプリを開発した。
その開発工程の中でRspecでDevise認証を使ったテストを行ったのだが、Rails5でこれを行う方法を簡潔にまとめられている記事がなかったので、これを機にアウトプットします。参考記事
rspecのテスト環境でdeviseにログインする方法【rails】
こちらに大まかな実装の流れを分かりやすく解説して頂いていたので、共有させていただきます。
やりたいこと
上記、参考記事に書かれている方法をRails5でも行えるようにする。
実装
参考記事と照らし合わせながら下記の実装解説をお読みください。
1. support配下を読み込み可能にする
spec_rails_helper.rb (修正前)# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
spec_rails_helper.rb (修正後)Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }コメントアウトのままだとsupport配下が読みこめていないのでコメントアウトを解除。
2. controller_macrosの作成
spec/support/controller_macros.rb (修正前)module ControllerMacros def login_admin(admin) @request.env["devise.mapping"] = Devise.mappings[:admin] sign_in admin end def login_user(user) controller.stub(:authenticate_user!).and_return true @request.env["devise.mapping"] = Devise.mappings[:user] sign_in user end endspec/support/controller_macros.rb (修正後)module ControllerMacros def login_admin(admin) @request.env["devise.mapping"] = Devise.mappings[:admin] sign_in admin end def login_user(user) allow(controller).to receive(:authenticate_user!).and_return(user) @request.env["devise.mapping"] = Devise.mappings[:user] sign_in user end end8行目に注目してください。修正前はstubと書かれていますがこのままだとエラーが出ちゃうので変更。
3. deviseのtest_helperとmacrosをcontroller内で使えるようにする
spec_rails_helper.rb (Rails5未満)RSpec.configure do |config| config.include Devise::TestHelpers, type: :controller config.include ControllerMacros, type: :controller endspec_rails_helper.rb (Rails5)RSpec.configure do |config| config.include Devise::Test::ControllerHelpers, type: :controller config.include ControllerMacros, type: :controller end3行目に注目してください。config.include Devise::TestHelpers, type: :controllerはRails5からはこの書き方は廃止されたのでconfig.include Devise::Test::ControllerHelpers, type: :controllerに変更。以上です。
- 投稿日:2020-02-18T19:44:18+09:00
each_with_objectでwith_indexしたい
- 投稿日:2020-02-18T17:47:05+09:00
Rails 日時フォーマットにI18nを使うときはレコード数に注意
[追記] 以下の内容ですが、違った可能性があります。ja.yamlの初回読み込みに時間がかかり、2回目以降はキャッシュが使われ早くなるという可能性があります(未検証)
日付・日時のフォーマットにI18nを使用していたところ、処理時間がだいぶかかってしまいました。
そこで
- I18n#l
- Time#to_s
- Time#strftime
の処理時間を調べてみました。
I18nに関してはこちら測定
time = Time.now sum_i18n = 0 sum_to_s = 0 sum_strftime = 0 # I18n#lの測定 100.times do s = Process.clock_gettime(Process::CLOCK_MONOTONIC) I18n.l(time) e = Process.clock_gettime(Process::CLOCK_MONOTONIC) sum_i18n += e-s end # Time#to_sの測定 100.times do s = Process.clock_gettime(Process::CLOCK_MONOTONIC) time.to_s e = Process.clock_gettime(Process::CLOCK_MONOTONIC) sum_to_s += e-s end # Time#strftimeの測定 100.times do s = Process.clock_gettime(Process::CLOCK_MONOTONIC) time.strftime("%a %b %d %H:%M:%S %z %Y") e = Process.clock_gettime(Process::CLOCK_MONOTONIC) sum_strftime += e-s end結果
I18n#l [s] Time#to_s [s] Time#strftime [s] 1回目 0.8247481999860611 0.002034699995419942 0.0011146999459015206 2回目 0.9185206999682123 0.0023584999435115606 0.0014091000193729997 3回目 0.8858548999996856 0.0011633000249275938 0.0014278999879024923 I18nは圧倒的に遅いですね。
レコード数が多い時はTime#strftimeを使った方が良さそうです。
- 投稿日:2020-02-18T17:31:48+09:00
お前らまだ引数に順番指定してんの?
はじめに
vueとnuxtの記事も書こうかなあ、、、
お前らのプロジェクト壊れる可能性あるぞ
先日、仕事中に学んだこと。
インスタンス変数を作成するためにinistializeメソッドを活用していた際に今までの自分は引数の順番に依存していました。Human.rbclass Human attr_render :name, :age, :sex def initialize(name, age, sex) @name = name @age = age @sex = sex end 〜省略〜 end Human.new('Taro',20,'male')この例では、Humanのinitializeメソッドは次の3つの引数を取ります。name, age, sexの3つですね。
つまりHuman.newでインスタンスを作成するところでは引数を3つ渡しています。
まあ教科書通りのinistializeメソッド及び引数の使い方ですね。
しかしこの方法には大きな欠点があります。
- 引数を順番に渡さなければならない
- 3つの引数をもれなく、だぶりなく渡さなければならない
この引数の使い方は小規模かつ個人での開発なら何ら問題有りません。
自分が作成したインスタンスなので勝手はわかっているし、他のクラスとの依存関係も頭に入っているはずです。
小規模の開発なら変更も少ないですし、この仕様が変わることはないかもしれません。しかし、大規模な開発かつチームでの開発だったらどうでしょう?
チームでの開発/実務レベルでの大規模な開発では常に変更を考えて実装しなければなりません。
プログラムに機能が追加されたり、改修要望が入った際には、インスタンスの引数の数が変わるかもしれないし、
そもそも既存のインスタンス変数が削除されるかもしれません。
また、この一つのインスタンスだけなら良いですが、別のクラスでHumanクラスのインスタンスを作成していた場合その箇所をすべて直さなければなりません。(10箇所の変更とか普通にあります、、、)
この書き方ではまずそうですね、、、。ではどのように書きましょう?
引数にハッシュを使う
先程述べた「引数の順番固定」を簡単に回避する方法があります。
ハッシュです!!!Human.rbclass Human attr_render :name, :age, :sex def initialize(args) @name = args[:name] @age = args[:age] @sex = args[:sex] end 〜省略〜 end Human.new(name: 'Taro', age: 20, sex: 'male')このテクニックにはいくつかの利点があります。
- 引数の順番依存を取り除ける
- 変更に強い
- key名が明示的なドキュメントになってくれている
この方法のおかげでどんなに引数を変更しても他のコードに対する副作用がなくなりました。
よって、仕様変更の際になんの気兼ねもなく引数の追加や除去ができます。
安心感がすごいです。
またkey名がなんの情報を渡しているのかを示してくれているため、
インスタンスを生成する際にとてもわかりやすいですね。その他のテクニック①
Human.rbclass Human attr_render :name, :age, :sex def initialize(args) @name = args[:name] || 'Jiro' @age = args[:age] || '10' @sex = args[:sex] || 'male' end 〜省略〜 end Human.new(name: 'Taro', age: 20, sex: 'male')||メソッドを使用することでデフォルト値を設定することができます。
||メソッドはor演算子と同様に作用します。
左辺を評価し、その結果がfalseまたはnilであれば右辺の評価に移ります。
こうすることで引数に値を入れ忘れたとき(意図的に入れないとき)でもインスタンス変数を生成することができるでしょう。
例えば「sexの値はほとんどの人がmaleだな」と思えば@sex = args[:sex] || 'male'と設定しておくだけでインスタンス生成時に引数を渡さなくても良くなります。
その他のテクニック②
Human.rbclass Human attr_render :name, :age, :sex def initialize(args) args = defaults.merge(args) @name = args[:name] @age = args[:age] @sex = args[:sex] end 〜省略〜 def defaults {name: 'Jiro', age: 10, sex: 'male'} end endこの方法もデフォルト値を設定するのに大変役立ちます。
隔離テクニックとでも名付けましょうか。
defaultsメソッドを設定し、initializeメソッド内で呼び出しています。
この方法は特にデフォルト値が長いときや複雑な時に活用すべきです。
コードの可視性が高まりますね。終わりに
プログラムは普遍的なものではありません。
常に変更と改善の繰り返しです。
変化に強いコードを書けるスキルは今の時代(アジャイルでの開発が主流になってきた時代)、必須のスキルと言っても過言ではありません。
あなたのコードがチームメンバーに多くの手間と工数をかけさせるかもしれません。
ひどいときにはプログラム自体を破壊してしまう可能性もあるのです。
ただ動くだけではなく、本当に"良いコード"を書けるように一緒に邁進しましょう!!!(今回はちょっと真面目に書きすぎたな、、、)
参考
オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方
Sandi Metz (著), 髙山泰基 (翻訳)
- 投稿日:2020-02-18T16:18:32+09:00
Routing Error : uninitialized constant ◯◯Controller解決出来ない。
コントローラちゃんと作ってルーティングしたのに!?
今日のメモは、きちんと設定できてるはずなのに、何故かルーティングエラーが出て、検索しまくるハメになってしまった話です。
解決までの流れ
まずは、テーブル からご紹介。
novel_listsテーブル novel_postsテーブルこの二つを使って、作成画面である、new.html.erbを作っていた訳ですが。
resources novel_lists only: ・・・・略 do
resources novel_posts only: ・・・・・略
endnovel_listsのnewアクションのnew.html.erbファイルにてformを作り。
createアクションでsaveされ、novel_postsのnewアクションのnew.html.erbに飛ぶ。こんな流れで
@novel_list = current_user.novel_lists.build(novel_list_params) if @novel_list.save flash[:success] = 'タイトルを作成しました' redirect_to new_novel_list_novel_post_path(@novel_list) else flash[:danger] = '作成に失敗しました。' render :new end end作っていました。
飛んだ直後にエラーが。
Routing Error : uninitialized constant NovelPostsController
!!??ちゃんとルーティング設定したはず・・・
rails routesで確認してもルーティングはしっかりと出来ています。
new_novel_list_novel_post GET /novel_lists/:novel_list_id/novel_posts/new(.:format) novel_posts#new
何故だ・・・と色々な所をチェックしていくが、治らない。
仕方なくネット検索をかけ、同じようなエラー記事をみて行く。
しかし、中々、解決に至る記事を見つけられない。その中で、見つけたのが
http://blog.livedoor.jp/tokyo_kinako/archives/21045311.html
このブログ記事。コントローラを作った際に
rails g controller NovelPost (s) 複数形にしていない事で起きた。と書かれていた。
複数形にしたつもりではいたが、まさか。と思って・・・・コントローラをチェックすると。novelposts.controller←ファイル名が違ってる!?
はい、その通りです。
novelposts→正しくは、novel_posts.controllerにならなければいけません。_ ただの棒線1本の違い。違いが細かすぎて出来てると思っている自分には、見えていませんでした。
という事で、今後は気をつけようとメモでした。
同じようなエラーが出た方はまず。
コントローラのファイル名を確認してみてください。
名前が違ったり、単数形になっていたりしているかもしれません。
気をつけて欲しいのは、作り直した場合、viewsファイルと、コントローラの中身は消えますので、
どこかにコピーなどしておくかしないと、書き直しです。では以上となります。!!
- 投稿日:2020-02-18T15:47:08+09:00
Rails tutorialを一周した。&不安しかないんで見てほしいっていう話
さきほどRails tutorialを一周してこれからどうしようかなと思ったので、
ひとまず書いてみることにしました。
長くなるかもしれませんがどうか片手間にお付き合いくださるとうれしいです。次にどうするか
現在大学1年生で、もともと「何か役に立つ物を作ってみてぇ.....」といった理由でプログラミング学習を始めました。
Rubyを少し触っていたこともあり、Rails Tutorialの理解も進み、一周できたということで
いよいよWebアプリの作成にかかりたいと思います。
.....しかしやはりお金も稼ぎたい
プログラミングは学べば学ぶほどできることが増えて、それに伴う達成感もあります。
しかし、やはりお金は必要ッ...!!現実は無常無慈悲であるッ....!!
おまけに文系大学生。ある意味地雷の塊です。
というわけでポートフォリオ等を充足させつつ、
インターン、或いは学生アルバイトやらを現段階、目指す必要があります。
本来なら、自発的な欲求を貫徹させて道筋を立てたいところですが、
社会的な干渉は避けえないものです。
ありがたいことに東京内の大学に在籍させていただいて、インターンを募集している企業様は地域内に数多く、環境には恵まれています。
インターンを視野に入れた、実践的技術を用いたプロダクトを作成することが要になりそうです。
......ですがDockerが使えない
まず最初に思いついた実践技術がDockerだったので、試してみることにしました。
この、一年間を共にしてきたWindowsならどこまでも行ける。そう意気揚々に信じていました。
Macがおすすめとか知ったもんかい!
こちとらバリバリのWindowsユーザーなんじゃ!Mac怖い!(本心)
しかし、その勢いは早々に裏切られます。
動かない。
いくら参考資料漁って調べて実行しても画面が固まる....。なんでや....。
原因はPCそのものにありました。
自分の所有するPCの弊害
やはりMacは偉大だったようです。ここで引っかかるとは....。
Dockerなどの仮想化技術をWindowsで用いる際、VT-X/AMD-vといったBIOS内の設定が必要なのですが、自分の持っているPCにそもそも装備されていませんでした。
WindowsのPCにもいろいろ機能差があったようで、無知が仇となった瞬間でした...。
Dockerは採用する側の方々から重要視されるとよく目にしていたので、ショックでした...。ひとまず何をするべきか
ここまで紆余曲折ありましたが、自分のレベルを過大評価して、焦ってはいけません。
僕はまだ初心者。仕方ない。そう考えていったん落ち着くことにしました。
では、どうするか。
ひとまず、最初の目標である「役に立つもの」を作りたい。
この思いは何よりも大切な、内発的な動機です。
なのでこの動機で自らを動かすことにしました。
そして何を作りたいか考えました。これから作るもの
結論として、学校の評価をすることができるSNSのようなものを作ってみたいと思いました。
その根拠として、この一年の大学生活から、授業の当たりはずれというものは意外と大きく、
個人的に苦労したというのがあり、学生アンケートはあるのですが、
フィードバックが少ない、或いは目にできる機会がないということで、授業の情報蓄積をしつつ、授業の概要を履修登録前に知れたら便利だな~と感じたからです。
ひとまずはRails Tutorialの2週目をしながら、触れることのなかったSlim, Rspec等のgemやVue.js等を使用してアプリ作成をしようと思います。
学生のくせに授業に文句を言うな勉強しろという意見は至極当然ですすいません!最後に
ここまでご覧いただきありがとうございました。
東京在住の一学生の、不安を書き綴った技術発信の場にそぐわない記事ですが、
同じような状況にいる方々、あるいはこの記事にふらりと来てくださった方が面白いなと感じてくださったら幸いです。
上記内では述べませんでしたが、渋谷、世田谷近辺の勉強会にも参加できたらいいなあと考えています!
ご精読ありがとうございました!
- 投稿日:2020-02-18T15:28:13+09:00
【Ruby】大文字→小文字変換(アッパーケース→キャメルケース)
用意されているメソッド
大文字・小文字変換に使えるもの
upcase
全部大文字に変換
'abc'.upcase # => ABCdowncase
全部小文字に変換
'ABC'.downcase # => abccapitalize
最初の文字を大文字に、他を小文字にする
'abc'.capitalize # => Abcswapcase
小文字と大文字の入れ替え
'AbCd'.swapcase # => aBcDcamelize
キャメルケースに変換する。通常はアッパーキャメルケース。
'john_do'.camelize # => JohnDo引数に
:lower
を指定するとローワーキャメルケースになる'john_do'.camelize(:lower) # => johnDounderscore
スネークケースにする
'JohnDo'.underscore # => john_doアッパーケース → ローワーキャメルケースへの変換
メソッドを組み合わせれば可能
"UPPER_CASE".downcase.camelize(:lower) # -> upperCase参考
- 投稿日:2020-02-18T14:44:04+09:00
dockerで環境構築する際にrails5.2.0環境以降でcredential.ymlを編集する方法
はじめに
初投稿です。よろしくお願いします。
忘備録として投稿します。内容
docker-compose.ymlにvimを入れてインストールしたはずなのにcredential.ymlを編集しようとしても暗号化されたまま編集できませんでした。
他にも方法があるかもしれませんが、全くの初心者レベルの人が解決できると仮定してその道筋を投稿します。開発環境
docker 19.03.5
docker-compose 1.25.4
rails 5.2.4.1
ruby 2.5.1
nginx 1.15.8
Mysql 5.7docker-compose.yml
docker-compose.ymlversion: '3' services: app: &app_base build: context: . env_file: - ./environments/db.env command: bundle exec puma -C config/puma.rb volumes: - .:/webapp - public-data:/webapp/public - tmp-data:/webapp/tmp - log-data:/webapp/log depends_on: - db tty: true stdin_open: true db: image: mysql:5.7 env_file: - ./environments/db.env volumes: - db-data:/var/lib/mysql ports: - "4306:3306" web: build: context: containers/nginx volumes: - public-data:/webapp/public - tmp-data:/webapp/tmp ports: - 80:80 depends_on: - app volumes: public-data: tmp-data: log-data: db-data:Dockerfile
FROM ruby:2.5.1 # リポジトリを更新し依存モジュールをインストール RUN apt-get update -qq && \ apt-get install -y build-essential \ nodejs \ vim # ルート直下にwebappという名前で作業ディレクトリを作成(コンテナ内のアプリケーションディレクトリ) RUN mkdir /webapp WORKDIR /webapp # ホストのGemfileとGemfile.lockをコンテナにコピー ADD Gemfile /webapp/Gemfile ADD Gemfile.lock /webapp/Gemfile.lock # bundle installの実行 RUN bundle install # ホストのアプリケーションディレクトリ内をすべてコンテナにコピー ADD . /webapp # puma.sockを配置するディレクトリを作成 RUN mkdir -p tmp/socketsdocker-compose build→up -d
コンテナをbuildしてvimインストールして起動したが、あれ? credential.yml編集できない...
なぜだ....
vimインストール出来ているか見てみよう!
作業ディレクトリでwhich vimコマンド
which vim /usr/bin/vimインストールはされているな.....どうやって起動すれば良いんだ
コンテナの中に入ってみよう
コンテナの中に入ればできるかも....
docker-compose exec app bash ⬆️docker-composeのrails名そうするとroot@というところに入るので以下のコマンドを打ちましょう
EDITOR=vim bin/rails credentials:editcredentialに入れた!
credentials.yml.enc# aws: # access_key_id: 123 # secret_access_key: 345 # Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies. secret_key_base: 8be8e637d755f79c799048bed8be0c...最後に
手順を書いてある記事が少なかったので少しでも参考になればと思います。
何かあればご意見ください!
- 投稿日:2020-02-18T14:14:27+09:00
[Rails]FullCalenderでカレンダー機能の実装
実装すること
①マイページで予定管理ができるようにする
②日付をクリックで予定の作成・編集をできるようにする
※Userモデル等は作成した前提で進めていきます。FullCalenderとは
オープンソースのカスタマイズ可能なjqueryのカレンダーライブラリです。
上手く活用することで、カレンダーのスクラッチ開発をせずにリッチなカレンダーを表示できます。ER図
モデルの作成
$ rails g model Event title:string body:text disp_flg:boolean start:datetime end:datetime allDay:stringアソシエーションの確認
app/models/user.rbclass User < ApplicationRecord has_many :events endapp/models/event.rbclass Event < ApplicationRecord belongs_to :user endダウンロード
FullCalenderの公式ドキュメントからダウンロードし、zipを解凍します。
https://fullcalendar.io/Gemの追加
Gemfile.gem 'jquery-rails', '4.3.3' gem 'fullcalendar-rails' gem 'momentjs-rails'$ bundle inatall読み込み
application.htmlのhead内で読み込みます。
app/views/layouts/application.html<head> ~ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/4.2.0/core/main.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/4.2.0/daygrid/main.min.css"> ~ </head>app/assets/javascripts/application.js//= require jquery //= require moment //= require fullcalendar表示する(マイページ)
コントローラー
app/contorollers/users_contoroller.rbdef show @user = User.find(params[:id]) @events = Event.where(user_id: @user.id) @event = Event.new endapp/controllers/events_controller.rbdef create event = Event.new(event_params) event.save! @events = Event.where(user_id: current_user.id) end def update event = Event.find(params[:id]) @events = Event.where(user_id: current_user.id) event.update(event_params) end def destroy @user = User.find(params[:id]) event = Event.find(params[:id]) event.destroy redirect_to user_path(@user) end private def event_params params.require(:event).permit(:title, :start, :end, :user_id, :body) endビュー
予定を表示する・作成する
・
<div id="calendar"></div>
でカレンダーを表示しています。
・予定を編集するときのモーダル内容はパーシャルにします。app/views/users/show.html<h3 class="text-center">カレンダー</h3> <!-- カレンダーの表示 --> <div id="calendar"></div> <!-- もしユーザーがログインしていたら --> <% if user_signed_in? %> <!-- ページのparams.idがログインユーザー.idと同じなら --> <% if @user.id == current_user.id %> <div id="inputScheduleForm" class="modal fade" tabindex="-1"> <div class="modal-dialog modal-nm"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">スケジュール登録</h4> </div> <div class="modal-body"> <%= form_with model: @event, url: events_path do |f| %> <div class="col"> <p> <span>タイトル</span> <span><%= f.text_field :title, class: "form-control", placeholder: "タイトルを入力してください" %></span> </p> <span>開始日時</span> <span><%= f.datetime_field :start, placeholder: "XXXX-XX-XX", class:"field" %> ~ </span><br> <span>終了日時</span> <span><%= f.datetime_field :end, placeholder: "XXXX-XX-XX", class:"field" %></span><br> <span>詳細 <%= f.text_field :body, class: "form-control", placeholder: "タイトルの詳細を記入してください" %></span> </div> <div class="modal-footer"> <%= f.submit "登録する", class: "btn btn-primary" %> <%= f.hidden_field :user_id, :value => current_user.id %> <button type="button" class="btn btn-default" data-dismiss="modal">閉じる</button> </div> <% end %> </div> </div> </div> </div> <!-- 編集 ------------------------------------------------------------------> <div id="inputEditForm"> <%= render 'events/edit', events: @events %> </div> <% end %> <% end %> <script> // CRUDを行う際にCSRF対策のtokenを発行 $(document).ready(function() { var prepare = function(options, originalOptions, jqXHR) { var token; if (!options.crossDomain) { token = $('meta[name="csrf-token"]').attr('content'); if (token) { return jqXHR.setRequestHeader('X-CSRF-Token', token); } } }; } ) // カレンダー表示 $('#calendar').fullCalendar ({ header: { left: 'prev,next today', center: 'month,agendaWeek,agendaDay', right: 'title' }, buttonText: { prev: "<", next: ">" }, timezone: 'UTC', events: '/users/events.json', navLinks: true, selectable: true, selectHelper: true, // 日付クリック dayClick : function ( date , jsEvent , view ) { $('#inputScheduleForm').modal('show'); }, // event クリックで編集、削除 eventClick : function(event, jsEvent , view) { jsEvent.preventDefault(); $(`#inputScheduleEditForm${event.id}`).modal('show'); }, eventMouseover : function(event, jsEvent , view) { jsEvent.preventDefault(); } }) </script>app/views/events/create.js//フォームを空にする $('input[type="text"]').val(''); //モーダルを消す $('#inputScheduleForm').modal('hide'); //作成した予定を差し替える $('#inputEditForm').html('<%= escape_javascript(render("events/edit", events: @events )) %>'); // フルカレンダー を一度消しもう一度表示 $('#calendar').fullCalendar('refetchEvents')予定を編集する
app/views/events/_edit.html<% events.each do |event| %> <div id='inputScheduleEditForm<%= event.id %>' class="modal fade" tabindex="-1"> <div class="modal-dialog modal-nm"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">スケジュール編集</h4> </div> <div class="modal-body"> <div class="col"> <%= form_with(model: event, url: users_event_path(event), method: :put) do |f| %> <p> <span>タイトル</span> <span id="inputTitle" value=""><%= f.text_field :title, class: "form-control", placeholder: "タイトルを入力してください" %></span> </p> <span>開始日時</span> <span><%= f.datetime_field :start, placeholder: "XXXX-XX-XX", class:"field" %> ~ </span><br> <span>終了日時</span> <span><%= f.datetime_field :end, placeholder: "XXXX-XX-XX", class:"field" %></span> <span><br> 詳細 <%= f.text_field :body, class: "form-control", placeholder: "タイトルの詳細を記入してください" %> </span> <div class="modal-footer"> <%= f.hidden_field :user_id, :value => current_user.id %> <%= f.submit "編集する", class: "btn btn-primary" %> <button type="button" class="btn btn-default" data-dismiss="modal">閉じる</button> </div> <% end %> </div> </div> </div> </div> </div> <% end %>app/views/events/update.js//updateした内容を差し替え $('#inputEditForm').html('<%= escape_javascript(render("events/edit", events: @events)) %>'); //モーダル背景画面を消す $('.modal-backdrop').remove(); // フルカレンダー を一度消しもう一度表示 $('#calendar').fullCalendar('refetchEvents')最後に
最後までご覧いただきありがとうございます。
初学者ですので間違っていたり、分かりづらい部分もあるかと思います。
何かお気付きの点がございましたら、お気軽にコメントいただけると幸いです。twitter:https://twitter.com/yto_oct
note:https://note.com/yto_oty参考
公式ドキュメント
https://fullcalendar.io/
[Rails]FullcalendarのイベントをDBに保存・編集
https://qiita.com/ShoutaWATANABE/items/3d0cddafadb4f275991e
- 投稿日:2020-02-18T10:58:14+09:00
windows/heroku/railsでhello world
とうとう作りたいwebサイトを思いついた
家のPC windowsなので
個人開発はherokuだって聞いたので
仕事でruby書いてるので
そんな環境でwebサイトをつくる(これは金曜夜に日本酒を飲みながら作りはじめ、書きはじめたサイト作成の記録なので、
酔っ払いが回り道をしながら、転びながら作っていることをご承知おきください。)VScodeとrailsとgitHub desktopの設定は前やってた
herokuいれた
herokuCLI windows用 いれた
heroku login
してプロジェクトを作った。dashboardに作ったプロジェクトが表示されない
→
git push
してないなpushした
→エラーでる。buildpackがどうとか。調べたところherokuでrubyでアプリ作るっていったのにrubyのフォルダ構成になってない(正確にはGemFileがない)からって怒られてるらしい
rails new app
してpush
→エラーでる。ちゃんと大事なところだけ赤字で怒ってくれる。子曰く、
$ Failed to install gems via Bundler. $ remote: ! Detected sqlite3 gem which is not supported on Heroku: $ remote: ! https://devcenter.heroku.com/articles/sqlite3そうですかサポート外ですか。
bundle install
の時はエラー出ないのになぜなんだ。
push
する際に行われるinstallでエラーがでる。
sqlite3のバージョン指定がいるとのことなのでGemFileを以下のように設定。GemFilegem 'sqlite3', '~> 1.3.13'ERROR: sqlite3.h is missing
そしてエラー。越えられない。
MySQLにしよう!
こちらに書いてある通りにしてMySQLいれる
終わったらWorkBenchが開くとあるが必要なものが全部ダウンロードできなくてエラーがでるのであきらめた。
MySQLがだめならpostgreだ!!
こちらと、
こちらを参照しつつproductionだけpostgreにしました。testとdevelopmentはsqlite3に戻しました。GemFilegroup :development, :test do gem 'sqlite3', '~> 1.3.6' end group :production do gem 'pg' end
git push heroku master
できた。herokuとの連携をgithub経由にしたのだけど、その過程で公開鍵の設定が必要になったのでそれも行ってます。(参照記事)
・・・hello worldが遠い(ここですでに4時間ほどが経過している)
heroku run rails db:migrate
がエラーPG::ConnectionBad: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
なるほどSUNDAYじゃねーの(よくわかっていない)
エラー文をそのままぐぐったところアドオンがいるらしい
https://qiita.com/suzuki-x/items/b878723080aea1a673edheroku addons:create heroku-postgresql実食!!
必要とされる作業は終わったので開いてみる。
heroku openふぁー
ぐぐって(略)rootファイルを書かなきゃらしい。
ここまで来てローカルで何も書いてないし動かしてないことに一抹の不安を覚える。ローカルでrails s
なんかある程度書かないとHello Worldできないっぽいし一回ローカル叩いてみるか、と
おもむろにrails sしてみたところ、また件のsqliteが怒っている。can not load such file — sqlite3/sqlite3_native色々やってみてなんとか解決した。
こちらのsqlite3のインストールを少し変更した。
soファイル生成までは同じだが、Ruby26だったので、ファイルパスにある2.5は2.6に置換して、そこにsoファイルを置いた。これの2.5を2.6に修正するmkdir C:\Ruby25-x64\lib\ruby\gems\2.5.0\gems\sqlite3-1.3.13-x64-mingw32\lib\sqlite3\2.5 copy C:\Ruby25-x64\lib\ruby\gems\2.5.0\gems\sqlite3-1.3.13\lib\sqlite3\sqlite3_native.so C:\Ruby25-x64\lib\ruby\gems\2.5.0\gems\sqlite3-1.3.13-x64-mingw32\lib\sqlite3\2.5
rails s自体は通るようになったが接続すると以下のエラーが出る。
LoadError: Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? can't activate sqlite3 (~> 1.4), already activated sqlite3-1.3.13-x64-mingw32. Make sure all dependencies are added to Gemfile.調べても、GemFileに1.3を指定すればいいとしか出ない。指定してbundle installしなおすも、同じエラー。
自分がちゃんとエラー読めていないのかもしれないが。。。
えっじゃあ逆に1.4にしたらどうなるのと思ってやってみたら通った。Gemfilegroup :development, :test do gem 'sqlite3', '~> 1.4' endHello World!(ローカルです)
routesRails.application.routes.draw do # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html root 'pages#index' endPagesContorollerとviews/pages/index.html.erbを作ってそこに魂を込めて
Hello World!!
と打ち込む。みれた!!!
で、これはherokuで見れるのか?
git heroku push master
を再度行う。herokuでHello World!!できた!
ででできた・・・!!
イメージはローカルと同じなので省略。
お付き合いいただきありがとうございました。あとがき
読み返したら、らしいらしいばっか言ってて恥ずかしい。
自己解決もだんだんできるようになってくるのだろうか。環境構築だけで3日も使った。時間にして8時間くらいだろうか。
もっとお布団の中だけでさくっと開発できるようにしてくださいかしこいひと。さも一度も失敗しなかったかのようなバージョンもまとめておきたい。
Qiitaの記事を書いたのも初めてなのでマークダウンの使い方とか多分あんまり良くない。あと酔っ払いだったから色んな記事を拾い読みしていて、最初の方に見たはずの
【初心者向け】railsアプリをherokuを使って確実にデプロイする方法【決定版】にミスったところ全部載ってたし、
これ通りにしていれば、こんなに時間かからなかったよなあと思う。
- 投稿日:2020-02-18T10:58:14+09:00
windows10/heroku/rails6でhello world
とうとう作りたいwebサイトを思いついた
家のPC windowsなので
個人開発はherokuだって聞いたので
仕事でruby書いてるので
そんな環境でwebサイトをつくる(これは金曜夜に日本酒を飲みながら作りはじめ、書きはじめたサイト作成の記録なので、
酔っ払いが回り道をしながら、転びながら作っていることをご承知おきください。)VScodeとrailsとgitHub desktopの設定は前やってた
herokuいれた
herokuCLI windows用 いれた
heroku login
してプロジェクトを作った。dashboardに作ったプロジェクトが表示されない
→
git push
してないなpushした
→エラーでる。buildpackがどうとか。調べたところherokuでrubyでアプリ作るっていったのにrubyのフォルダ構成になってない(正確にはGemFileがない)からって怒られてるらしい
rails new app
してpush
→エラーでる。ちゃんと大事なところだけ赤字で怒ってくれる。子曰く、
$ Failed to install gems via Bundler. $ remote: ! Detected sqlite3 gem which is not supported on Heroku: $ remote: ! https://devcenter.heroku.com/articles/sqlite3そうですかサポート外ですか。
bundle install
の時はエラー出ないのになぜなんだ。
push
する際に行われるinstallでエラーがでる。
sqlite3のバージョン指定がいるとのことなのでGemFileを以下のように設定。GemFilegem 'sqlite3', '~> 1.3.13'ERROR: sqlite3.h is missing
そしてエラー。越えられない。
MySQLにしよう!
こちらに書いてある通りにしてMySQLいれる
終わったらWorkBenchが開くとあるが必要なものが全部ダウンロードできなくてエラーがでるのであきらめた。
MySQLがだめならpostgreだ!!
こちらと、
こちらを参照しつつproductionだけpostgreにしました。testとdevelopmentはsqlite3に戻しました。GemFilegroup :development, :test do gem 'sqlite3', '~> 1.3.6' end group :production do gem 'pg' end
git push heroku master
できた。herokuとの連携をgithub経由にしたのだけど、その過程で公開鍵の設定が必要になったのでそれも行ってます。(参照記事)
・・・hello worldが遠い(ここですでに4時間ほどが経過している)
heroku run rails db:migrate
がエラーPG::ConnectionBad: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
なるほどSUNDAYじゃねーの(よくわかっていない)
エラー文をそのままぐぐったところアドオンがいるらしい
https://qiita.com/suzuki-x/items/b878723080aea1a673edheroku addons:create heroku-postgresql実食!!
必要とされる作業は終わったので開いてみる。
heroku openふぁー
ぐぐって(略)rootファイルを書かなきゃらしい。
ここまで来てローカルで何も書いてないし動かしてないことに一抹の不安を覚える。ローカルでrails s
なんかある程度書かないとHello Worldできないっぽいし一回ローカル叩いてみるか、と
おもむろにrails sしてみたところ、また件のsqliteが怒っている。can not load such file — sqlite3/sqlite3_native色々やってみてなんとか解決した。
こちらのsqlite3のインストールを少し変更した。
soファイル生成までは同じだが、Ruby26だったので、ファイルパスにある2.5は2.6に置換して、そこにsoファイルを置いた。これの2.5を2.6に修正するmkdir C:\Ruby25-x64\lib\ruby\gems\2.5.0\gems\sqlite3-1.3.13-x64-mingw32\lib\sqlite3\2.5 copy C:\Ruby25-x64\lib\ruby\gems\2.5.0\gems\sqlite3-1.3.13\lib\sqlite3\sqlite3_native.so C:\Ruby25-x64\lib\ruby\gems\2.5.0\gems\sqlite3-1.3.13-x64-mingw32\lib\sqlite3\2.5
rails s自体は通るようになったが接続すると以下のエラーが出る。
LoadError: Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? can't activate sqlite3 (~> 1.4), already activated sqlite3-1.3.13-x64-mingw32. Make sure all dependencies are added to Gemfile.調べても、GemFileに1.3を指定すればいいとしか出ない。指定してbundle installしなおすも、同じエラー。
自分がちゃんとエラー読めていないのかもしれないが。。。
えっじゃあ逆に1.4にしたらどうなるのと思ってやってみたら通った。Gemfilegroup :development, :test do gem 'sqlite3', '~> 1.4' endHello World!(ローカルです)
routesRails.application.routes.draw do # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html root 'pages#index' endPagesContorollerとviews/pages/index.html.erbを作ってそこに魂を込めて
Hello World!!
と打ち込む。みれた!!!
で、これはherokuで見れるのか?
git heroku push master
を再度行う。herokuでHello World!!できた!
ででできた・・・!!
イメージはローカルと同じなので省略。
お付き合いいただきありがとうございました。あとがき
読み返したら、らしいらしいばっか言ってて恥ずかしい。
自己解決もだんだんできるようになってくるのだろうか。環境構築だけで3日も使った。時間にして8時間くらいだろうか。
もっとお布団の中だけでさくっと開発できるようにしてくださいかしこいひと。さも一度も失敗しなかったかのようなバージョンもまとめておきたい。
Qiitaの記事を書いたのも初めてなのでマークダウンの使い方とか多分あんまり良くない。あと酔っ払いだったから色んな記事を拾い読みしていて、最初の方に見たはずの
【初心者向け】railsアプリをherokuを使って確実にデプロイする方法【決定版】にミスったところ全部載ってたし、
これ通りにしていれば、こんなに時間かからなかったよなあと思う。
- 投稿日:2020-02-18T10:25:20+09:00
System Specによる開発
はじめに
こちらは社内技術勉強会用の資料として作成したものです。
Ruby on Railsにおいて、RSpecの機能である、System Specを使用して開発をしてみます。サンプルプログラムを使用して、小さな開発を行いつつ、その動作確認をRSpecで行います。
サンプルプログラムについて
概要
サンプルプログラムUV Eatsは、Webサイト上で料理のメニューを注文すると配達してもらえる、というサービスであるとします。以下のような動作をするものとします。
- あらかじめ登録されているユーザでログインして利用します。
- メニュー一覧からひとつのメニューを選択して注文します。
- 注文時は配達先住所、支払方法、クレジットカード番号を入力します。
今回使用する画面は以下の4つです。
- ログイン画面 (Sessionsコントローラ)
- メニュー画面 (Menusコントローラ)
- 注文画面 (Ordersコントローラ)
- 注文完了画面 (Ordersコントローラ)
サンプルプログラムのソースコードはこちらを参照してください。
画面イメージ
DB
DBは以下の3つのテーブルで構成されています。
- ユーザ(users)
- メニュー(menus)
- 注文(orders)
RSpecの使い方について
その1: テストコードの作成
テストコードは、specディレクトリ内に、specファイルを作成して記述します。ログイン処理のテストであれば、ログイン処理を実装しているSessionsコントローラに関連するものとして、
spec/system/sessions_spec.rb
に記述します。ログイン画面を表示してみるコードは、以下のような内容になります。
spec/system/sessions_spec.rbrequire 'rails_helper' RSpec.describe "Sessions", type: :system, js: true do it 'ログイン画面が表示されること' do visit '/sessions/new' end endSystem Specは、
describe
のオプションtype
に、:system
を指定することで記述します。
js
というオプションが指定されていますが、これはこのサンプルプログラムの都合によるものです。付加しておいてください。テストの内容は、
it
のブロック内に記述していきます。その2: 初期データの登録
例えば、サービスにログインできるようにするためには、あらかじめログイン可能なユーザが登録されている必要があります。あらかじめデータを登録しておく方法として、FactoryBot を使用します。
FactoryBotの使い方は、GETTING_STARTED や こちらの記事 を参照してください。
その3: RSpecの実行
RSpecを実行するには、以下のようにコマンドを実行します。
$WEB_ROOT
は、Railsプロジェクトのルートディレクトリであるとします。cd $WEB_ROOT bundle exec rspec -fd spec/system/sessions_spec.rb以下のように表示されます。これは、1件のテストを実行し、0件が失敗した、ということを表しています。
1 example, 0 failuresその4: ページ内の文字列を検出
ログイン画面には、「メールアドレス」というラベルが表示されるとします。
ログイン画面が正しく表示されたかどうかを判定するには、URLにアクセスした後、このラベル文字列が含まれるページが表示されたかどうかを調べることでわかります。RSpecの構文で、以下のように記述します。
expect(page).to have_content('メールアドレス')specファイル全体では以下のようになります。
spec/system/sessions_spec.rbrequire 'rails_helper' RSpec.describe "Sessions", type: :system, js: true do it 'ログイン画面が表示されること' do visit '/sessions/new' expect(page).to have_content('メールアドレス') end endCapybaraによるWebブラウザの操作方法
その1: Webページへのアクセス
System Specは、自動でWebブラウザを操作してWebアプリケーションにアクセスし、動作の確認を行う仕組みです。Webブラウザの操作には、Capybara を使用します。
Capybaraの構文を使用して、Webページにアクセスするには
visit
メソッドを使用します。例えば、ログインページのパスが
/sessions/new
であったとすると、以下のように記述することで、ログインページにアクセスすることができます。visit '/sessions/new'その2: テキストフィールドへの入力
たとえばメニューを注文する画面において、配達先住所の入力欄が以下のように定義されていたとします。
<label for="order_delivery_address">配達先住所</label> <input type="text" id="order_delivery_address" name="order[delivery_address]" value="">この要素に対して「東京都新宿区内藤町11番地」と入力したい場合は、Capybaraの
fill_in
メソッドを使用し、以下のいずれかのように記述します。# 入力対象をラベルで指定する場合 fill_in '配達先住所', with: '東京都新宿区内藤町11番地' # 入力対象をid属性で指定する場合 fill_in 'order_delivery_address', with: '東京都新宿区内藤町11番地' # 入力対象をname属性で指定する場合 fill_in 'order[delivery_address]', with: '東京都新宿区内藤町11番地'その3: ドロップダウンの項目の選択
メニューを注文する画面において、支払方法の洗濯欄が以下のように定義されていたとします。
<select name="order[payment_method]"> <option value="01">現金</option> <option value="02">クレジットカード</option> </select>このドロップダウンで「クレジットカード」を選択したい場合は、Capybaraの
select
メソッドを使用して、以下のように記述します。select 'クレジットカード', from: 'order[payment_method]'選択したい項目はvalueではなく、テキストで指定していることに注意してください。
その4: ボタンのクリック
メニューを注文する画面において、入力フォームの内容を送信するボタンが以下のように定義されているとします。
<input type="submit" value="注文する">このボタンをクリックするには、
click_button
メソッドで、以下のように記述します。click_button '注文する'リンクをクリックしたい場合や、ボタンとリンクを区別したくない場合などについては、Clicking links and buttons を参照してください。
課題の実施にあたって
RSpecとCapybaraの簡単な使い方を確認したところで、課題を始めましょう。ここで、みなさんに無理難題を申し付けます。
課題にあたっては、ローカルPCで普段使用しているWebブラウザを使用しないでください。使用してもよいWebブラウザは、dockerコンテナ内にインストールされているheadless chromeのみとします。
ページがどのように表示されているのか分からなくて困る?まぁ、とりあえずはじめましょう。
課題1
ログイン画面が表示されることを確認してください。
説明
ログイン画面は、サンプルプログラムではSessionsコントローラ、newアクションに実装されています。Webブラウザでこのアクションに向かってアクセスし、ログイン画面が表示されることを確認してください。
Hint 1
ログイン画面を表示するためのテストコードは、前述「RSpecの使い方について」の「その4: ページ内の文字列を検出」に記載されています。実際にテストコードをspecファイルに記述して実行してみてください。
Hint 2
パスを固定文字列で直接指定してもかまいませんが、Sessionsコントローラ、newアクションにアクセスするためのURL(またはパス)は、URLヘルパーメソッド
new_session_url
やnew_session_path
で取得することができます。これらのヘルパーメソッドでURL部分を置き換えてみましょう。Hint 3
headless chromeの画面を直接見ることはできませんが、必要なタイミングでスクリーンショットを作成することができます。スクリーンショットを作成するには以下のように記述します。
take_screenshot
ログイン画面にアクセスした後に、スクリーンショットを作成してみましょう。テストコード内、
visit
メソッド呼び出しの次の行に追加して、実行してみてください。スクリーンショットは
tmp/screenshots/
というディレクトリに、png形式のファイルで作成されます。フォルダウィンドウでこのフォルダを開いておき、画像がプレビュー表示される状態にしておくとよいでしょう。また、スクリーンショットではなく、生成されたHTMLを確認したい場合は、
visit
メソッド呼び出しの後に以下のように記述しておくと、RSpecを実行しているターミナルの画面に出力されます。puts page.body課題2
ログイン画面にメールアドレスとパスワードを入力し、ログインを成功させてください。
説明
ログイン画面にはメールアドレス、パスワードの2つの入力欄と、ログインボタンがあります。DBに存在するユーザのメールアドレスとパスワードを入力し、ログインボタンをクリックしてください。
Hint 1
テスト用のデータベースには、最初はレコードが1件も登録されていない状態です。ログインするためには、あらかじめユーザを1件登録しておく必要があります。
ユーザのレコードは、FactoryBotを使用すると、以下のようなコードで登録することができます。
user = create(:user)
user
変数にUserモデルのインスタンスが代入されます。このインスタンスにはFactoryBotによって自動的に生成されたメールアドレスとパスワードがセットされています。それぞれ、user.mail、user.password とすると値を参照することができます。これらの値を、入力欄に与えてみましょう。Hint 2
入力フォームのへの入力とボタンのクリックは、前述のように、
fill_in
、click_button
で行うことができます。Hint 3
ログインに成功すると、メニュー一覧画面が表示されます。ログインに成功したかどうかは、スクリーンショットを作成する、または、ページの内容に
Menus
という文字が含まれているかどうかを判定する、などの方法により確認することができます。課題3
注文画面を完成させてください。
説明
ユーザがWebサイトにログインし、メニュー画面でいずれかのメニューを選択したとします。すると、注文画面が表示されます。
この注文画面のビューとコントローラの開発を行ってください。
注文画面には以下の入力項目があるとします。これらの項目がある入力フォームをビュー(
app/views/orders/_form.html.erb
)に追加してください。
入力項目 物理名 入力方法 選択肢 配達先住所 delivery_address テキスト - 支払方法 payment_method ドロップダウン 01
:現金、02
:クレジットカードカード番号 card_number テキスト - Ordersコントローラ(
app/controllers/orders_controller.rb
)では、create
アクションで注文画面から送信された内容を受け取り、Orderモデルで、DBのordersテーブルにレコードを登録します。Orderモデルのインスタンスを生成するには、以下の属性値を指定します。
属性名 物理名 型 値の取り出し元 メニューID menu_id 数値 params[:menu_id]
ユーザID user_id 数値 @me.id
配達先住所 delivery_address テキスト params
のorder
内、delivery_address
支払方法 payment_method ドロップダウン params
のorder
内、payment_method
カード番号 card_number テキスト params
のorder
内、card_number
Ordersコントローラの
order_params
メソッドに、上記の属性値を取り出すコードを記述してください。テストコードは、
spec/system/orders_spec.rb
に記述してください。Hint 1
ビューファイル
_form.html.erb
内での、テキスト入力欄、送信ボタンなどの記述方法は、menus
やusers
などのビューファイルを参考にしてください。ドロップダウンの記述方法は、Railsガイドの SelectタグとOptionタグ を参考にしてください。以下のようなコードになります。
<%= form.select :payment_method, options_for_select([['現金', '01'], ['クレジットカード', '02']]) %>Hint 2
どのようなHTTPリクエストが送信されているかを確認したくなった場合は、Railsのログを見ることで確認することができます。ログは
log/test.log
に出力されます。たとえば、注文画面での入力内容は以下のように送信されていることがわかります。Started POST "/orders?menu_id=11" for 127.0.0.1 at 2020-02-18 23:38:23 +0900 Processing by OrdersController#create as HTML Parameters: {"order"=>{"delivery_address"=>"MyText1", "payment_method"=>"01", "card_number"=>"MyText1"}, "commit"=>"登録する", "menu_id"=>"11"}新しいターミナルを開き、以下のコマンドを実行して、常にログを確認できる状態にしておくとよいでしょう。
tail -f log/test.logHint 3
注文を行うためには、あらかじめDBに以下のデータが必要です。
- ログインする(=注文する)ユーザ
- 注文するメニュー
このうち、ログインするユーザは、
spec/system/orders_spec.rb
内の以下の行により、自動的に登録されるようになっています。include_context :system_shared_contextメニューは、FactorbyBotを使用して、以下のように記述すると登録することができます。
create(:menu)データを登録したら、Capybaraを使用して入力欄を埋め、「登録する」ボタンをクリックしてください。
課題4 おまけ
サンプルプログラムでは、注文画面において、支払方法に「クレジットカード」、カード番号に「0000」を入力すると、決済に失敗したとして例外が発生するようになっています。
例外を検知し、例外のメッセージと共に注文画面を再表示するようにプログラムを修正してください。
課題1の解答例
spec/system/sessions_spec.rbrequire 'rails_helper' RSpec.describe "Sessions", type: :system, js: true do it 'ログイン画面が表示されること' do # ここにテストコードを書く visit new_session_path take_screenshot end end課題2の解答例
spec/system/sessions_spec.rbrequire 'rails_helper' RSpec.describe "Sessions", type: :system, js: true do it 'ログインに成功すること' do # ここにテストコードを書く login_user = create(:user) visit new_session_path fill_in 'user[mail]', with: login_user.mail fill_in 'user[password]', with: login_user.password click_button 'ログイン' expect(page).to have_content('Menus') end end
let
を使って書く場合は以下のようになります。spec/system/sessions_spec.rbrequire 'rails_helper' RSpec.describe "Sessions", type: :system, js: true do describe 'ログインに' do let (:login_user) { create(:user) } it '成功すること' do visit new_session_path fill_in 'user[mail]', with: login_user.mail fill_in 'user[password]', with: login_user.password click_button 'ログイン' expect(page).to have_content('Menus') end end end課題3の解答例
ビュー
app/views/orders/_form.html.erb<div class="field"> <%= form.label :delivery_address %> <%= form.text_field :delivery_address %> </div> <div class="field"> <%= form.label :payment_method %> <%= form.select :payment_method, options_for_select([['現金', '01'], ['クレジットカード', '02']]) %> </div> <div class="field"> <%= form.label :card_number %> <%= form.text_field :card_number %> </div> <div class="actions"> <%= form.submit nil, { class: 'button' } %> </div>コントローラ
app/controllers/orders_controller.rbdef order_params params.require(:order).permit( :delivery_address, :payment_method, :card_number, ).merge({ menu_id: params[:menu_id] }).merge({ user_id: @me.id }) endテストコード
spec/system/orders_spec.rbrequire 'rails_helper' RSpec.describe "Orders", type: :system, js: true do include_context :system_shared_context # ここにテストコードを書く describe '新規登録に' do let (:menu) { create(:menu) } let (:order) { build(:order) } let (:payment_trans) { { '01' => '現金', '02' => 'クレジットカード' } } it '成功すること' do visit new_order_path({ menu_id: menu.id }) fill_in 'order[delivery_address]', with: order.delivery_address select payment_trans[order.payment_method], from: 'order[payment_method]' fill_in 'order[card_number]', with: order.card_number click_button '登録する' expect(page).to have_content('Order was successfully created.') end end endおわりに
開発において、DBの値のリセットや入力フォームへの値の入力などの作業をテストコードに任せる、ということを体験していただくことができましたでしょうか?
今回はRuby on RailsとSystem Specでしたが、他の開発言語、フレームワークでも同様なことができるものもあるでしょう。
テストコードはテストを行う手段というだけでなく、開発時にも使ってみていただけるとよいと思います。
- 投稿日:2020-02-18T09:19:15+09:00
Rails.root.join("foo", "bar")よりも、Rails.root.join("foo/bar")が良いのでは?というお話
はじめに:joinに渡す引数はいくつ?
たとえば、Railsのテストを書いたりするときに、テスト用のCSVファイルのパスを指定することがあると思います。
# 入力フォームでCSVファイルをアップロードするコード例 attach_file 'CSV file', csv_file_pathこのとき、
Rails.root.join
を使うと簡潔にファイルパスを取得できるのですが、いろんな人のコードを見ていると、大きく分けて以下のような2パターンがあるようです。# "/" で区切った1つの文字列を渡すパターン csv_file_path = Rails.root.join('spec/fixtures/sample.csv') # パスの要素ごとに区切って複数の文字列を渡すパターン csv_file_path = Rails.root.join('spec', 'fixtures', 'sample.csv')僕はふだん前者のパターンで書いています。その理由は以下のとおりです。
- 後者のパターンより短く書けるから
'spec/fixtures/sample.csv'
のようなパスが、プロジェクトルートから見た相対パスとして、ぱっと認識しやすいから一方、後者のパターンで書く人の理由を聞いてみると、「実行環境によってはパスの区切り文字が
/
と限らないから」と答える人が多かったです。
これはおそらく、Windows環境でパスの区切り文字が\
になることを意識しているんだと思います。検証:"/"でパスを区切っても、Windows環境でちゃんと動く
しかし、後者のパターンで書く理由が「Windows環境を意識しているから」なのであれば、その心配はおそらく無用です。
Windows環境のrails consoleで、先ほどのような
Rails.root.join
の2つの書き方を比較した結果を以下に載せます。
(僕はWindowsをふだん使わないため、Railsのバージョンが少し古いですが、おそらく挙動は今でも同じだと思います)C:\dev\rails-sandbox>rails c Loading development environment (Rails 5.0.2) irb(main):001:0> Rails.root => #<Pathname:C:/dev/rails-sandbox> irb(main):002:0> p1 = Rails.root.join('config', 'database.yml') => #<Pathname:C:/dev/rails-sandbox/config/database.yml> irb(main):003:0> File.exist? p1 => true irb(main):004:0> p2 = Rails.root.join('config/database.yml') => #<Pathname:C:/dev/rails-sandbox/config/database.yml> irb(main):005:0> File.exist? p2 => trueすこし見づらいかもしれませんが、
Rails.root.join('config', 'database.yml')
と書いた場合も、Rails.root.join('config/database.yml')
と書いた場合も、どちらも同じようにファイルの存在チェックに成功しています。まとめ:"/"で区切る書き方でも問題ないのでは?
どちらが絶対に正しい書き方、というのはないと思いますが、短くシンプルに書ける「
/
で区切る書き方」を積極的に採用するのは悪くない考えだと思います。もし「パスの区切り文字が
/
とは限らないから(Windows環境が心配だから)」という理由でRails.root.join('spec', 'fixtures', 'sample.csv')
のような書き方をしている人がいたら、次回からRails.root.join('spec/fixtures/sample.csv')
のような書き方も検討してみてください。また、
Rails.root.join('spec', 'fixtures', 'sample.csv')
の方がメリットが大きい、という方がいたら、コメントをお待ちしています。補足1:"/"で始まるパスを渡さないように注意!
ただし、この書き方には1つだけ注意点があります。それは「
/
ではじまる文字列を引数として渡さないこと」です。
/
で始まる文字列を引数にすると、プロジェクトルートのパスが付与されず、引数がそのまま絶対パスとして扱われます。# OK: 最初に"/"を付けない場合→プロジェクトルートのパスが付与される Rails.root.join('spec/fixtures/sample.csv').to_s #=> "/Users/jnito/dev/rails-sandbox/spec/fixtures/sample.csv" # NG: 最初に"/"を付けた場合→プロジェクトルートのパスが付与されない Rails.root.join('/spec/fixtures/sample.csv').to_s #=> "/spec/fixtures/sample.csv"補足2:Rails.rootメソッドが返すオブジェクトは何?
Rails.root
メソッドが返すのはRuby標準のPathname
オブジェクトです。Rails.root.class #=> Pathnameまた、
join
メソッドもRuby標準の実装が使われています。(ActiveSupportによって拡張されているわけではありません)Rails.root.method(:join).source_location #=> ["/Users/jnito/.rbenv/versions/2.6.5/lib/ruby/2.6.0/pathname.rb", 407]
Pathname#join
メソッドの仕様については以下のドキュメントを参照してください。
- 投稿日:2020-02-18T07:56:46+09:00
RailsでGenerateしたらArgumentErrorで怒られた話
ルー大柴みたい
Railsチュートリアルも完走したし、オリジナルWebアプリ作るぞーと意気込んでGenerateしてみたところ、
ArgumentErrorと怒られたのでその備忘録です。$ rails generate controller Companys show Traceback (most recent call last): 58: from bin/rails:4:in `<main>' 〜〜省略〜〜 1: from /Library/Ruby/Gems/2.6.0/gems/actionpack-5.1.6/lib/action_dispatch/routing/mapper.rb :307: in `check_controller_and_action' /Library/Ruby/Gems/2.6.0/gems/actionpack-5.1.6/lib/action_dispatch/routing/mapper.rb :327:in `check_part': Missing :controller key on routes definition, please check your routes. (ArgumentError)
ArgumentError
とはメソッドの引数が正しくない時や足りない時に発生するエラーです。
wrong number of arguments (given 0, expected 1+) というエラーメッセージが表示されています。
これは 引数の数が間違っています(現状0個です、正常な引数の数は1個以上です) という意味です。
つまり form_for のメソッドの引数が足りないために起こっているエラーだということが分かります。メソッドのリファレンス(http://railsdoc.com/)を見ながら、正しい引数が設定されいるかを確認し修正すると解決できることが多いです。
なるほど、ArgumentErrorは引数のエラーなんですね
そしてエラー文を読み込むのが大事と。エラーメッセージに立ち返る
Missing :controller key on routes definition, please check your routes. (ArgumentError)
「routes上にあるコントローラーのキーが未定義ですので、routesを確認してね。」なんかよくわからんけど、
please check your routes.
って言われたし仕方ねえ確認してやるか。routes.rbRails.application.routes.draw do root 'static_pages#home' get '' # <= 何これ? endとりあえず削除してみて、もう一度generateしてみる
$ rails generate controller Companys show create app/controllers/companys_controller.rb route get 'companys/show' invoke erb create app/views/companys create app/views/companys/show.html.erb invoke test_unit create test/controllers/companys_controller_test.rb invoke helper create app/helpers/companys_helper.rb invoke test_unit invoke assets invoke coffee create app/assets/javascripts/companys.coffee invoke scss create app/assets/stylesheets/companys.scss上手く行った!!!
結論:作業途中のコードを放置するのはやめよう
そう心に誓いました。
- 投稿日:2020-02-18T07:40:34+09:00
【Rails】ユーザー情報変更後投稿一覧ページに遷移する
現在作成中のポートフォリオでは、ユーザー機能にdeviseを利用しています。
今回はユーザー情報変更後、指定のページに戻る方法を学びましたのメモしておきます。
registrations_controllerの設定
registrations_controller.rbで以下の部分のコメントアウトを外してください。
registrations_controller.rbdef after_update_up_path_for(resource) # ここにページ遷移したいパスをいれる home_show_path(resource) end私の場合はhome/showページに飛ばしたかったのでhome_show_pathと記入しています。
routesの設定
次はルートです。
以下のように記述してください。routes.rbas :user do get 'home/show',:to =>'devise/registrations#edit',:as => :user_root endasメソッドを使うと、どのリソースがルートかを伝えてくれるため、指定ページに簡単にリダイレクトしてくれます。
まとめ
今回のパターンを含め、他パターンは公式で紹介されているのでそちらもぜひ参考にしてください。
【How To: Customize the redirect after a user edits their profile】deviseは便利ですが結構複雑な印象があるので、色々試してなれていきたいです。
この記事が誰かの助けになれば幸いです。
ではでは。
- 投稿日:2020-02-18T02:58:17+09:00
rails s が立ち上がらない "Booting Puma", "server is already running"
$ rails s => Booting Puma => Rails version application starting in development => Run `rails server --help` for more startup options A server is already running. Check app/tmp/pids/server.pid. Exiting備忘録的に、、、
前回メソッドをいじっていたらループで抜けられなくなり強制終了(ごめんなさい!)
rails s
を起動したまま終了したので、次に起動してもalready running.
(もう動いてるよ!)だそうです。メッセージの通りに
app/tmp/pids/sever.pid.
をCheck。server.pid.
なるものを右クリックで削除。再度
rails s
で起動しました。
- 投稿日:2020-02-18T00:50:47+09:00
Railsのannotateでハマった話
ハマったところ
Railsでannotateのgemを入れて
group :development do gem 'web-console', '3.5.1' gem 'listen', '3.1.5' gem 'spring', '2.0.2' gem 'spring-watcher-listen', '2.0.1' gem 'pry-byebug' gem 'annotate' endインストールしたのに
bundle installannotateコマンドが反映されない,なぜか
$ bundle exec annotate // なにも結果が帰ってこないこうやって解決
Railsのプロジェクトに明示的に導入しないと使えないみたい.
$ rails g annotate // これでannotateできるようになったgemがinstallされていることと,今作業しているプロジェクトで使えることは別モノだということに気づけた.
- 投稿日:2020-02-18T00:28:11+09:00
画像をリモートで表示させる
使用例)
publicファイルにlogo.pngがある
title__logoクラスがある(haml) .title__logo = image_tag"/logo.png",alt""
- 投稿日:2020-02-18T00:01:09+09:00
Rails6 シンプルなカレンダーを実装する
目的
- Rails6のアプリ作成からシンプルなカレンダーを表示させるまでの手順をまとめる
環境
- Rails version
- 6.0.2.1
- SQLite3
- 1.4
- OS
- macOS 10.13.6
目標
- http://localhost:3000/home/topにアクセスした時にカレンダーが表示される。
- データベースからのデータをセルに表示して。。。などややこしいことはせずとにかくカレンダーを表示する。
公式の手順
実施方法
Rails6のアプリを作成
下記コマンドを実行して「simple_calendar」という名前のアプリを作成する。
$ rails _6.0.0_ new simple_calendar下記コマンドを実行して一度simple_calendarを起動する。
$ cd simple_calendar $ rails sブラウザでhttp://localhost:3000/にアクセスし下記の画面が表示されるか確認する。
下記キーを押下して一旦アプリを停止する。
- 「Ctrl」 + 「c」
http://localhost:3000/home/top
の画面表示準備
下記コマンドを実行して「homeコントローラ」と「topアクション」と対応するビューファイルを作成する。
$ rails g controller home top下記コマンドを実行して一度simple_calendarを起動する。
$ rails sブラウザでhttp://localhost:3000/home/topにアクセスし下記の画面が表示されるか確認する。
下記キーを押下して一旦アプリを停止する。
- 「Ctrl」 + 「c」
Gemのインストール
- アプリ名ディレクトリ直下にあるGemFileの最終行に
gem "simple_calendar", "~> 2.0"
と追記する。下記に記載前後のGemFileを記載する。
記載前
source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.5.0' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 6.0.0' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4' # Use Puma as the app server gem 'puma', '~> 3.11' # Use SCSS for stylesheets gem 'sass-rails', '~> 5' # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker gem 'webpacker', '~> 4.0' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.7' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use Active Model has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use Active Storage variant # gem 'image_processing', '~> 1.2' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.4.2', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' end group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara', '>= 2.15' gem 'selenium-webdriver' # Easy installation and use of web drivers to run system tests with browsers gem 'webdrivers' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]記載後
source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.5.0' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 6.0.0' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4' # Use Puma as the app server gem 'puma', '~> 3.11' # Use SCSS for stylesheets gem 'sass-rails', '~> 5' # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker gem 'webpacker', '~> 4.0' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.7' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use Active Model has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use Active Storage variant # gem 'image_processing', '~> 1.2' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.4.2', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' end group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara', '>= 2.15' gem 'selenium-webdriver' # Easy installation and use of web drivers to run system tests with browsers gem 'webdrivers' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] gem "simple_calendar", "~> 2.0"下記コマンドを実行してGemをインストールする。
$ bundle installGemの設定
- 下記のファイルのファイルを開く。
- アプリ名ディレクトリ/app/assets/stylesheets
- application.css
*= require simple_calendar
を追記する。
記載前
/* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's * vendor/assets/stylesheets directory can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the bottom of the * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS * files in this directory. Styles in this file should be added after the last require_* statement. * It is generally better to create a new file per style scope. * *= require_tree . *= require_self */
記載後
/* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's * vendor/assets/stylesheets directory can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the bottom of the * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS * files in this directory. Styles in this file should be added after the last require_* statement. * It is generally better to create a new file per style scope. * *= require simple_calendar *= require_tree . *= require_self */
表示確認
- 下記のファイルを開く。
- アプリ名ディレクトリ/app/views/home
- top.html.erb
下記のコードを追記する。
<%= month_calendar do |date| %> <%= date %> <% end %>top.html.erbの追記前後の様子を記載する。
追記前
<h1>Home#top</h1> <p>Find me in app/views/home/top.html.erb</p>追記後
<h1>Home#top</h1> <p>Find me in app/views/home/top.html.erb</p> <%= month_calendar do |date| %> <%= date %> <% end %>下記コマンドを実行して一度simple_calendarを起動する。
$ rails sブラウザでhttp://localhost:3000/home/topにアクセスし下記の画面が表示されるか確認する。(月日はいつを表示していてもOK)
予告
- ビューファイルを下記のように記載するとカレンダーのセルに指定のコンテンツを記載できることがわかったため、DBの特定レコードのcreate_atなどとリンクさせてDB内コンテンツの記載をしてみようと思う。
忘れないように予告として書かせていただいた。
<h1>Home#top</h1> <p>Find me in app/views/home/top.html.erb</p> <%= month_calendar do |date| %> <%= date %> <p>わろた</p> <% end %>下記に前述のコードを記載した際のhttp://localhost:3000/home/topのプレビューを記載する。