モチベーションの維持

こんばんは。

現在私は某プログラミングスクールでプログラミングの勉強をしています。

朝の9時から夜の9時までみっちり教室で勉強しているんですが、

ずっと勉強しているとだんだん頭が働かなくなっていきますよね。

 

そして集中力が続かなくなったり、手を抜き始めたりしてしまうものです。

 

そこで今日は勉強を始めてから一ヶ月が経過したので、

ここで一旦立ち止まってモチベーション維持のための時間を設けることにしました。

 

ちなみに今までの人生でも、こういう途中で「なぜ自分が今頑張るのか」を見つめる作業っていうのは必ずしてきました。

 

私は今大学生で慶應義塾大学に所属しているんですが、

大学受験を始めた当初は校内でビリから数えた方が早いくらい成績も悪くて、

いつも補習を受けている子でした。

 

そんな私が1年間の受験勉強を経て慶應義塾大学に合格できることになるんですが、少なからずここに自分の成功の鍵があると考えています。

 

がむしゃらに頑張らない

がむしゃらに頑張らない方がいい!とは思わないんですけど、

私自身こういう生き方はしてこなかったかな、、。

 

むしろ「これはがむしゃらに頑張っているだけなのか」「頑張る先に得られるものと自分が得たいものが合致しているのか」を判断基準にしてきました。

 

私は「これをやってみたい!」と思ったら、わりとすぐに手を出したり行動に移してしまうタイプで、今その瞬間に「やりたい!」って思った気持ちを尊重したいのでバンバン行動にしていきます。

だって私は今22才の若くてピチピチの女の子で失敗しても、まだ他のことで挑戦できる時間が残されてると思うんです!笑

でもその残された時間は限りあるものなので、今ある時間のなかでやりたいと思ったことは挑戦してみないともったいないんじゃないかな。そんな風に思っています。

 

ただ行動に移すまでの時間が少ないということはデメリットももちろんあります。

やってみたら自分が求めるものではなかったり、

自分の得意分野にはできないなと実感してしまったり、、。

 

それって当たり前のことですよね笑

それでいいんです。

大事なことは「そこから何を学んだの?」「学んだことよりも他に自分が学びたいことがあるの?」「なんでそんな風に感じたの?」「自分が求める先の方向性はなに?」、、こんな風に自問自答して、方向転換する必要性を感じて揺るがないのであればやめればいいと思います。

 

人生は短いし、自分だけのために使える時間なんてもっと限られているのに、

意味もなくがむしゃらに頑張るなんて馬鹿らしいと思います。

もちろん意味のあるものだったら頑張らなきゃいけません。当たり前ですね。笑

 

やらなきゃいけない環境をつくる

やりたいと思ったらすぐに行動する私ですが、

そこにもこだわりがあります。

「学びたいことが最短で身につく方法を考える」です。

 

現在もプログラミングスクールに通っていますが、

短期集中コースで週7日、土日休みなしで3ヶ月間みっちり勉強するコースを選択して勉強しています。

実際かなりきつい、、、。でも、きつい!とはしょっちゅう思ってますが、不思議なことにやめたいとは1mmも思ったことはないですね。

それは今の時点で頑張って得られるだろうものと、自分が得たいものが合致しているからだと思います。

 

応援してくれる人を作る

やらなきゃいけない環境として、私は「応援してくれる人を作る」という作業もします。

 

今回プログラミングを勉強するときに関しても、

私は自分が大好きな家族や友人に「こういう気持ちで勉強がしたい」と相談しました。

そして、彼らはありがたいことに心から「あなたならきっと頑張れる。応援してる!」と言ってくれました。本当に感謝しかないです。

 

しかしこれも大事な環境作りのひとつだと、私は思います。

 

自分のことを信じて応援してくれる人たちのために頑張ろう、という気持ちにもなりますし、なかなかそんなふうに思ってくれる人たちを裏切れるひとって少ないですよね。少なくとも私はそういう人たちから信頼を失うことが、世の中で1、2位を争うくらい怖いことだと思っているので、こういった人間関係からも頑張らなきゃいけない環境づくりができていると思います。

 

競争相手をみつける

私は普段なにげなく歩いてるときも、少し前に歩いてるひとをターゲットにして「このひとを絶対ぬかそう!」と決めて歩いてます。笑

 

ウォーキングに限らず、勉強や何か頑張りたいときには(自分の負けず嫌いな性格からかもしれませんが)これもかなり効果的です。

 

いつも自分の能力の少し上のひとを見つけて、「この人に負けない」というライバル心を勝手に燃やしています。

そうすると、いざ自分がだらけてしまいそうになったときに

「いま自分がだらけて学習が止まったら、あの人に負けてしまう」と思うようになり、スピードを緩めようとする自分を制限することができます。

 

できないことは当たり前でどうやったらできるかを探す

私はいつもこんな風に自分に制限をかけてモチベーションを維持しています。

うーん、もしかするとモチベーションを維持するためには

モチベーションをあげようとするのではなくて、むしろモチベーションが下がるのを止めようとすることが大事なんではないでしょうか。

 

人間だれだって、モチベーションが下がるのは当たり前なので。

モチベーションが下がった自分自身を責めるのではなくて、

モチベーションが下がってしまった環境を責めてあげるといいじゃないかなと思います。

 

プログラミングとは関係ない話題になってしまいましたが、

プログラミングの勉強意欲維持の方法として今日はモチベーションの話で終わりたいと思います。

 

テストを実装してみる(2)コントローラー編

前回に引き続き、

アプリケーションのテストを行います。

 

今回はコントローラー編!ということで、

メッセージ送信機能のコントローラーが正しく機能しているかを調べます。

メッセージ送信機能が動いているかを調べるにあたって今回は、

送信したあとのindexアクションが動作しているかをテストしてみます。

 

deviseをRSpecで使用するように設定する

コントローラーでのテストの場合、ログインしてるか、してないかによってコントローラーアクションが変わってくることがあります。

 

そこで

ログイン状態ログインしていない状態を分けてテストできるように設定をします。
ログインをしている、していないということはgemのdeviseに任せているので、

deviseRSpecで使用できるように設定する必要があります。

 

やりかたはこのサイトを参考にしました〜

qiita.com


⑴まず、/spec/supportディレクトリに、controller_macros.rbを作成し、ログインのためのloginメソッドを定義する。

 

module ControllerMacros
  def login(user)
    @request.env["devise.mapping"] = Devise.mappings[:user]
    sign_in user
  end
end

 (これはgemの中に内臓されている文で深く理解するのは難しいらしいです。なので私は定型文として捉えました)

その後、rails_helper.rbに、deviseのコントローラのテスト用のモジュールと、いま定義したControllerMacrosを読み込む記述を行います。

 

RSpec.configure do |config|
  Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include ControllerMacros, type: :controller
  #〜省略〜
end

 

(これも定型文のような認識。今の段階でこれを一から書くのはなかなか難しい、、。) 

 

この2つの記述によって、

とりあえずcurrent_userなど、deviseのヘルパーメソッドを使用したインスタンス変数のテストが出来るようになりました!

 

テストコードを書いていく

ファイルを作成する

この作業は基本的にモデルのテストのときと同じです。

テストしたいメッセージコントローラーのファイルを作成するために、

controllersディレクトリを作ってその中にmessages_controller_spec.rbというファイル名をファイル命名規則に従って書いていきます(前回説明済み)

 

基本コードを書く

これもモデルのテストの時と同じですね。

 

違うのは今回の場合分けは「ログインしているか」「ログインしてないか」の2通りになるということです。

 

場合分けにはcontextを使うんでしたよね!

indexアクションとcreateアクションで分けて、

それぞれログインしているときとログインしてないときにcontextを分けます。

 

f:id:lilybelly:20181009151531p:plain

 

 

indexアクションについてテストコードを書く

まず大まかに概要を書きます!

 

メッセージ一覧を表示するアクションでテストすべきは以下の点です。

  • ログインしている場合
    • アクション内で定義しているインスタンス変数があるか
    • 該当するビューが描画されているか
  • ログインしていない場合
    • 意図したビューにリダイレクトできているか
ログインしている場合のテストコードを書いていく 

 

 

何度も使うことを最初に定義する

 

今回はログインしている状態を記述しようとします。

ログインしている中でも、

  • アクション内で定義しているインスタンス変数があるか
  • 該当するビューが描画されているか

の2つを調べるんでしたね。

 

このときどちらも前提条件として「ログインをする」、「擬似的にindexアクションを動かすリクエストを行う」共通の処理にあるので、

処理を先にまとめて書いてしまう方がコードがすっきりします。

 

先にまとめる方法としてbeforeメソッドを使いましょう。

before do
        login user
        get :index, params: { group_id: group.id }
      end

 

簡単に解説すると

ログインをする状態を表すには

さっきdeviseで設定した「login」を呼び出せばいいです。

module ControllerMacros
  def login(user)
    @request.env["devise.mapping"] = Devise.mappings[:user]
    sign_in user
  end
end

 

「login」で定義できてるので、

2行目の login userでオッケーです。

 

3行目は「擬似的にindexアクションを動かすリクエストを行う」ために、getメソッドを利用しています。messagesのルーティングはgroupsにネストされているため、group_idを含んだパスを生成します。そのため、getメソッドの引数として、params: { group_id: group.id }を渡しています。

 

ここまでで、共通の処理を定義することができました。

 

アクション内で定義しているインスタンス変数があるかどうか確かめる

 アクション内で定義しているインスタンス変数があるかどうか確かめていきましょう。
インスタンス変数に代入されたオブジェクトは、コントローラのassigns メソッド経由で参照できます。


@messageを参照したい場合、assigns(:message)と記述することができます。

 

it 'assigns @message' do
        expect(assigns(:message)).to be_a_new(Message)
      end

      it 'assigns @group' do
        expect(assigns(:group)).to eq group
      end

 

@messageはMessage.newで定義された新しいMessageクラスのインスタンスです。

be_a_newマッチャを利用することで、 対象が引数で指定したクラスのインスタンスかつ未保存のレコードであるかどうか確かめることができます。

今回の場合は、assigns(:message)が

Messageクラスのインスタンスかつ未保存かどうかをチェックしています。

 

 

it 'assigns @group' do
        expect(assigns(:group)).to eq group
      end
 

@groupはeqマッチャを利用して参照したassigns(:group)とgroupが同一であることを確かめることでテストできます。

 

該当するビューが描画されているかどうかをテストしていきましょう。

it 'redners index' do
        expect(response).to render_template :index
      end

 

 

expectの引数にresponseを渡しています。responseは、example内でリクエストが行われた後の遷移先のビューの情報を持つインスタンスです。 render_templateマッチャは引数にアクション名を取り、引数で指定されたアクションがリクエストされた時に自動的に遷移するビューを返します。この二つを合わせることによって、example内でリクエストが行われた時の遷移先のビューが、indexアクションのビューと同じかどうか確かめることができます。

 

 

ログインしていない場合を考える
it 'redirects to new_user_session_path' do
  expect(response).to redirect_to(new_user_session_path)
end

 

redirect_toマッチャは引数にとったプレフィックスにリダイレクトした際の情報を返すマッチャです。

今回の場合は、非ログイン時にmessagesコントローラのindexアクションを動かすリクエストが行われた際に、ログイン画面にリダイレクトするかどうかを確かめる記述になっています。

何度も使う変数をまとめる

 

テスト内で何度も使用する変数はletメソッドを使用するらしいです。

 

qiita.com

このサイトにletの書き方も書いてありました。

 

let(:foo) { ... } のように書くと、 { ... } の中の値が foo として参照できる、というのが letの基本的な使い方です。

 

 

let(:group) { create(:group) }
let(:user) { create(:user) }

 

上は

create(:group)の値が :group として参照できるということと

create(:user)の値が :user として参照できるということ

 

を表しています。

これをコードの一番上にまとめとくことで、

「:group」でgroupのインスタンス変数を

「:user」でuserのインスタンス変数を扱うことができます。

 

 

 

完成したコード

 

ちょっとわかりにくかったので、

コメントアウトでどんな風に動いているのかを簡単に書いておきます。

 

require 'rails_helper'

describe MessagesController do
  let(:group) { create(:group) }
  let(:user) { create(:user) }
  #コードをまとめて書いている
  describe '#index' do

    context 'log in' do #ログインしてる場合
      before do
        login user #ログインしててindexアクションを動かすことをまとめてる
        get :index, params: { group_id: group.id }
      end

      it 'assigns @message' do
        expect(assigns(:message)).to be_a_new(Message)
      end #参照した:messageが保存できてるか確かめる

      it 'assigns @group' do
        expect(assigns(:group)).to eq group
      end #参照したgroupとgroupが一緒か確かめる

      it 'redners index' do
        expect(response).to render_template :index
      end #indexのビューに移動できてるか確かめる
    end

    context 'not log in' do
      before do
        get :index, params: { group_id: group.id }
      end

      it 'redirects to new_user_session_path' do
        expect(response).to redirect_to(new_user_session_path)
      end #ログインしてない場合はログイン画面にリダイレクトされるか確かめる
    end
  end
end

 

 

 

 今日はこんな感じです。

ちょっと難しくて、自分でもこんな感じなのかと理解するので精一杯でした!

 

説明がわかりにくくてすみません。

またちゃんと理解できたときに編集を更新したいと思います!

 

 

 

 

 

 

 

 

 

 

 

 

テストを実装してみる⑴モデル編

前回の記事で、テストについて理解しテストを行うのに必要なgemをインストールできました。

 

そこで今日はテストを実際にやっていこうと思います。

 

前回の記事でも言いましたが、

テストにはモデルのテストとコントローラーのテストがあります。

 

モデルでは正しくデータを保存できてるかのテスト、

コントローラーでは指定したアクションが動いてるか・指定したビューが表示されるようになっているかのテスト

を行います。

 

モデルのテストを行う

今回は今作っているチャットアプリにおけるテストを行いたいと思います。

チャットアプリにおいてメッセージ送信がきちんと行われるかを確認するために、

メッセージ送信機能のモデルをテストをしましょう。

 

モデルのテストコードを書いてみよう
 まずファイルを作成する

今回はメッセージ送信機能のモデルをテストするので、

メッセージモデルのファイルを作成をしていきます。

 

では、どこのディレクトリの、どのファイルを作成し、記述していくべきなのか?

これはrspecの規則を理解する必要があります。

 

[RSpecの規則]

RSpecによるテストコードが書かれたファイルのことを、specファイルと呼びます。

全てのspecファイルは、先ほどのrails g rspec:installコマンドで生成された「specディレクト」の中に格納しておきます。

 

モデルに関するテスト用ファイル→spec/models/以下に、

コントローラーに関するテスト用ファイル→spec/controllers/以下に

格納されます。

 

またspecファイル名は対応するクラス名_spec.rbという名前になります。

 

つまり、今回はメッセージモデルのテストを

spec/models/のディレクトリの中に「message_spec.rb」 という名前で作成し、

そこにテストコードを書いていけばオッケーですね。

f:id:lilybelly:20181009124631p:plain

 

  基本となるコードを書く

まず基本となるコードがだいたい定型文であるので、

それを書きます。

あとで説明するので、まずコードをみてください。

 

f:id:lilybelly:20181009125139p:plain

[1行目] 1行目のrequire 'rails_helper'は、

rails_helper.rb内の記述を読み込むことで共通の設定を有効にしています。

この1行目の記述は、全てのspecファイルに書き込みます。

 

[3~7行目] 3, 4行目に連続してdescribeが登場しています。describeは、このようにネスト(入れ子状)にすることができます。ここでは「messageクラスにあるcreateメソッドをテストするまとまり」であることを示しています。このように、describeとdoの間にメソッド名を書く際は#をつけるのが慣習です。

 

基本コードがかけたので、ネストした中に実際のテスト処理を行うコードを書いていきましょう!

 

 テストコードを書いていく

まず何をテストしなきゃいけないのかを把握しておきましょう。

 

モデルでテストすべきは以下の点です。

  • メッセージを保存できる場合
    1. メッセージと画像があれば保存できる
    2. メッセージがあれば保存できる
    3. 画像があれば保存できる
  • メッセージを保存できない場合
    1. メッセージも画像も無いと保存できない
    2. group_idが無いと保存できない
    3. user_idが無いと保存できない

ここでわかるのが「メッセージが保存できる場合とできない場合」の2つで分けることができます。

 

このように特定の条件で分ける場合可読性を高めるために、

context」を使った方がいいです。

 

contextは以下のように使います。

 

require 'rails_helper'

RSpec.describe Message, type: :model do
  describe '#create' do
    context 'can save' do
 # この中にメッセージを保存できる場合のテストを記述
    end

    context 'can not save' do
 # この中にメッセージを保存できない場合のテストを記述
    end
  end
end

 

メッセージの保存ができる場合とできない場合を場合分けできたので、

中のテスト記述をそれぞれ考えていきます。

 

テストの記述方法は、下の例をみて参考にしてください。

 

describe "hogehoge" do
  it "1 + 1は2になること" do
    expect(1 + 1).to eq 2
  end
end

 

まず、describeというキーワードでテストをグループ化します。

(これはもう書いてありますね)
続いて、テスト1つ(example)として評価される

it do ~ endのブロックの中に、expect(X).to eq Yという形式の式を書いていきます。

これが、実際にテストが成功するかどうかチェックされる式(エクスペクテーション)になります。

 

eqの部分はマッチャと言って、テストが成功する条件を示します。例えばeqは「等しければ」という意味になります。つまり上の文であれば、「1+1が2と等しければ成功」ということになります。

 

他にもinclude(含んでいれば)、valid(バリデーションされれば)など複数のマッチャが存在します。

 

[ メッセージを保存できる場合]

先程の項目を上からやっつけていきたいと思います!

 

まず1個目、

①「メッセージと画像があれば保存ができる」

このように保存ができるという条件をクリアする場合のテストを使いたい時は、

be_validマッチャを利用します。

 

使ってみます。

 it 'is valid with content and image' do
  expect(build(:message)).to be_valid
 end

 

it と do の間にテストの説明文を書きます。

(ちなみに「内容とイメージがあれば有効」的なことを書いてます。)

 

2行目にあるbuild(:message)は実は他のファイルにmessageとして作成したインスタンスの情報をあらかじめ設定していれることで省略して使えるようにしてます。

(前回の記事で少し触れてるので戻ってみてください)

 

f:id:lilybelly:20181009132911p:plain

 

factoriesというディレクトリを作って、

そのなかで作成したいインスタンス名からとってmessages.rbというファイルを作成し

設定したいインスタンスの情報を記述しています。

 

これで既にファクトリーの定義が完了しているため、build(:message)でMessageモデルのインスタンスを生成することができます。

 

これで1つ目のテストコードが完成です。

it 'is valid with content and image' do
  expect(build(:message)).to be_valid
 end

 

②メッセージがあれば保存できる。

これも保存できちゃうかを調べるので be_validを使う。

 

 it 'is valid with content' do
  expect(build(:message, image:  nil)).to be_valid
 end

 

buildで設定したインスタンスを持ってきながら、

image: nilで情報の上書きもできます。

これで画像はないけどメッセージはあるという情報をテストできます。

 

③画像があれば保存できる。

これも②と同じですね、上書きの部分でcontent: nilにすればオッケー

 

 it 'is valid with image' do
  expect(build(:message, content:  nil)).to be_valid
 end

 

[保存ができない場合]

次に保存ができない場合について調べてみます。

 

今度は逆に保存ができない状態になってるか?について調べたいですね。

そういうときはvalid?メソッドを使います。

 

①画像もメッセージもないと保存できない

 

 it 'is invalid without content and image' do
   message = build(:message, content: nil, image: nil)
   message.valid?
 end

 

最初にcontentもimageもないインスタンスを生成します。

そして2行目で保存ができないようになっているか確認します。

 

it 'is invalid without content and image' do
  message = build(:message, content: nil, image: nil)
  message.valid?
  expect(message.errors[:content]).to include('を入力してください')
end

 

valid?メソッドを利用したインスタンスに対して、errorsメソッドを使用することによって、バリデーションにより保存ができない状態である場合なぜできないのかを確認することができます。

contentもimageもnilの今回の場合、'を入力してください'というエラーメッセージが含まれることが分かっているため、includeマッチャを用いて以下のようにテストを記述することができます。

これで「メッセージも画像もない場合は保存できずに'入力してください'というエラーがでるかどうかをテストする」ことができます。

 

②group_idが無いと保存できない

③user_idが無いと保存できない

これも①とほとんど一緒です。

上書きしたいところをnilにして、入力してくださいというエラー文がでるかを確認してください。

 it 'is invalid without group_id' do
   message = build(:message, group_id: nil)
   message.valid?
   expect(message.errors[:group]).to include('を入力してください')
 end

 it 'is invaid without user_id' do
   message = build(:message, user_id: nil)
   message.valid?
   expect(message.errors[:user]).to include('を入力してください')
 end

 

うん、ほぼ一緒ですね笑

 

テストしてみる
$ bundle exec rspec spec/models/message_spec.rb

ターミナルでこのコマンドを打つと、テストを実行できます!

 

 

これでエラーが起きなければ完成です!

 ターミナルはこんな感じでテストできました!

 

f:id:lilybelly:20181009142952p:plain

 

 

テストを理解する

テストとは

こんにちは。今日はアプリ開発における「テスト」について学んでいこうと思います。

 

テストとは:プログラミングにおいて「正常に機能しているか?」を確認することです。

基本的にテストは2種類に分けることができて、

 

1つは単体テストと呼ばれるような、プログラムを構成する小さな単位の機能が正しく機能しているかを調べるテストと

 

もう1つは「統合テスト」と呼ばれるような、複数の単位の機能が連動して1つのプログラム全体が正しく機能できているかを調べるテスト

 

の2種類です。

 

私はなんとなく細かいところは単体テスト、プログラム全体は統合テストと覚えておくことにしました!!

なんのために学ぶのか

なんのために学ぶって、ちゃんと機能してるか確かめることは大事なことでしょう〜って思いますよね。

 

まあ当たり前のことなんですけど、

 

ただちゃんと機能するかを確かめるときも単体テストと統合テストで分けることによって単体テストの段階で不具合を発見できて、結果的に開発全体のエラー修正の際のコスト削減が実現できるなどのメリットは多いみたいです。

 

これからチームで開発していく上では必ず必要な知識ですね。

ということで、今日はテストについて学んでいきます。

 

実際のテスト方法

テストを行う前の下準備

テストを行う前に2つのgemをインストールしました。

RSpec」と「Factory_girl」です。それぞれ説明していきます。

 

Rspecの導入

Ruby on Railsにおいてテストは基本的にモデルとコントローラーのファイルにおいて行うみたいです。

 

その際に RSpecという独自の言語を利用してテストコードを書いていきます。

RSpecの導入方法は「rspec-rails」というgemをインストールすると利用できるようになるみたいです。

 

実際にやってみます。

まずgemgfileに追加記述をします。

 

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug'
  gem 'spring', '1.3.6'
  gem 'pry-rails'
  gem 'compass-rails','~> 2.0'
  gem 'sprockets', '2.11.0'
  gem 'kaminari'
  gem 'devise'
  gem 'rspec-rails'
end

 

かけたら、ターミナルでbundle installします。

f:id:lilybelly:20181008125649p:plain

f:id:lilybelly:20181008125739p:plain

このように表示されたらインストール成功です(gemfile.lockに反映されてるかでも確認できます)

RSpecの設定をする

次にRSpecの基本設定をしました。

まず、設定ファイルを作成する必要があります。

 

[Rsoec設定ファイル作成方法]

$ rails g rspec:install #RSpec用設定ファイルの作成

ターミナルで上記のコマンドを打つと、ファイルが作成されます。

 

作成されたファイルのなかの[.rspec]というファイルに

--format documentation

を記述します。

これは何をしてるかというと、

Rspecの記述フォーマットを設定しています。

フォーマットは以下の4種類の中から指定できるみたいなので色々と調べてみてください。

 

  • progress (もしくはp)
  • documentation (もしくはd)
  • html (もしくはh)
  • json (もしくはj)

参考文献載せておきます

samurai.ataglance.jp

Rspecが正常に起動しているか確認

確認方法はターミナルに

$ bundle exec rspec

と打ち込むと、

No examples found.


Finished in 0.00031 seconds (files took 0.19956 seconds to load)
0 examples, 0 failures

こんな風に出てくればオッケーみたいです。

 

factory_girlをインストールする

factoru_girlはあらかじめテストするダミーのインスタンス変数を定義しておくことで、

テストコードのなかにそれぞれインスタンス変数を定義することを省略化できるものです。

 

ちょっとよくわからないと思うんですけど、Qiita でわかりやすい記事があったのでこれをみてもらえるといいと思います。

qiita.com

 

ここにgemのインストール方法が書いてあるので、factory_girlのインストール方法については割愛させていただきます。

 

続きを読む

画像のアップロードができるようにする

画像のアップロードとは

今日は画像のアップロード機能の追加方法について勉強していきます。

この機能って結構アプリケーションを作成する時に使用しますよね。

ただなんだか難しそう、、、、!

 

そう思ってたんですけど意外と簡単でした。

 

なんせGemという簡単なライブラリを使えばあっという間に実装できちゃうんです。

 

今日はそんな画像アップロードの方法について書いていきます。

 

CarrierwaveというGemを使う

まず下準備としてgemのインストールをしましょう。

 

gemfileにgemの記述を追加して、ターミナルでbundle installを行えばいいんです。

じゃあ実際にやってみます。

 

f:id:lilybelly:20181007123153p:plain

 

今回は画像アップロードができる"carrierwave"と一緒に画像処理をしてくれる"mini_magick"を一緒に追加しました。

(幾つかの記事でcarrierwaveと共に「rmagick」の導入が促されていますが、こちらのgemは最新版がインストール出来ない不具合があるためインストールしないようにしましょう。かわりに「mini_magick」というgemをインストールすることをおすすめします。)

 

f:id:lilybelly:20181007123534p:plain

gemfile.lockを確認すると、きちんと反映されていました。オッケーです!

 

画像のアップローダーを作成する

画像のアップローダーは

ターミナルのコマンド

$ rails g uploader image

を入力すると

image_uploader.rbというアップローダーを作成できます。

 

このアップローダー、なんで作る必要があるのかというと

アップロードした画像を保存する場所を指定できる

という特徴があるからなんです。

 

なので、画像のアップロード機能を追加したい場合は

gemのインストール後のアップローダーを生成して

色々とここから設定を記述していく必要があるみたいです。

 

私もその通りにアップローダーを生成しました。

 

f:id:lilybelly:20181007125647p:plain

 

これで、app/uploadersのディレクトリ内に

image_uploader.rbが生成されたのがわかります。

 

image_uploader.rbに記述する

さっき作ったimage_uploader.rbに

画像の設定を色々と記述していきます。

 

以下に色々と設定したいパターンごとの見本を載せておくので

参考にしてください。

 

f:id:lilybelly:20181007131430p:plain

 

私は今回、縦横比を維持したまま、width, heightをリサイズしたかったので

先程 インストールした画像処理ができるmini_magickを使ってリサイズを行います。

 

そこで上記のリサイズするパターンを見習って

include CarrierWave::MiniMagick を記述するのと、

(RMagickではなく今回はMiniMagicを使ってるので)

 

縦横比を維持したまま、width, heightをリサイズするには

「resize_to_fit」が使えるので、

process resize_to_fit: [800, 800]

で縦横比を維持したまま、アップされた画像を width, heightが800pxにリサイズされるように設定しました。

 ↓

  include CarrierWave::MiniMagick

  process resize_to_fit: [800, 800]

 

カラムと結びつける

そしてアップロードされた画像と実際にあるカラムを結びつけてあげます。

 

アップロードされた画像がテーブルのどこに保存されるべきか

指定してあげないと、画像がどこにもされないでエラーがおきますから。

 

今回はチャットアプリのメッセージと一緒に画像もアップロードできるように

機能を追加しているので

メッセージテーブルのカラムを見てみます。

 

f:id:lilybelly:20181007130213p:plain

 

そうすると、imageカラムがありますね。

そう、このimageカラムにアップロードした画像が入ってくれればいい訳です。

なので今回はimageカラムと結びつけてあげます。

 

mount_uploaderメソッドを使う

画像とカラムを結びつけるために、

「mount_uploaderメソッド」を使います。

 mount_uploader :結びつけたいカラム名, ImageUploader
 mount_uploader :image, ImageUploader


このようにmount_uploader :結びつけたいカラム名, さっき色々と画像の設定をしたファイル名
を記述することによって

「ImageUploader に書いた設定に沿って画像をイメージカラムと結びつけてね」
 と設定できます。


これで完成です!
画像がアップロードできるように設定できました。

 

 

まとめ

以上の手順をまとめると

  1. gem carrierwave, mini_magickをインストール
  2. uploaderを作成し、画像の設定を行う
  3. 保存したいモデルのカラムを結びつける

です。

簡単ですね。

ぜひやってみてください!!!

form for タグ を理解する

はじめに

ここまで何度かアプリを作成する練習をしてきました。

そしてそのなかでフォーム作成をする機会が何度かあったんですが、

ちゃんと理解しないまま利用していたメソッド?タグ?がありました。

 

それが「form for」タグです。

いろんな記事を見たんですが、form for の説明が丁寧な記事ってなかなかなくって

よくわからないまま記載されてある記述をコピペしたりして

なんとかここまで実装してきました。

 

が、アプリケーションを作成する際にユーザー登録って必ず使うじゃないですか。

それなのにちゃんと理解できてないのって、まずいなって思ったんです。

 

なので今回はform forについて、ちゃんと理解していこうと思います。

 

どんなときに使うか?

そもそも form for ってどんな時に使えばいいか?

ー調べてみました。

 

form_forは入力フォームでデータを入力するときに使います。(ここまではわかる)

実際にはformタグ・ inputタグで入力フォームとして使うことができるんですが、

度々「form_for に変換した方がいい」と言われます。

これってなんでなんだろうって思ってたんですけど、

結論からいえばform_for タグを使ったほうが色々と楽なんだなーってことらしいです。

 

 

勝手にフォームアクションから適切なコントローラー内のアクションに移動してくれる

ビュー画面でフォームタグを作成すると、以下の感じになります。

 

f:id:lilybelly:20181006141128p:plain

 

例えばこれで、引数にuserのインスタンス変数を渡してあげるようになっています。

 

そして

@userで渡されたデータが

新しい情報の場合はuser#createに移って、

 createアクションでデータを作成保存してくれます。

既存の情報の場合はuser#updateに移って、

 updateアクションでデータの情報を更新してくれます。

 

これを特に記載せずに自動的にやってくれるっていうんだから

それは楽ですよね、、!

(デフォのcreate update 以外の動作を特定したい場合は、

 urlとmethodを書く必要があるらしいですが、、、)

 

 

勝手にパラメーターを生成してくれる 

コントローラー内でも便利みたいです。

ビューでform_forタグを使って書いたものが以下です。

 

f:id:lilybelly:20181006142256p:plain

 

form_tagのなかに、ネストして「f.〜」で書いてあるものがありますね。

このネストした部分がデータの新規作成・更新の時に

パラメーターとして生成してくれるみたいです。

(f.labelは表示される項目名みたいなもの、f.~fieldで書いてあるものが入力欄)

これで生成したuserのインスタンス変数に

ネスト内にあるnameやemailやpasswordなどの属性を入力してもらって、

それらをコントローラーへ引数として渡すことができます。

 

 

 

コントローラーへ移ると

実際にcreateアクション内で引数で渡したものを受け取り保存してくれます。

 

f:id:lilybelly:20181006143204p:plain

 

  ↑

こんな感じ

 

じゃあその中身はどうなっているかというと

上のform_forタグのネスト内で

「f.text_field: name」として属性値を設定してれば

パラメーターを生成してcreateメソッドに送ってるので

 

f:id:lilybelly:20181006143931p:plain

こんな風にユーザーモデルにネームというパラメータが入った状態になってるはずです。

 

なるほど、、ここまでまとめると、、、、

  • フォームタグから適切なアクションを識別して行ってくれる
  • コントローラー内へパラメーターを生成して送ってくれる

 

、、、めちゃ便利じゃん。頑張って使えるようにしよう。

 

実際にやってみる

今回はチャットアプリのビュー画面で、

グループ作成の際に情報を入力してもらうために

このform_tagを使いたいと思います。

 

f:id:lilybelly:20181006150857p:plain

 

実際にできたビュー画面です。

複雑になっちゃってるので、見にくくてすみません。

3行目のfomタグをform_forに変更して、groupの情報を登録したいので、@groupにします(ビューで変数をもってくるためには、コントローラーのアクションないに定義しなきゃいけません。ちゃんとあとでnewアクション内に定義します)

 

で、さっき説明したネストする f.~が12行目らへんにあります。

クラス名やplaceholderはこんな風に書くことができます。

 

ちなみに25行目はチェックボックスを表示させてます。

f:id:lilybelly:20181006151654p:plain

collection_check_boxを使う

f:id:lilybelly:20181006152022p:plain

さっきform_forタグの中のネスト内に f.~で属性を書くといいました。

 

これも基本的には同じです。f.collection_check_boxesで使えます。

 

ちなみにcollection_check_boxesの中には、

5つ引数がセットされています。


:group(第1引数)

:オブジェクト(form_forブロック配下では省略可能。上記では省略してます)

 


:user_ids (第2引数)

:メソッド(プロパティ?)


:User.all(第3引数)

:inputタグの元となるオブジェクト配列。配列の数だけinputタグが作成されます


:id(第4引数)

:作成されたinputタグのvalueとなる値を指定。今回の場合、各userのidが入力されます


:name(第5引数)

:作成されたinputタグのテキストとなる値を指定。

今回の場合、各userのnameが入力されます

 

こんな感じで、ユーザーidを管理しながら

チェックボックスにユーザー名を表示させることができました。

 

、、正直チェックボックスはまだ理解できてないので、

また今度記事にしていきたいと思います。

 

 

form_forから送られたデータを新規作成、保存するように設定する。

f:id:lilybelly:20181006154713p:plain

 

(この「@group.users << current_user」というのは、

選択するメンバーに自分は表示されないようになっているので

自動的に作成してる本人はグループに入れるようにしています。)

 

 

 

 

これでform_forタグからインスタンス変数を生成し、コントローラーアクションで新規作成・保存ができるようになりました。

 

 

なかなか難しいですが、

これを使うと便利なことがわかったので慣れるまで積極的に使っていこうと思います。

 

 

 

 

Flashメッセージを実装する

 

こんにちは。今日も天気が悪いですね。

今週末にはまた台風がくるみたいです。最近は台風も人々の生活を及ぼすまでの自然災害になってきているので、怖いです、、、。

 

突然ですがブログ を見返してみて、

ふと自分のブログ 見にくいな〜と思いました。

そしてブログ の書き方も改善が必要だと感じました。

今までは学習のまとめとしてここにその日習ったことを書いていこうと思ってましたが、学習したカテゴリーごとに記事を書いていこうと思います。

 

 

なので今日は「Flashメッセージの実装方法」について書いていきます。

 

Flashメッセージとは

Flashメッセージとは、webページの一番上に表示されるお知らせみたいなものです。

ログインしたときに「ログインしました!」と書かれたりします。

 

下に例として画像を載せておきます。

(私はいまチャットアプリを作成しているので、Flashメッセージには「チャットグループが作成されました」と表示されるように設定してます。)

 

f:id:lilybelly:20181005154720p:plain

 

この水色の部分が、Flashメッセージです。

なんとなく理解できたでしょうか?

 

実装方法

では実際にどういう実装方法をたどると、このFlashメッセージが表示されるようになるのでしょうか。

 

まずFlashメッセージを生成させるためには、

Railsにもともと設定されてあるFlashというオブジェクトを使います。

このFlashハッシュ型のオブジェクトで、

Flashを使用すると「キーと値」がセットになって自動的にハッシュオブジェクトを生成してくれます。

 

 

今回はサインアップ・ログイン・ログアウトをした時にFlashメッセージが出てくるようにします。

(ちなみに現状の環境としては、deviseのgemをインストールしてあります。)

 

 

またFlashの特徴として、

  1. deviseを導入した状態でflashオブジェクトを使用すると、deviseに関する通知(ログイン・ログアウトなど)が発生した時のみ、keyとvalueのハッシュを生成してくれるようになっています。
  2. flashはデフォルトで notice(動作成功時)とalert(動作失敗時)の2つのキーを生成してくれるようになっています。

 

うーん、なんとなくわかるけど、よくわからない、、、。

簡単に言うと、deviseを導入しちゃえば、

flashを使ったときに勝手にFlashメッセージ出してくれるよ!ってことの解釈でいいんでしょうか?

 

ちょっとこの段階だとよくわからないですが、とりあえず進めて行きます。(笑)

 

Flashメッセージを実装したい = ログインなどの特定のアクションを行なった時のみこのタグを表示させたい

つまり特定の時にwebページにFlashメッセージを表示させたいということです。

なのでビューに表示させたい場合は、HTMLのなかに特定の時のみFlashメッセージを表示するタグを作るようにすればいいです。

 

 

まず全体のHTMLにタグを入れるんですが、

私はログイン・ログアウト・サインアップ以外にもこのFlashメッセージを使うかもしれないので一応部分テンプレ化して入れておきます。

 

部分テンプレ化するもとのところに、

renderで記述して、、、、

 

部分テンプレの中身はlayoutディレクトリのnotificationsというファイル に記述していこうと思います。(部分テンプレは_アンダーバーから始めます)

 

f:id:lilybelly:20181005164658p:plain

f:id:lilybelly:20181005165113p:plain

 

そしてnotificationというFlashメッセージを表示させるためのタグを作ります。

「.notification」でクラス名が「notification」のdivタグを作ってます。

(%divは省略できます)

(1行目)

f:id:lilybelly:20181005170253p:plain

2行目以降で、

 

ここでFlashオブジェクトを呼び出します。

f:id:lilybelly:20181005170553p:plain

 

ここで、さっきFlashの特徴として書いた

  1. deviseを導入した状態でflashオブジェクトを使用すると、deviseに関する通知(ログイン・ログアウトなど)が発生した時のみ、keyとvalueのハッシュを生成してくれるようになっています。
  2. flashはデフォルトで notice(動作成功時)とalert(動作失敗時)の2つのキーを生成してくれるようになっています。

が今ここで実際行われているということです。

つまりkeyとvalueが入ったハッシュオブジェクトが作られているらしいです。

 

これをconten_tagというHTMLタグを作ってくれるメソッドを使って、

キーをクラス名としたバリューを表示させるdivタグを作成します。

  (ちなみにcontent_tagはHTMLタグを生成することができ、第一引数にタグの種類、第二引数に表示内容、第三引数にオプション( classなど)を設定できる

 

f:id:lilybelly:20181005165325p:plain

 

keyとvalueをハッシュから取り出したいので、

eachメソッドで取り出してあげます。

 

これで、ログイン・ログアウト・サインアップが行われた時だけ

Flashオブジェクトがよばれて

生成されたハッシュからcontent_tagでdivタグを作るようにしました!!

 

うーん、ここまできてやっとflashオブジェクトが理解できました。

 

サーバーを立ち上げてみると、ちゃんと表示されてます。

が、ここで表示言語が英語なことに気づきます!!

 

f:id:lilybelly:20181005173132p:plain

 

Flashメッセージの表示言語を英語から日本語にする

このFlashメッセージってデフォルトは英語表記になっているみたいです。

 

そこで英語表記から日本語表記へと変換させます。

 

これはローカルディレクトリにあるdevise.en.ymlが英語表記になってるためにこの現象が起こるらしいです。

f:id:lilybelly:20181005174813p:plain

 

なので

gitで日本語のファイルを検索して

devise.ja.yml

ja.yml

をconfig/localesに配置します。

 

そしてconfig/application.rbの20行目で

英語版のファイル を読まずにダウンロードした日本語ファイル を読むように指定することで日本語化がキチンと行われるようになりました。

 

f:id:lilybelly:20181005175313p:plain

 

完成したフラッシュメッセージは以下の通りです。

 

f:id:lilybelly:20181005182923p:plain

 

ちなみに以下のサイトも読んで参考にしたので、

読んでみてください。

 

 


ruby-rails.hatenadiary.com