20201022のRailsに関する記事は30件です。

ポートフォリオのダミーデータをFakerで作る【備忘録】

エンジニア初学者の方でポートフォリオのダミーデータを手入力で入れていくのは、とても面倒だし、かっこよくダミーデータを入れたいですよね。gem Fakerを使用すれば簡単に実現できます。

実装の流れ

作業時間は初めての方で30分程度になります。
1.gem Fakerの導入
2.fakerの日本語化
3.ターミナルからbundle install
4.seedファイルに記述
5.ダミーデータの作成/rails db:seed
6.DBに反映されているか確認

それではやっていきましょう!

1.gem fakerの導入

まずは、GemfileにFakerを導入しましょう!

Gemfile
gem 'faker'

2.fakerの日本語化

次にfakerの日本語化ファイルを導入します。
下記のリンクから、ja.ymlをダウンロードorコピーしてください、rails内のconfig>locales>ja.ymlに置きます。
https://github.com/faker-ruby/faker/blob/master/lib/locales/ja.yml
キャプチャ.PNG
次にapplication.rbのモジュール内にconfig.i18n.default_locale = :jaを記述します

application.rb
module hoge
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
    config.i18n.default_locale = :ja #ここを追加
  end
end

※ダウンロードorコピーはrawボタンからできます。(名前を付けてファイルを保存しましょう)
キャプチャ (2).PNG

3.bundle install

ターミナルでbundle installしましょう!

4.seedファイルに記述

いよいよseedファイルにテストデータを入れていきます。
下記の場合、modelで作成した、name/character/emailのカラムに対して50個のランダムなダミーデータを入力してくれます。

Faker::のメソッド記述は、READE.meを確認しましょう!

seeds.rb
50.times do 
  User.create(
    name: Faker::Name.name, 
    character: Faker::Games::Pokemon.name, 
    email: Faker::Internet.email,
  )
end
#一番左のname:はモデルのカラム名

次に、rails db:seedでデータの反映をします。

5. DBに反映されているか確認

コンソールからrails cで反映されているか確認しましょう。

User.all

※rails cはrails consoleの略

日本語化されたデータが入っていれば完了です。
お疲れさまでした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

turbolinksが悪さをして戸惑った話

この記事ではインストールしたRails 6.0.0を使っています
その中のJavaScriptについてです。
Railsでフリマアプリのコピーアプリを作っている中で、販売価格についての実装をJavaScriptで行っていました!
9b24e01a49b7e4729ba9f315f7554ca5.png

item_price.js
window.addEventListener('load', () => {
  const itemPrice = document.getElementById("item-price");
  itemPrice.addEventListener("input", () => {
    const inputValue = itemPrice.value;


  const addTaxDom = document.getElementById("add-tax-price");
  addTaxDom.innerHTML = (Math.floor(inputValue * 0.1));


  const saleProfit = document.getElementById("profit"); 
    const value_result = inputValue * 0.1
    saleProfit.innerHTML = (Math.floor(inputValue - value_result));      
  })
});

実装には成功し喜んで次の実装に進み、また出品しようと価格をinputするとたまに手数料と利益の計算が作動しない時がありました。
なんでだろう?と感じいろいろ試行錯誤と調べた結果この記述が悪さをしていたみたいです。
require("turbolinks").start()

この記述はapplicaion.jsに定義した記述です。注目して欲しいのはこの中の"turbolinks"です。意味としては『Ajaxによるページ遷移の高速化のためのライブラリ』という感じです。
素晴らしいメリットなのですが、こいつはたまにJava Scriptに悪さをし、小さなバグを発生させたり、readyが呼ばれない、headerが変化しない等というデメリットがあるらしいです。笑
メリットもあるので使いたいですが、どのような時が使いどきなのでしょうか?

turbolinksの使いどき

開発コストを上げてでもページのレンダリングを高速化したい場合
Javascriptの記述量が少ないとき
Railsから作られたビューを返す事がメインであるサイトなど

逆にページのレンダリングを高速化する必要がない規模のサイトなど
  Javascriptの記述量が多い時
  ページごとにcssやJavaScriptを分けて記述している場合は使うメリットは減るということです。

まとめ

Turbolinks使用の際は挙動をしっかり理解しておく必要がありますね。
メリット、デメリットを十分に考えたうえで使用用途をしっかり考え運用することをおすすめします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

html & rails メモ

はじめに

超ど初心者のメモです

フォーム

新規投稿フォーム

form_tag("url") do で送った情報はparam[] に入る

<%=form_tag("/posts/create") do%>

      <div class="form">
        <div class="form-body">

          <textarea name="content"></textarea>
          <input type="submit" value="投稿">

        </div>
      </div>

<% end %>

param[:content] とかで参照する。

新規ユーザー登録

<%= form_tag("/users/create") do %>

      <p>ユーザー名</p>
      <input name="name" value="<%= @user.name %>">
      <p>メールアドレス</p>
      <input name="email" value="<%= @user.email %>">
      <input type="submit" value="新規登録">

<% end %>

ログインフォーム

 <%= form_tag("送りたいURL") do%>

      <p>メールアドレス</p>
      <input name="email">
      <p>パスワード</p>
      <input type="password" name="password">
      <input type="submit" value="ログイン">

<% end %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Rails チュートリアルの中で覚えておくべきこと・概念

はじめに

私はWeb系の自社開発企業に転職のためにRailsの勉強をしました!
その勉強の一環でRailsのチュートリアル第6版を実施していて、私はこれが大事 & 覚えておくべきと思ったことを記載します。

  • Railsのチュートリアルをやったけど、あんまり頭に入ってない方
  • Railsのチュートリアルってどんなこと学べるの?と思ってる方
  • Railsでアプリを作成するときの基本を復習、学びたい方 は本記事が参考になるかと思います!

※本記事は5章〜14章までしか網羅してません。(5章からQiitaで記事に纏めて、備忘録にしようと思ったので。。。)
 気が向いたら、1章〜4章も後で更新します。STAR WARS方式で。

RubyとRailsの基礎用語、概念

★gemとは
- RubyGemsが公開してるRubyのパッケージのこと
- それらパッケージを管理するパッケージ管理システムのこと

★bundle install
- Gemfileに記載してあるRailsでの開発に必要なものをInstallするコマンド

★rails db:migrate
- railsで使用するデータベースの構造(テーブル、カラム)を変更するときに利用する機能
 ・rails db:migrateの大まかな使用の流れ
 1. マイグレーションファイルを作成&内容を記載
 2. $ rails db:migrateコマンドでマイグレーションを順番に実行してデータベースに変更を加える

第5章 レイアウトを作成する

5.2.1 アセットパイプライン

アセットパイプラインというのは主に(以下の)3つの主要機能に分かれている。
(以下 ※説明 ★簡単に要約)

[アセットパイプラインの最大のメリット]
本番アプリケーションで効率的になるよう最適化されたアセットも自動に生成されること。(=本番環境でページの読み込みを早くするのを自動的に行なってくれる。)
そうすることにより、「開発環境ではファイルの可読性」を保ち、「本番環境ではアプリの実行速度をあげる」という2つの異なる環境で各々に最強の環境を提供するという両立ができる。
★要するに、「開発環境」も「本番環境」も最適化されて、最高に効率/利便性が良いということ

  1. アセットディレクトリ
      ※開発に必要なもの(アセット)を置いておくディレクトリ

    • app/assets: 現在のアプリケーション固有のアセット
    • lib/assets: あなたの開発チームによって作成されたライブラリ用のアセット
    • vendor/assets: サードパーティのアセット(デフォルトでは存在しません)
  2. マニフェストファイル
      ※上記の「アセット」マニフェストファイルを一つのファイルに纏めることができる。

    • アセットを纏める処理を行うのはSprocketsというgem
    • マニフェストファイルで纏めれるのはCSSとJavaScript。(※画像ファイルには適応されない。)
 *= require_tree . #app/assets/stylesheetsの中の全てのCSSファイルを含むようにしてる
 *= require_self  #マニフェストファイル(application.css)自身も含むようにしてる

マニフェストファイルの中の上記のようなコメントをSporocketsが読み込んでいる。

3.プリプロセッサエンジン
  ※Railsはプリプロセッサエンジンを介して、アセットを実行し、ブラウザに配信できるように、マニフェストファイルを用いて結合し、サイト用に準備する

★要するにアセットを一つに纏めて、ブラウザで使いやすくしてる

5.3.4 リンクのテスト

    assert_select "a[href=?]", help_path, 

※help_pathが"/help”という定義は行っている前提。
上記のコードは、以下の"/help”パスが存在するか確認するテスト。
"a[href=?]"の?の部分がhelp_pathに置き換わる。(“/help”が存在するか確認)

<a href="/help”>...</a>
    assert_select "a[href=?]", root_path, count: 2

のcountはroot_pathへのリンクは2つあり、2つテストすることを指す。

assert_selectには色々な指定の仕方があります。
以下がそのうちのいくつかの代表例です。
image.png

第5章のまとめ

 - Railsのパーシャルは効率化のために使われ、別ファイルにマークアップを切り出すことができる。
 - Bootstrapフレームワークを使うと、レスポンシブで良いデザインを素早く実装できる
 - SassとAsset Pipelineは、(開発効率のために切り分けられた)CSSの冗長な部分を圧縮し、本番環境に最適化した結果を出力する
 - Railsのルーティングは自由にルールを定義できて、そのときに名前付きルートも使えるようなる。
 - 統合テストはページ感遷移を効率的にシュミレーションできる。

第6章 ユーザーのモデルを作成する

6.1 Userモデル

Active Record:データベースとやりとりをするデフォルトのRailsライブラリ

モデルを作成するときは、generate modelというコマンドを使います。
例) nameやemailといった属性を付けたUserモデルの作成

$ rails generate model User name:string email:string

[Railsの命名慣習]
- コントローラ名:複数形(例:Users)
- モデル名:単数形(例:User)
  └モデルは一人のユーザを表すから
- テーブル名:複数形
  └テーブル(DB)は複数のユーザの情報を持つから

6.1.3 ユーザーオブジェクトを作成する

  • user = User.new: インスタンスの生成
  • user.save: モデルの保存 ※下記の>>はrails console上で実行してることを意味する。
>> user = User.new(name: "Michael Hartl", email: "michael@example.com")
>> user.save
  • User.create: Active Recordを通じて、モデルの生成と保存を同時に行う方法
>> User.create(name: "Another Sky”, email: "anothersky@example.org")
  • モデルへのアクセス (<オブジェクト名>.<キー>) 例)
>> user.name
=> "Michael Hartl"
>> user.email
=> "mhartl@example.com"
>> user.updated_at
=> Mon, 23 May 2016 19:05:58 UTC +00:00
  • Active Recordでデータが形成された順で検索する方法
>> User.find(1)
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com",
created_at: "2019-08-22 01:51:03", updated_at: "2019-08-22 01:51:03">
  • Active Recordで特定の属性(データ)でユーザーを検索する方法
>> User.find_by(email: "michael@example.com")
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com",
created_at: "2019-08-22 01:51:03", updated_at: "2019-08-22 01:51:03">

6.2 ユーザーを検証する

Active Recordでよく使われるValidation(検証)ケース
1. Presence(存在性)
2. Length(長さ)
3. Format(フォーマット)
4. Uniqueness(一意性)

テスト駆動開発のテストの進め方
1. 有効なモデルのオブジェクトを作成
2. その属性のうちの1つを有効でない属性に意図的に変更
3. バリデーションで失敗するかどうかをテストする
4. 念のため、最初に作成時の状態に対してもテストを書いておき、最初のモデルが有効であるかどうかも確認
5. 4.のテストすることで、バリデーションのテストが失敗したとき、バリデーションの実装に問題があったのか、オブジェクトそのものに問題があったのかを確認することができる

rails test:models: モデルに関するテストだけを走らせるコマンド

$ rails test:models

6.3.1 ハッシュ化されたパスワード

マイグレーション名は自由に指定できる。
末尾を指定(to_usersに)しておくことで、usersテーブルにカラムを追加するマイグレーションがRailsによって自動的に作成される。

例)add_password_digest_to_usersというマイグレーションファイルを生成するためには、次のコマンドを実行します。

$ rails generate migration add_password_digest_to_users password_digest:string

6章のまとめ

  • Active Recordを使うと、データモデルを作成したり、操作したりするための多くのメソッドが使える
  • Active RecordのValidationを使うと、モデルに対して制限を追加できる
  • よくあるValidationは、「存在するか」「長さ」「フォーマット」
  • データベースにインデックスを追加すると検索効率が飛躍的に向上するし、データベースレベルでの一意性を保証するためにもインデックスを使える。

第7章 ユーザー登録

7.3.3 エラーメッセージ

「shared」: 複数のビューで使われるパーシャルは専用のディレクトリ

7.3.4 失敗時のテスト

assert_select: テストの対象がCSSの
・クラスの場合→div#CSSのid名

assert_select 'div#error_explanation'

クラスの場合→div.CSSのクラス名

assert_select 'div.field_with_errors'

7.6.1 本章のまとめ

  • debugメソッドを使うことで、有意なデバッグ情報を表示できる
  • Sassのmixin機能を使うと、CSSのルールをまとめたり、変数のように他の場所でもmixinで指定したCSS情報を使用できる
  • Railsでは簡単に標準的なRESTfulなURLを通した、データ管理が可能
  • form_withヘルパーは、Active Recordのオブジェクトに対応したフォームを作成する
  • flash変数を使うと、一時的なメッセージを表示できる
  • 統合テストを使うと、送信フォームの振る舞いを検証したり、バグの発生を検知できる

第8章 基本的なログイン機構

8.1 セッション

  • HTTPはステートレスなプロトコル

    • 状態管理がないプロトコルということ
    • 前後のリクエストの情報を全く利用せず、独立したトランザクション(処理)として扱われる
    • なのでHTTPプロトコル内「には」、ユーザのID等の情報を保持する「手段」がない
    • ユーザ情報などをWebアプリケーション上で管理する際は、「セッション(Session)」で半永続的な接続をクライアントとサーバ間に別途設定する必要がある

8.1.5 フラッシュのテスト

assert_templateとは:assert_template後にあるURLがビューを描画しているかをテストする。
※下記の場合は、sessions/newがビューを描画してるかのテスト

    assert_template 'sessions/new'

コラム 8.1. 「||=」とは何か?

Rubyではnilとfalseを覗いて、あらゆるオブジェクトがtrueになるように設計されている。
Rubyでは、||演算子をいくつも連続して式の中で使う場合、項を左から順に評価し、最初にtrueになった時点で処理を終えるように設計されてる。
この評価法は短絡評価(short-circuit evaluation)と呼ぶ。

&&演算子も似たような設計になってるが、項を左から評価して最初にfalseになった時点で処理を終了する点が異なる点である。

8.2.4 レイアウトの変更をテストする

.& safe navigation演算子(または"ぼっち演算子) 
Rubyのぼっち演算子を使うと、obj && obj.methodのようなパターンをobj&.methodのように凝縮した形で書けます。
例を上げると、以下のような論理演算子コードが

    if user && user.authenticate(params[:session][:password])

以下のように簡略化できます。

    if user&.authenticate(params[:session][:password])

&& user.authenticate&.authenticate と簡略化できています。
Ruby初学者としては簡略化しすぎでは?と少し混乱するのですが、
ぼっち演算子は使用されることが多いようなので、自分で使ってみて覚える努力が必要そうです。

8.4.1 本章のまとめ

  • Railsのsessionメソッドを使うと、ページ遷移時の状態を保持できる。一時的な状態の保持にはcookiesも使える。(※今後あらゆるブラウザがクロスドメインでのcookies共有を禁止にするため、Rakute○のドメインで取得した、Rakute○IDなどを別ドメイン(Rakute○以外のドメイン)では使用できなくなる。)
  • sessionメソッドを使うと、ユーザIDなどをブラウザに一時保存できる
  • テスト駆動開発(TDD)はレグレッションバグを防ぐときに便利
  • 統合でストでは、ルーティング、DBの更新、レイアウトの変更が正常に実施されてるかテストできる

9章 発展的なログイン機構

9.1.1 記憶トークンと暗号化

cookieを盗み出す有名な方法は4つある。
1. 管理の甘いネットワークを通過するネットワークパケットからパケットスニッファという特殊なソフトで直接cookieを取り出す
2. DBから記憶トークンを取り出す
3. クロスサイトスクリプティング(XSS)を使う
4. ユーザがログインしてるPCやスマホを直接操作してアクセスを奪い取る

1.の対処は7.5のSSLをサイトに対応すること
2.の対応は本チュートリアルでは、DBには記憶トークンをハッシュ化して保存してること
3.の対応はRailsでは自動的に対策されてる
4.システム側で根本的防衛策を講じることは不可能

■attr_accessorの利用用途
読み取りも書き込みもできるオブジェクトの属性を定義したい時
 
・name, descriptionという属性を持つUserオブジェクトを定義の仕方
Railsの場合

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name
      t.string :description

      t.timestamps null: false
    end
  end
end

DBを扱わない純粋なRubyコードの場合

class User
  attr_accessor :name, :description
end

ちなみに attr_reader は読み出し専用の属性を定義したいときに使い、
attr_writer は書き込み専用の属性を定義したいときに使う。

コラム 9.2. 10種類の人々

「この世には10種類の人間がいる。2進法を理解できる奴と、2進法を理解できない奴だ」は、この業界に古くから伝わるジョーク(らしい)です。
ローランドみたいですね(笑)もしかしたらローランドはここからパクったのか??

■三項演算子
以下のif elseコードが

  if boolean?
    var = foo
  else
    var = bar
  end

以下の様に短縮できる

var = boolean? ? foo : bar

三項演算子をメソッドの戻り値として使うこともよくあります。
※true, falseで関数の実行結果を判断するなど。

9.3.2 [Remember me]をテストする

assert_equalは、<期待>, <実際の値>の順で値を並べる。

assert_equal <expected>, <actual>

9.4.1 本章のまとめ

  • Railsではページ遷移の際に「状態」を保持することができる。ページの状態を長時間保持したいときは、cookiesメソッドを使って永続的なセッションにしましょう
  • remember_token と remember_digest をユーザごとに関連付けて、永続的セッションが実現できる
  • cookiesメソッドを使うと、ユーザのブラウザにcookiesなどを保存できる
  • (一般的に)セッションとcookieをそれぞれ削除すると、ユーザのログアウトを実現できる

第10章 ユーザーの更新・表示・削除

10.1 ユーザーを更新する

target="_blank" を使用すると、リンク先を新しいタブ(またはウィンドウ)で開くようになるので、別のWebサイトへリンクするときに便利な要素。
★個人的にリンク先へ飛ぶときは別のタブが嬉しいから、自分が実装するときはこれは絶対実装したいなと思った!
 個人的にはPC用(PCが主なクライアントが想定)のサイトは絶対コレ導入すべきやと思う!

<a href="https://gravatar.com/emails" target="_blank">change</a>

Railsは、form_with(@user) を使ってフォームを構成すると、@user.new_record?true のときにはPOST を、false のときにはPATCH を使います。

10.2.3 フレンドリーフォワーディング

*Tutorialでは@userではなくuserが使われているが、使うとusers_login_testでエラーが発生するので@userを使う。

sessions_controller.rb
  def create
    @user = User.find_by(email: params[:session][:email].downcase)              # paramsハッシュで受け取ったemail値を小文字化し、email属性に渡してUserモデルから同じemailの値のUserを探して、user変数に代入
    if @user && @user.authenticate(params[:session][:password])                 # user変数がデータベースに存在し、なおかつparamsハッシュで受け取ったpassword値と、userのemail値が同じ(パスワードとメールアドレスが同じ値であれば)true
      log_in @user                                                              # sessions_helperのlog_inメソッドを実行し、sessionメソッドのuser_id(ブラウザに一時cookiesとして保存)にidを送る
      params[:session][:remember_me] == '1' ? remember(@user) : forget(@user)   # ログイン時、sessionのremember_me属性が1(チェックボックスがオン)ならセッションを永続的に、それ以外なら永続的セッションを破棄する
      redirect_back_or @user                                                    # userの前のページもしくはdefaultにリダイレクト
    else
      flash.now[:danger] = 'Invalid email/password combination'                 # flashメッセージを表示し、新しいリクエストが発生した時に消す
      render 'new'                                                              # newビューの出力
    end
  end

*実際のエラー文

Error:
UsersLoginTest#test_login_with_remembering:
NoMethodError: undefined method `remember_token' for nil:NilClass
    test/integration/users_login_test.rb:60:in `block in <class:UsersLoginTest>'

10.5.1 本章のまとめ

  • ユーザーは、編集フォームからPATCHリクエストをupdateアクションに対して送信し、情報を更新する
  • Strong Prameters (params[:foobar])を使うことによって、安全にWeb上から変更させることができる
  • beforeフィルタを使うと、特定のアク4が実行される前にメソッドを呼び出すことができる(※めちゃ便利!!色んな活用用途がありそう!!)
  • Authorization(認可)のテストでは、特定のHTTPリクエストを直接送信する簡単なテストと、ブラウザの操作をシミュレーションする(ユーザが実際にする操作)難度の高いテスト(統合テスト)の2つを実行した(個人的には、統合テストのシミュレーションに必要なテストを考えるのは、論理的に考える必要があって、建設的に思考をこらせて楽しかった。)
  • フレンドリーフォワーディングは実際のアプリを作るときは絶対いるから、覚えて積極的に実装すべき(UX的に基本的にフレンドリーフォワーディングは必須)
  • rails db:seed コマンドは、db/seeds.rb にあるサンプルデータをDBに流し込む
  • render @usersを実行すると、自動的に _user.html.erb パーシャルを参照し、各ユーザーをコレクションとして表示する
  • boolean型のadmin属性をUserモデルに追加すると、admin?という論理オブジェクトを返すメソッドが自動的に追加される

第11章 アカウントの有効化

ユーザActivationの流れ
1. ユーザーの初期状態は「有効化されていない」(unactivated)にしておく。
2. ユーザー登録が行われたときに、有効化トークンと、それに対応する有効化ダイジェストを生成する。
3. 有効化ダイジェストはデータベースに保存しておき、有効化トークンはメールアドレスと一緒に、ユーザーに送信する有効化用メールのリンクに仕込んでおく。
4. ユーザーがメールのリンクをクリックしたら、アプリケーションはメールアドレスをキーにしてユーザーを探し、データベース内に保存しておいた有効化ダイジェストと比較することでトークンを認証する。
5. ユーザーを認証できたら、ユーザーのステータスを「有効化されていない」から「有効化済み」(activated)に変更する。

11.3.3 有効化のテストとリファクタリング

assigns メソッドを使うと、対応するアクション内のインスタンス変数にアクセスできるようになる。
例えば、Usersコントローラの create アクションでは @user というインスタンス変数があるが、テストで assigns(:user) と書くと、userインスタンス変数にアクセスできるようになる。

testでエラーが出た。。
こちらのteratailの記事を参考に以下のコードを

  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      if user.activated?
        log_in user
        params[:session][:remember_me] == '1' ? remember(user) : forget(user)
        redirect_back_or user
      else
        message  = "Account not activated. "
        message += "Check your email for the activation link."
        flash[:warning] = message
        redirect_to root_url
      end
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

以下のようにすると成功しました〜

  def create
    @user = User.find_by(email: params[:session][:email].downcase)
    if @user && @user.authenticate(params[:session][:password])
      if @user.activated?
        log_in @user
        params[:session][:remember_me] == '1' ? remember(@user) : forget(@user)
        redirect_back_or @user
      else
        message  = "Account not activated. "
        message += "Check your email for the activation link."
        flash[:warning] = message
        redirect_to root_url
      end
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

11.5.1 本章のまとめ

  • アカウント有効化はActive Recordオブジェクトではないが、セッションの場合と同様に、リソースでモデル化できる
  • Railsはメール送信で扱うAction Mailerのアクションとビューを生成できる
  • Action MailerはテキストメールとHTMLメールの両方を利用できる
  • Mailer Actionで定義したインスタンス変数は、他のアクションやビューと同様、Mailerのビューから参照できる
  • アカウント有効化のために、生成したトークンを使って一意のURLを作る
  • SendGridを使うと、production環境からメール送信できる

12章 パスワードの再設定

12.3.3 パスワードの再設定をテストする

・assignsメソッドはコントローラのインスタンス変数をテストするメソッド。
 引数にインスタンス変数をシンボル型で渡す。
 そうすることでインスタンス変数にアクセスできるようになり、テストができる。

    @user = assigns(:user)

12.5.1 本章のまとめ

  • Railsはメール送信で扱うAction Mailerのアクションとビューを生成できる
  • より安全なパスワード再設定のために、ハッシュ化したトークン(ダイジェスト)を使う

第13章ユーザーのマイクロポスト

13.4.1 基本的な画像アップロード

■Active Storage
Active Storageを使うことで画像を簡単に扱うことが出来、画像に関連付けるモデルも自由に指定できます。
Active Storageは汎用性が高く、平文のテキストやPDFファイル、音声ファイルなど様々なバイナリファイルを扱えます。

Active Storage APIの中で最初に知っておく必要があるのはhas_one_attachedメソッドです。これは、指定のモデルと、アップロードされたファイルを関連付けるのに使います。
has_one_attached は指定のモデルとアップロードされたファイルを関連付けるのに使えます。
has_one_attached の場合、「マイクロソフト1件に付き画像は1件」ですが、
has_many_attached を使えば、「マイクロソフト1件に付き複数の画像」を添付できます。

13.5.1 本章のまとめ

  • Rails は複数のキーインデックスをサポートしてる
  • Userは複数のMicropostsを持っていて(has_many)、Micropostは一人のんUserに依存してる(belongs_to)
  • user.microposts.build(...)というコードは引数で与えたユーザに関連付けされたマイクロポストを返す
  • dependent: :destroy オプションを使うと、関連付けされたオブジェクトと自分自身を同時に削除する
  • fixtureは関連付けを使ったオブジェクトの作成もサポートしてる
  • パーシャルを呼び出すときに一緒に変数を渡すことができる
  • where メソッドを使うとActive Recordを通して選択(部分集合を取り出すこと)ができる ※生のSQL文と同じ様な文章で取得できる

第14章ユーザーをフォローする

14.2.2 統計と[Follow]フォーム

@user ||= current_user

上記のコードは @user がnilではない場合は何もせず、nilの場合には @user にcurrent_userを代入するというコード

14.4.3 本章のまとめ

  • has_many :throughを使うと、複雑なデータ関係をモデリングできる
  • has_manyメソッドには、クラス名や外部キーなど、いくつものオプションを渡すことができる
  • 適切なクラス名と外部キーと一緒にhas_many/has_many :throughを使うことで、能動的関係(フォローする)や受動的関係(フォローされる)がモデリングできた
  • ルーティングは、ネストさせて使うことができる
  • whereメソッドを使うと、柔軟で強力なデータベースへの問い合わせが作成できる
  • Railsは(必要に応じて)低級なSQLクエリを呼び出すことができる

番外編

■assertの一覧表

メソッド 説明
assert_template(expected, message = nil) そのアクションで指定されたテンプレートが描写されているかを確認する
assert_not( test, [msg] ) testfalseかを確認する。
assert_select "div.nav" selector(div)に合致した要素の内容を引数equality(nav)でチェック

※assert_selectは柔軟でパワフルな機能で、多くのオプションがあるが、レイアウト内で頻繁に変更されるHTML要素 (リンクなど) をテストするぐらいに抑えておくとよい。

「!!」(「バンバン(bang bang)」と読みます)
オブジェクトをBoolean(論理)値に変換できる演算子。
nilはfalseになります。

>> !!nil
=> false

その他のあらゆるRubyのオブジェクトは、ゼロですらtrueです。

>> !!0
=> true

■! ビックリマーク(感嘆符)について
◆!マークを使うことで、データ(〜〜属性)を直接変更できる。
★!を使わん場合

  before_save { self.email = email.downcase }

★!を使う場合

  before_save { email.downcase! }

◆!をメソッドにつけることで例外を発生させられる!!
create, saveでの例。
! をつけない場合(create save)
・処理に実行して、レコードの作成/保存に失敗して際、 nil が返される。
! をつける場合(create! save!)
例外(例: ActiveRecord::RecordNotFound ERROR )を発生させられる。

■HTMLのtype= “email”
htmlでtype=“email”にすると、携帯電話から入力フォームをタップすると、メールアドレス用に最適化された特別なキーボードが表示される。

private キーワード
- そのファイル(クラス)内でしか使わないメソッドを定義するために使われる
- 他のファイル(クラス)ではprivate内で定義されたメソッドは使用できない。
- 他のファイルでは使われないメソッドをprivateにすることで、想定外のエラーが避けられる

  private

    def user_params
      params.require(:user).permit(:name, :email, :password, :password_confirmation)
    end

PATCH Method for HTTP
- Putメソッドは更新というよりは置換
- Putsで置き換え先が「空」でも、値を置き換える(置き換えようとしてる値をそのまま代入する)
- Patchメソッドは既存のリソースを更新・変更・修正

■<<演算子(Shovel Operator)
<< で配列の最後に追記することができます。

user.following << other_user

さいごに

結構時間かかりました。。Cloud9のエラー等も伴いましたが、結果1ヶ月強くらいかかってしまいました。。
結構ボリューミーだったので仕方ないと思ってますが、もっと早く終わらせてる人もいるので、Portfolio作りは早く終わらせようと思います!!

読んでいただきありがとうございました!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】投稿にタグ付け・インクリメンタルサーチ機能を実装する方法(gemなし)

タグ付けを行う前の前がき

本記事の概要

・投稿にタグ付けをできるようにする。
・文字を入力する度に自動検索を行ってくれる機能(インクリメンタルサーチ)をタグにを実装する

開発環境

Mac OS Catalina 10.15.4
ruby 2.6系
rails 6.0系
※rails newでアプリケーションは作成済みであることを前提としています。

タグ付け機能の完成形イメージ

demo

上図のGifのように、タグを入力し始めるとDBに保存されているタグを元にオススメタグを表示できるようにしています。
今回の記事を元にタグ付け機能を実装できれば、タグ検索なども容易に実装できるかと思います。

タグ付け機能実装の流れ

1. Tag,Post,PostTagRelation、Userモデルを作成
2. 各種モデルのmigrationファイルを編集
3. Formオブジェクトを導入
4. ルーティングの設定
5. postsコントローラーを作成、アクション定義
6. ビューファイルの作成
7. インクリメンタルサーチの実装(JavaScript)

上記の手順で実装を行ってきます。

1.Tag,Post,PostTagRelation,Userモデルを作成

er-figure

まずは、各種モデルを導入しましょう。

%  rails g model tag
%  rails g model post
%  rails g model post_tag_relation
%  rails g devise user

そのまま、導入した各モデルを関連付け(アソシエーション)してバリデーションを記述しましょう。

post.rb
class Post < ApplicationRecord
  has_many :post_tag_relations
  has_many :tags, through: :post_tag_relations
  belongs_to :user
end
tag.rb
class Tag < ApplicationRecord
  has_many :post_tag_relations
  has_many :posts, through: :post_tag_relations

  validates :name, uniqueness: true
end

「through: :中間テーブル」とすることで、多対多の関係であるPostモデルとTagモデルのアソシエーションを組んでいます。
注意点としては、throughによる参照前に中間テーブルの紐付けを行う必要があります。
(コードは上から読み込まれるので、 has_many :posts, through: :post_tag_relations → has_many :post_tag_relationsの順で書いてしまうとエラーになります。)

post_tag_relation
class PostTagRelation < ApplicationRecord
  belongs_to :post
  belongs_to :tag
end
user.rb
class User < ApplicationRecord

  #<省略>
  has_many :posts, dependent: :destroy
  validates :name, presence: true

Userモデルのhas_manyのオプションに、dependent: :destroyと付けているのは、親要素であるユーザー情報が削除された時にそのヒトの投稿も併せて削除されるようにするためです。

なお、PostモデルとTagモデルにて空データを保存させないようにするための記述(validates :〇〇, presence: true)に関しては、後ほど作成するフォームオブジェクトでまとめて指定しますので、今は必要ありません。

2.各種モデルのmigrationファイルを編集

続いて、作成したモデルにカラムを追加していきます。
(最低限必要なのは、tagのnameカラムくらいなので、その他はお好みでアレンジされてください。)

postのマイグレーションファイル
class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.string :title, null: false
      t.text :content, null: false
      t.date :date
      t.time :time_first
      t.time :time_end
      t.integer :people
      t.references :user, foreign_key: true
      t.timestamps
    end
  end
end

postのマイグレーションファイルで外部キーとしてuserを参照しているのは、後ほどuser名を投稿一覧で表示するためです。

tagのマイグレーションファイル
class CreateTags < ActiveRecord::Migration[6.0]
  def change
    create_table :tags do |t|
      t.string :name, null: false, uniqueness: true
      t.timestamps
    end
  end
end

上記のnameカラムにuniqueness: trueを適用しているのは、タグ名の重複を防ぐために導入しています。
(タグは同じ名前のものが何度も使われることが想定されるので、重複を防いだらタグ付け機能として成り立たなくない?と思われるかもですが、既存のタグを投稿に反映させる方法は後ほど登場します。)

post_tag_relationのマイグレーションファイル
class CreatePostTagRelations < ActiveRecord::Migration[6.0]
  def change
    create_table :post_tag_relations do |t|
      t.references :post, foreign_key: true
      t.references :tag, foreign_key: true
      t.timestamps
    end
  end
end

このpost_tag_relationモデルが、多対多の関係であるpostモデルとtagモデルの中間テーブルの役割を担っています。

userのマイグレーションファイル
class DeviseCreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :name,               null: false
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

   #<省略>

ユーザー名を利用したかったので、nameカラムを追加しました。

カラムの編集が終わったら、忘れずに下記コマンドを実行しましょう。

%  rails db:migrate

※まだDBを作成していないという方は、先にrails db:createを実行する必要があります。

3.Formオブジェクトを導入

今回の実装では投稿フォームからpostsテーブルとtagsテーブルへ同時に入力値を保存させたいので、Formオブジェクトを利用します。

まず、appディレクトリの中にformsディレクトリを作り、その中にposts_tag.rbファイルを作成しましょう。
そして、下記のようにpostsテーブルとtagsテーブルに同時に値を保存するためのsaveメソッドを定義します。

posts_tag.rb
class PostsTag

  include ActiveModel::Model
  attr_accessor :title, :content, :date, :time_first, :time_end, :people, :name, :user_id

  with_options presence: true do
    validates :title
    validates :content
    validates :name
  end

  def save
    post = Post.create(title: title, content: content, date: date, time_first: time_first, time_end: time_end, people: people, user_id: user_id)
    tag = Tag.where(name: name).first_or_initialize
    tag.save
    PostTagRelation.create(post_id: post.id, tag_id: tag.id)
  end
end

4. ルーティングの設定

続いて、postsコントローラーのindex・new・createアクションを動かすためのルーティングを設定します。

routes.rb
  resources :posts, only: [:index, :new, :create] do
    collection do
      get 'search'
    end
  end

collection内で定義しているsearchアクションへのルーティングは、インクリメンタルサーチ機能で利用します。

5. postsコントローラーを作成、アクション定義

ターミナルでコントローラを生成します。

% rails g controller posts

生成されたpostsコントローラファイル内のコードは下記のようになります。

posts_controller.rb
class PostsController < ApplicationController
  before_action :authenticate_user!, only: [:new]

  def index
    @posts = Post.all.order(created_at: :desc)
  end

  def new
    @post = PostsTag.new
  end

  def create
    @post = PostsTag.new(posts_params)

    if @post.valid?
      @post.save
      return redirect_to posts_path
    else
      render :new
    end
  end

  def search
    return nil if params[:input] == ""
    tag = Tag.where(['name LIKE ?',  "%#{params[:input]}%"])
    render json: {keyword: tag}
  end

   private

  def posts_params
    params.require(:post).permit(:title, :content, :date, :time_first, :time_end, :people, :name).merge(user_id: current_user.id)
  end
end

createアクションでは、先程Formオブジェクトで定義したsaveメソッドを使ってPostsモデルとTagsテーブルへposts_paramsで受け取った値を保存しています。

searchアクションでは、JS側で取得したデータ(タグ入力フォームで打ち込まれた文字列)を元に、 where + LIKE句でtagsテーブルからデータを引っ張り出し、reder jsonでJSに返しています。(JSファイルは後ほど登場。)

そういう訳なので、↑のsearchアクションは、インクリメンタルサーチを実装しないのであれば必要ありません。

6.ビューファイルの作成

new.html.erb
<%= form_with model: @post, url: posts_path, class: 'registration-main', local: true do |f| %>
  <div class='form-wrap'>
    <div class='form-header'>
      <h2 class='form-header-text'>タイムライン投稿ページ</h2>
    </div>
   <%= render "devise/shared/error_messages", resource: @post %> 

    <div class="post-area">
      <div class="form-text-area">
        <label class="form-text">タイトル</label><br>
        <span class="indispensable">必須</span>
      </div>
      <%= f.text_field :title, class:"post-box" %>
    </div>

    <div class="long-post-area">
      <div class="form-text-area">
        <label class="form-text">概要</label>
        <span class="indispensable">必須</span>
      </div>
      <%= f.text_area :content, class:"input-text" %>
    </div>

    <div class="tag-area">
      <div class="form-text-area">
        <label class="form-text">タグ</label>
        <span class="indispensable">必須</span>
      </div>
      <%= f.text_field :name, class: "text-box", autocomplete: 'off' %>
    </div>
    <div>【おすすめタグ】</div>
    <div id="search-result">
    </div>

    <div class="long-post-area">
      <div class="form-text-area">
        <label class="form-text">イベント日程</label>
        <span class="optional">任意</span>
      </div>
      <div class="schedule-area">
        <div class="date-area">
          <label>日付</label>
          <%= f.date_field :date %>
        </div>
        <div class="time-area">
          <label>開始時刻</label>
          <%= f.time_field :time_first %>
          <label class="end-time">終了時刻</label>
          <%= f.time_field :time_end %>
        </div>
      </div>
    </div>

    <div class="register-btn">
      <%= f.submit "投稿する",class:"register-blue-btn" %>
    </div>

  </div>
<% end %>

僕のアプリ実装で使っていたビューファイルをベタ貼りしているため、コードが冗長になっていますが要はフォームの内容を@post等でルーティングに送れていれば問題ありません。

index.html.erb
<div class="registration-main">
  <div class="form-wrap">
     <div class='form-header'>
      <h2 class='form-header-text'>タイムライン一覧ページ</h2>
    </div>
    <div class="register-btn">
      <%= link_to "タイムライン投稿ページへ移る", new_post_path, class: :register_blue_btn %>
    </div>
    <% @posts.each do |post| %>
    <div class="post-content">
      <div class="post-headline">
        <div class="post-title">
          <span class="under-line"><%= post.title %></span>
        </div>
        <div class="more-list">
          <%= link_to '編集', edit_post_path(post.id), class: "edit-btn" %>
          <%= link_to '削除', post_path(post.id), method: :delete, class: "delete-btn" %>
        </div>
      </div>
      <div class="post-text">
        <p>■概要</p>
        <%= post.content %>
      </div>
      <div class="post-detail">
        <% if post.time_end != nil && post.time_first != nil %>
              <p>■日程</p>
        <div class="post-date">
          <%= post.date %>
          <%= post.time_first.strftime("%H時%M分") %> 〜
          <%= post.time_end.strftime("%H時%M分") %>
        </div>
        <% end %>
        <div class="post-user-tag">
          <div class="post-user">
          <% if post.user_id != nil %>
            ■投稿者: <%= link_to "#{post.user.name}", user_path(post.user_id), class:'user-name' %>
          <% end %>
          </div>
          <div class="post-tag">
            <% post.tags.each do |tag| %>
              #<%= tag.name %>
            <% end %>
          </div>
        </div>
      </div>
    </div>
    <% end %>
  </div>
</div>

こちらも同様に冗長なので、適宜必要なところだけ参照ください...

## 7.インクリメンタルサーチの実装(JavaScript)

こちらは、JSファイルをいじります。

tag.js
if (location.pathname.match("posts/new")){
  window.addEventListener("load", (e) => {
    const inputElement = document.getElementById("post_name");
    inputElement.addEventListener('keyup', (e) => {
      const input = document.getElementById("post_name").value;
      const xhr = new XMLHttpRequest();
      xhr.open("GET", `search/?input=${input}`, true);
      xhr.responseType = "json";
      xhr.send();
      xhr.onload = () => {
        const tagName = xhr.response.keyword;
        const searchResult = document.getElementById('search-result')
        searchResult.innerHTML = ''
        tagName.forEach(function(tag){
          const parentsElement = document.createElement('div');
          const childElement = document.createElement("div");

          parentsElement.setAttribute('id', 'parents')
          childElement.setAttribute('id', tag.id)
          childElement.setAttribute('class', 'child')

          parentsElement.appendChild(childElement)
          childElement.innerHTML = tag.name
          searchResult.appendChild(parentsElement)

          const clickElement = document.getElementById(tag.id);
          clickElement.addEventListener('click', () => {
            document.getElementById("post_name").value = clickElement.textContent;
            clickElement.remove();
          })
        })
      }
    });
  })
};

location.pathname.matchを使って、postsコントローラのnewアクションが発火した時に、コードが読み込まれるようにしています。

JS内のおおまかな処理としては、
①keyupでイベント発火させて、タグフォームの入力値をコントローラーへ送る(xhr.〇〇辺り)
②xhr.onload以下でコントローラーから返ってきた情報を元に、予測タグをフロントに表示させる。
③予測タグがクリックされたら、そのタグがフォームに反映される。

以上で、タグ付け機能の実装とインクリメンタルサーチの実装ができました。
ざっくりとした記事にはなりますが、最後までお読み頂きありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】投稿時間の日本語化

application.rbを修正

以下を追記。
config.i18n.default_locale = :ja
config.time_zone = 'Tokyo'

application.rb
require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module ChatApp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.0
    config.i18n.default_locale = :ja
    config.time_zone = 'Tokyo'

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
  end
end

ja.ymlファイルを作成

config/locales/ja.yml
ja:
  time:
    formats:
      default: "%Y/%m/%d %H:%M:%S"

lメソッドを用いて時間を日本化

以下は一例

html.erb
<div class="message-date">
  <!-- 投稿した時刻を出力する -->
  <%= l message.created_at %>
</div>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

メソッドについて

メソッド

プログラムにおける命令のことをメソッドと呼びます。
メソッドとは、プログラミングにおける何らかの処理をまとめたものです。
メソッド名をプログラム中に記述することで、そのメソッドの処理を実行できます。

メソッド.png

Rubyには便利なメソッドがたくさん用意されています。
たとえば、ターミナルで文字入力モードを起動する、指定した文字を
ターミナルに出力する、などのメソッドです。
また、特定の値にのみ使用できるメソッドもあります。

文字列にも、使用できるメソッドが用意されています。

まとめ

メソッドとは、プログラミングにおける何らかの処理をまとめたもの。

以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

文字列の連結方法

文字列の連結

文字列を連結させるには、文字列同士を+(プラス)で繋ぎます。数式と同じような書き方です。

以下の例では、HelloWorldの文字列が繋がっています。

【例】irb
# 文字列を連結
irb(main):001:0> "Hello " + "World"
=> Hello World

irbでコードを実行してみましょう!!

文字列を連結してみましょう。
以下の例のようにirbでコードを実行してみて下さい。

irb
# 文字列を連結
irb(main):001:0> "Good" + " morning"

# 続けてこのように表示されれば成功
=> "Good morning"

そうすることで、上記のように文字列の連結ができます!!

まとめ

irbとは、ターミナルから直接Rubyのプログラムを動かすことができる機能のこと。
文字列とは、プログラミングの中で文字を扱うための値のこと。
文字列は、+(プラス)で連結できる。

以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘録】MVCモデル まとめ

はじめに

筆者の漁った色々な知識を備忘録としてまとめ、残しています。

MVCとは

モデル(Model)頭文字「M」、ビュー(View)頭文字「V」、コントローラー(Controller)頭文字「C」の略であり、アプリケーション設定を整理するための概念。イメージはユーザーがブラウザで入力(クリック)した内容をWebアプリケーションで処理する流れ。

RubyonRailsは、MVCモデルで構成されている。

Model(モデル)

アプリケーション固有のデータを扱う部分です。Controllerからの依頼を受けて処理する(Modelに直接処理を記入することもある(例:「特定の文字列を探して抽出して」とか、「データベースのこの項目には空白入れないで」 等))。データベースに対して、データの登録や取得、更新、削除などの処理を行う。

View(ビュー)

PCの画面に関わる部分。データベースの情報を表示する場合、Controllerから情報を受け取り、ブラウザに表示させるHTMLを実際に組み立てる。

Controller(コントローラ)

ModelやViewを制御する部分です。ユーザーからのリクエスト(例:TOPから商品一覧(データベースに登録されてる商品)をみたい 等)を受けて、Modelと連携したり、どのView(画面)を表示するのかといったことを制御します。

RubyonRailsでは

プログラムの構造をMVCの役割によって分けることで、プログラムのメンテナンス性を向上させたり、複数人で開発するときに影響する箇所を限定できるようになっています。

抽象化すると

Viewが営業
Controllerが管理者
Modelが事務

Veiw(商品一覧)を表示する時
View     :問い合わせがあったので、Controllerさんお客さんに見せるプレゼン用のカタログください!
Controller  :了解!Viewくん! Modelさん!キャビネットからもってきて!
Model     :controllerさん、了解しました。今とってきます。

Viewでユーザーが新規会員登録された時
View     :Controllerさんお客さんから依頼とってきました!
Controller  :ありがとう!Viewくん! Modelさんに渡しとくね!
Model     :controllerさん、了解しました。記録残しておきますね。

そして各役割ごとに、業務をルーチン化して効率を向上させている。

みたいなイメージを持っています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘録】優しいMVCモデル まとめ

はじめに

筆者の漁った色々な知識を備忘録としてまとめ、残しています。

MVCとは

モデル(Model)頭文字「M」、ビュー(View)頭文字「V」、コントローラー(Controller)頭文字「C」の略であり、アプリケーション設定を整理するための概念。イメージはユーザーがブラウザで入力(クリック)した内容をWebアプリケーションで処理する流れ。

RubyonRailsは、MVCモデルで構成されている。

Model(モデル)

アプリケーション固有のデータを扱う部分です。Controllerからの依頼を受けて処理する(Modelに直接処理を記入することもある(例:「特定の文字列を探して抽出して」とか、「データベースのこの項目には空白入れないで」 等))。データベースに対して、データの登録や取得、更新、削除などの処理を行う。

View(ビュー)

PCの画面に関わる部分。データベースの情報を表示する場合、Controllerから情報を受け取り、ブラウザに表示させるHTMLを実際に組み立てる。

Controller(コントローラ)

ModelやViewを制御する部分です。ユーザーからのリクエスト(例:TOPから商品一覧(データベースに登録されてる商品)をみたい 等)を受けて、Modelと連携したり、どのView(画面)を表示するのかといったことを制御します。

RubyonRailsでは

プログラムの構造をMVCの役割によって分けることで、プログラムのメンテナンス性を向上させたり、複数人で開発するときに影響する箇所を限定できるようになっています。

抽象化すると

Viewが営業
Controllerが事業推進
Modelが事務

Veiw(商品一覧)を表示する時
View     :問い合わせがあったので、Controllerさんお客さんに見せるプレゼン用のカタログください!
Controller  :了解!Viewさん! Modelさん!キャビネットからもってきて!
Model     :controllerさん、了解しました。今とってきます。

Viewでユーザーが新規会員登録された時
View     :Controllerさんお客さんから依頼とってきました!
Controller  :ありがとう!Viewさん! Modelさんに渡しとくね!
Model     :controllerさん、了解しました。記録残しておきますね。

そして各役割ごとに、業務をルーチン化して効率を向上させている。
※viewとcontrollerには、実は課長(application_controller.rbとapplication_html.erb))がいて、課(フォルダ)内にまとめて命令を出せたりする。

みたいなイメージを持っています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘録】MVCモデル 簡単なまとめ

はじめに

筆者の漁った色々な知識を備忘録としてまとめ、残しています。

MVCとは

モデル(Model)頭文字「M」、ビュー(View)頭文字「V」、コントローラー(Controller)頭文字「C」の略であり、アプリケーション設定を整理するための概念。イメージはユーザーがブラウザで入力(クリック)した内容をWebアプリケーションで処理する流れ。

RubyonRailsは、MVCモデルで構成されている。

Model(モデル)

アプリケーション固有のデータを扱う部分です。Controllerからの依頼を受けて処理する(Modelに直接処理を記入することもある(例:「特定の文字列を探して抽出して」とか、「データベースのこの項目には空白入れないで」 等))。データベースに対して、データの登録や取得、更新、削除などの処理を行う。

View(ビュー)

PCの画面に関わる部分。データベースの情報を表示する場合、Controllerから情報を受け取り、ブラウザに表示させるHTMLを実際に組み立てる。

Controller(コントローラ)

ModelやViewを制御する部分です。ユーザーからのリクエスト(例:TOPから商品一覧(データベースに登録されてる商品)をみたい 等)を受けて、Modelと連携したり、どのView(画面)を表示するのかといったことを制御します。

RubyonRailsでは

プログラムの構造をMVCの役割によって分けることで、プログラムのメンテナンス性を向上させたり、複数人で開発するときに影響する箇所を限定できるようになっています。

抽象化すると

Viewが営業
Controllerが事業推進
Modelが事務

Veiw(商品一覧)を表示する時
View     :問い合わせがあったので、Controllerさんお客さんに見せるプレゼン用のカタログください!
Controller  :了解!Viewさん! Modelさん!キャビネットからもってきて!
Model     :controllerさん、了解しました。今とってきます。

Viewでユーザーが新規会員登録された時
View     :Controllerさんお客さんから依頼とってきました!
Controller  :ありがとう!Viewさん! Modelさんに渡しとくね!
Model     :controllerさん、了解しました。記録残しておきますね。

そして各役割ごとに、業務をルーチン化して効率を向上させている。
※viewとcontrollerには、実は課長(application_controller.rbとapplication_html.erb))がいて、課(フォルダ)内にまとめて命令を出せたりする。

みたいなイメージを持っています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【注意!!】Railsのdeviseとviewファイルをhamlに変換する時の注意点

こんばんは
アロハな男、やすのりです!

今日はdeviseのビューファイルを修正している時に遭遇した躓きポイントについてお話していこうと思います。

ただ、前提が当てはまる人は参考にしていってね!!

前提

Railsでアプリケーション作成中にGemの
deviseを使用していて、更にhaml-rails等でhtml.erbhtml.hamlに変換している人

状況

ファイル名

deviseの新規登録ページのビューファイルに名前の入力欄を追加したいと思いコード修正していました。

views/users/registrations/new.html.haml
%h2 Sign up
= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
  = render "users/shared/error_messages", resource: resource
  .field
    = f.label :name
    %br/
    = f.text_field :name, autofocus: true
  .field
    = f.label :email
    %br/
    = f.email_field :email, autofocus: true, autocomplete: "email"
  .field
    = f.label :password
    - if @minimum_password_length
      %em
        (#{@minimum_password_length} characters minimum)
    %br/
    = f.password_field :password, autocomplete: "new-password"
  .field
    = f.label :password_confirmation
    %br/
    = f.password_field :password_confirmation, autocomplete: "new-password"
  .actions
    = f.submit "Sign up"
= render "users/shared/links"

ということで、:nameの欄を足してこれでバッチリだ!!
と、思っていたら...
ファイル名

...え?
何も変わってなくない??あれ???

修正するビューファイル間違えたかな?と思って確認してみても間違いなく registrations って書いてあるし...

ファイル名
あれ!?
なぜか、new.html.erbを参照してる!?
しかも参照先がapp/views/deviseregistrations/new.html.erbになってるぞ!?

と、思いいろいろ調べて見ると原因が見えてきました。

原因

僕のアプリケーションの構成上、deviseにUserモデルを持たせていたので、deviseのビューファイルを生成する時に$ rails g devise:views usersとコマンドを打っていたんですが、これが原因みたいです。
そもそもdeviseのモデルがUserモデル以外に無いのであれば、$ rails g devise:viewsだけで良かったみたいです。
※Userモデル以外というよりは、deviseのモデルが1つだけの時と言う方が正しいかも?

2つのコマンドの違いは?

生成されるビューファイルのディレクトリ構造が少し変わってしまいます。
具体的には$ rails g devise:views usersとコマンドを打った場合は、

app/views/users/以下にディレクトリとビューファイルが生成されます。

一方、$ rails g devise:viewsとコマンドを打った場合は

app/views/devise 以下にディレクトリとビューファイルが生成されます。

deviseディレクトリ...

ファイル名

これだぁぁあああ!!

はい、ということでビューファイルを生成した段階でコミットしていたので、コミット履歴を削除してコマンドを打ち直した後に、新規ビューファイルのコードを修正してみました。

すると...

ファイル名

よしっ!!
名前の入力欄が加わってるぞ!!

ファイル名

参照先もちゃんとnew.html.hamlになってる!!

結論

deviseのビューファイルを生成する時は、基本$ rails g devise:viewsでOK!!

皆さんも気をつけてね!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【エラー】Mysql2::Error: Specified key was too long; max key length is 767 bytes

エラーの忘備録

エラー内容

rails db:migrateをした時に、以下のエラー文が出ました。(Mysqlのエラー)

Mysql2::Error: Specified key was too long; max key length is 767 bytes

指定したキーが長すぎるというエラーです。
テーブルに色々カラムを追加すると、キーの制限である767バイトを超えてしまうため
このエラーが起こってしまいます。

原因

config/database.yml
  default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock

encoding: utf8mb4という記述のためエラーが出ます。

解決方法

encoding: utf8に書き換えます。

config/database.yml
  default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock

utf8mb4とutf8の違いはいまいちわかっていないのですが、utf8mb4は1〜4バイト、utf8は1〜3バイトの文字が格納できるようです。そのためutf8だと、絵文字などは保存できませんが、代わりに容量が大きくなるのではないかな?と推測しました。

すでにrails db:createでデータベースを作成してしまっている場合は、

% rails db:drop
% rails db:create

% rails db:reset

で、もう一度データベースを作り直してあげる必要があります。

おわりに

もし間違えている点などございましたら、ご指摘いただけましたら幸いです。
読んでいただきありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】アソシエーション

中間テーブル

データ型:referencesとforeign_keyをセットで使用する。
referencesはPKを参照する。よって、:userと記述しているがカラム名はuser_idとなる。
foreign_keyで、他テーブルの情報を参照できる。

model.rb
class CreateRoomUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :room_users do |t|
      t.references :user, null: false, foreign_key: true
      t.references :room, null: false, foreign_key: true
      t.timestamps
    end
  end
end

dependent: :destroy

親子関係のデータについて、親を削除した際に子も削除されるようにする。

親モデルのhas_manyにdependent: :destroyを追記。

(例)親モデル:user、子モデル:post

class User < ApplicationRecord
  has_many :posts, dependent: :destroy
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[エラー]background-image: image-urlでSassC::SyntaxError

background-image: image-urlでSassC::SyntaxError

デプロイ前にcssに記述したbackground-imageを
下記のように記述したら SassC::SyntaxError となりました。

background-image: image-url("IMG_4335 (1).JPG");

原因は文字間にスペースがあったからでした。
初歩的なミスに随分時間を費やしてしまいました。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Macを買い換えたので個人的に便利なアプリや開発ツールをまとめてみた(アプリ編)

Macbook Proをクラムシェルモードで運用していたが、あまりにも本体が熱くなりすぎて寿命が心配になってきたのでiMacを購入しました。
なるべくクリーンな状態で必要なアプリ・ツールのみをインストールしたかったので、それらをまとめる個人的なメモ + どこが気に入ってるのか なども併せてご紹介します。

まっさらな状態から、neovimを使ってRails開発が行えるところまでをゴールとします。
いつかまたセットアップする機会がきたときに役に立てばいいかな!

今回は、「アプリ編」として筆者が仕事で使っているアプリや、よく利用していて便利だなと思っているアプリをまとめました。
よく見かけるものばっかりだと思いますので、あくまで参考程度にご覧ください。

導入するもの

名前 用途
Logi Options Logicool用マウスの機能拡張
Karabiner-Elements キーボードのキーバインド変更
The Unarchiver ファイル解凍
BetterSnapTool ウィンドウリサイズ
Aspect Ratio Calculator 比率計算
ATOK 日本語入力
Dropbox オンラインストレージ
Photoshop 写真編集
Microsoft 365 ドキュメント編集
Notion 情報集約ツール
Todoist タスク管理
Trello タスク管理

Logi Options

Logicoolの Mx Master 3 というマウスを使用しており、それに色々な便利機能を追加してくれます。
スクリーンショット 2020-10-22 1.57.40.png

Mx Master自体はスクロールホイールの機構が特殊で、一定の速度以上でホイールを回すと滑らかに回転し、長いページも一瞬でスクロールできてめちゃくちゃ便利。
また横にスクロールするためのサムホイールなるものもあるので、Excelなんかでは重宝します。
Logi Optionsではアプリ毎にボタンの動作を変更したり、異なるOS同士でマウスカーソルを共有したり、ファイルの転送をおこなえるようになるので、導入必須ですね。

ダウンロード先
https://www.logicool.co.jp/ja-jp/product/options

Karabiner-Elements

キーマップの変更や、マウスなどの操作をキーボードで行えるようにしたり、エディタのショートカットを設定できたりと、俺に任せろといわんばかりに色々できる。
設定が面倒な人でも既存の設定をインポートすることが可能なので、あれこれいじらなくてもすぐに便利さを感じれると思う。
スクリーンショット 2020-10-22 2.30.17.png

上の画像のように、vimでCtrl+[を押下したときに自動的に半角英数入力にすることができたり、Ctrlキーを押すだけで英数・かなを切り替えられる。
ちなみにhhkbのUS配列を使ってる人は、このCtrlキーでのアクションはめちゃくちゃ便利。

ダウンロード先
https://karabiner-elements.pqrs.org/

The Unarchiver

Macの解凍ツールといえばこれ。これ以外知らない
Windows用ファイルも問題なく解凍してくれます。
それ以上でもそれ以下でもないような定番アプリ。

ダウンロード先
https://apps.apple.com/jp/app/the-unarchiver/id425424353?mt=12

BetterSnapTool

Windowsのように画面隅にアプリ画面を移動することにより、決められた大きさにリサイズしてくれるもの。
もう少し詳しく書くと、Safariのウィンドウバーをモニター画面上部にドラッグすれば自動的に最大化を行ってくれます。
なぜMacのデフォルト機能として存在しないのか不思議です。

ちなみにMagnetという似たようなアプリもあって、そちらのほうがAppStoreでは人気みたいです。(設定時の言語がこちらと異なり、日本語だからかな?)
筆者はマルチモニター環境でして、キーショートカットでウィンドウを他のモニターで表示するように移動させたかったので、こちらのアプリにしました。
Magnetでは設定が見当たらなかったので、マルチモニタ環境の人はこちらがおすすめです。

ダウンロード先
https://apps.apple.com/jp/app/bettersnaptool/id417375580?mt=12

Aspect Ratio Calculator

たぶんほとんどの人には必要ないかもしれない・・・。
アスペクト比を自動計算してくれます。

似たようなアプリはたくさんあるのですが、Macの右上に常時表示できて、クリックするとどのウィンドウよりもトップで表示され、なおかつ見やすい。
探してみると意外とこんな表示にこだわったアプリはなかったので、採用しました。

ダウンロード先
https://apps.apple.com/jp/app/aspect-ratio-calculator/id955155151?mt=12

ATOK

日本語入力に最適なIME。
月額300円ほどのサブスクリプションに登録しています。
Google日本語入力を使っていた時期もありまして、そちらと比べて変換ミスが起きにくいのと、
かな入力時でも半角スペースを入力できるオプションが便利で使っています。(Googleのほうでも、もしかしたらできるかもしれません。)
スクリーンショット 2020-10-22 3.29.33.png

ダウンロード先
https://mypassport.atok.com/install/install_mac.html

Dropbox

オンラインストレージサービスの先駆け。
その後色々な競合サービスが打ち出されてきましたが、筆者の周りではみんなこれでファイル共有しているので、仕方なく導入しています。
ファイルが保存できるだけではなく、Excelファイルを同時編集している人がいないか確認できたり、色んなサイトに登録したパスワードなどを安全に保管出来るなど、便利な機能があります。

ダウンロード先
https://www.dropbox.com/install

Photoshop

仕事で写真編集をする機会が多いので使っています。
特にPhotoshopじゃないと出来ないことをしているわけではないですが、「コンテンツに応じた塗りつぶし」機能は他のアプリより優れていたので使っています。
これは写真から消したいオブジェクトを合成で綺麗に消してくれるものなのですが、最近はどのように消えるかプレビュー画面で確認しながら、
写真のどの部分をサンプリングするのか自分で編集できるようにもなって、どんどん便利になっていってる機能でもあります。

撮影時に通行人が写ってしまうっていうときに、大変便利なわけですね。
ただ消したいオブジェクトによって隠れていた箇所を機械的に導きだすわけなので、複雑な模様などはうまく処理できません。
retatti_top-715x409.png

ダウンロード先
https://www.adobe.com/jp/products/photoshop.html

Microsoft 365

説明するまでもないOfficeのサブスクリプションサービスですね。
筆者は仕事でもばりばりというか、ただテストのエビデンス画像を貼るだけなのにExcelを使わされているのですが、Web系エンジニアの方も使われているのでしょうか?
VBAマクロが入ったドキュメントを使うことが多いので課金してますが、正直無料のもので十分な気がしています(泣

ダウンロード先
https://www.microsoft.com/ja-jp/microsoft-365/try

Notion

最近知りまして、これから使っていきたいと思っている情報集約アプリ。
説明がむずかしいのですが、Excel・Word・PowerPointなどなどをまとめたようなツールです。
Evernoteに似ていますが、デフォルトでMarkdownに対応しており、起動も早く、データテーブルを用いて集計を行ったり、豊富な機能がそろっております。
ただ学習コストが異常に高いので、ミニマルに初めてみて徐々に色々な機能を使ってみてください。じゃないと挫折する可能性が高い。(筆者も一度挫折しています。)
スクリーンショット 2020-10-22 16.01.53.png

使い始めは、以下の記事を読むとわかりやすいです。
わかる、Notion 徹底入門

ダウンロード先
https://www.notion.so/desktop

Todoist

タスク管理アプリ。
iPhoneアプリ、デスクトップアプリもあり、特に課金しなくても同期してくれる点が魅力的。
TODOの表示形式もリスト、カンバン両方に対応していますし、なによりタスクの追加までがシンプルで簡単なので億劫にならない。
Googleカレンダーと同期して、相互にタスクが連携されるように設定しています。

スクリーンショット 2020-10-22 16.06.24.png

ダウンロード先
https://todoist.com/ja

Trello

こちらもタスク管理アプリ。
仕事で使用していますが、カンバン方式で視覚的にわかりやすく、タスクの状態が変化していくような管理方法に向いていると思います。
個人で使用するときは、追加までのアクションが少ない上記のTodoistになりましたが、タスクのサムネイル画像をつけられたり便利な面があるので、使い分けてもよさそうです。
Trello-Butler-Done-Drag-1 (1).gif

ダウンロード先
https://todoist.com/ja

まとめ

本当によく見かけるものだったと思いますが、そういったサービスはそれだけ便利であるということですね笑
ブラウザ上で利用しているものは省きましたが、とりあえずこれだけあれば問題ないものをまとめてみました。
この中ではNotionの可能性がやばいと思っているので、早く使い慣れたいなと思っております。

筆者はまだMac環境になって日が浅く、これまでずっとWindows環境だったんですね。
なのでMacの便利な機能やアプリを探したり、それこそ初期設定が思っていたより大変でした!
同じような方の参考になればうれしい! もしおすすめなどあれば教えてください!

次回は、開発ツール編をまとめたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails 5 コードリーディング 第2回 ~ActionView編~

    class RenderedTemplate # :nodoc:
      attr_reader :body, :template

      def initialize(body, template)
        @body = body
        @template = template
      end

      def format
        template.format
      end

      EMPTY_SPACER = Struct.new(:body).new
    end

formatメソッド内の templateが@templateとインスタンス変数でないのはなぜか?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

heroku コマンドが使えなくなったときのメモ

ある日bash: heroku: command not foundでherokuコマンドが使えなくなりました。
git push heroku masterは使えました。
heroku open やheroku rake db:migrate が使えなかったです。

npm install -g heroku

したら治りました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsで申し込み機能を実装する

Railsを用いた投稿の申し込み機能とキャンセル機能の実装方法について解説します。
※ユーザー機能と投稿機能は実装済みであることを前提とします。

実装の流れ

大まかな流れとして、以下の手順で実装していきます。
1. 投稿と申込者の中間テーブルを作成する
2. モデル同士の関連付け(アソシエーション)を行う
3. ルーティングを定義する
4. コントローラーに申し込み機能とキャンセル機能を定義する
5. 申込ボタンのビューを作成する

投稿と申込者の中間テーブルを作成する

投稿は複数人の申込者を持つことができ、ユーザーは複数の投稿に申し込むことができます。
そのため、投稿とユーザーは多対多の関係となり、中間テーブルが必要となります。

また、ここでは同じユーザーの中でも投稿者と申込者を区別するために、申込者をtakerと定義することにします。
投稿のモデル名をPostとすると、post_takersという中間テーブルを作れば良いということになります。

中間テーブルを作成するにはまず、ターミナルに以下のコマンドを打ちモデルを作成します。

$ rails g model PostTaker

出来上がったマイグレーションファイルを開き、以下のように記述します。

2020XXXXXXXXXX_create_post_takers.rb
class CreatePostTakers < ActiveRecord::Migration[6.0]
  def change
    create_table :post_takers do |t|
      t.references :post, foreign_key: true
      t.references :taker, foreign_key: {to_table: :users} 
      t.timestamps
    end
  end
end

ここでのポイントは、t.references :taker, foreign_key: {to_table: :users}の部分です。
このように書くと、中間テーブルの外部キーとして申込者であるtakerという名前を定義しつつ、usersテーブルを参照できます。
参考記事:https://qiita.com/publichtml/items/1fba15d8071fab66d043

モデル同士の関連付け(アソシエーション)を行う

次に、モデルにアソシエーションを記述します。

user.rb
class User < ApplicationRecord
  has_many :post_takers, foreign_key: "taker_id", dependent: :destroy
end
post.rb
class Post < ApplicationRecord
  has_many :post_takers, dependent: :destroy
  has_many :takers, through: :post_takers, dependent: :destroy
end
post_taker.rb
class PostTaker < ApplicationRecord
  belongs_to :taker, class_name: 'User', foreign_key: 'taker_id'
  validates_uniqueness_of :post_id, scope: :taker_id
end

post_taker.rbのbelongs_to :taker, class_name: 'User', foreign_key: 'taker_id'は、
このような書き方をすることでUserモデルに紐付いた申込者と関連付けができます。
参考記事:https://qiita.com/gyu_outputs/items/421cc1cd2eb5b39e20ad

また、validates_uniqueness_of :post_id, scope: :taker_idは、
投稿と申込者の同じ組み合わせが2つ以上登録されないようにするため、このようなバリデーションを記述しています。

ルーティングを定義する

申し込むというアクションをtake、キャンセルというアクションをcancelとしてルーティングに以下のように記述します。

routes.rb
Rails.application.routes.draw do
  resources :posts do
    member do
      get 'take'
      get 'cancel'
    end
  end
end

上記では、パスに投稿のidを含めるためmemberを使っています。
参考記事:https://qiita.com/hirokihello/items/fa82863ab10a3052d2ff

コントローラーに申し込み機能とキャンセル機能を定義する

コントローラーに以下の記述を追加します。
※ここでは投稿詳細ページに申込ボタンを表示させることを前提として書いていますが、各々の状況に合わせて書き換えてください。

posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post

  def show
    @user = @post.user
  end

  def take
    # 該当の投稿とログイン中のユーザーとの中間テーブルのレコードを作成する
    PostTaker.create(post_id: @post.id, taker_id: current_user.id)
    # フラッシュメッセージを表示(フラッシュメッセージを表示させない場合は書かなくて大丈夫です)
    flash[:notice] = '申し込みが完了しました。'
    # 投稿の詳細ページにリダイレクト
    redirect_to action: "show"
  end

  def cancel
    # 中間テーブルの中から、該当の投稿とログイン中のユーザーによるレコードを抽出する
    post_taker = PostTaker.find_by(post_g_id: @post.id, taker_id: current_user.id)
    post_taker.destroy
    flash[:notice] = 'キャンセルが完了しました。'
    redirect_to action: "show"
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end
end

申込ボタンのビューを作成する

最後に、申込ボタンのビューを作成したら完成です!
以下のコードはhamlで記述しています。

show.html.haml
-# 投稿者とログイン中のユーザーが一致しない場合のみボタンを表示させる
- if @user.id != current_user.id
  -# 該当の投稿の申込者の中に、ログイン中のユーザーが含まれているか否かで場合分けする
  - if @post.taker_ids.include?(current_user.id)
    = link_to "申し込みをキャンセルする", cancel_posts_path(@post.id), data: { confirm: "こちらの投稿の申し込みをキャンセルしますか?" }
  - else
    = link_to "申し込む", take_posts_path(@post.id), data: { confirm: "こちらの投稿に申し込みますか?" }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails 5 コードリーディング 第一回 ~ActiveRecord newメソッド編~

Railsの使い方はなんとかわかるにようなりました。

でも、コーディング力が足りない。

他の言語に行った時に、応用力がつかないのではないか、、、

と思ったので、

Railsのソースコードを読んでみることにした。

こちらを参考にしてみました。
Railsコードを読んでみた

Active record 周りを読んでみることに
まずは、shift command f で
def new を
全文検索

# frozen_string_literal: true

module ActiveRecord
  # = Active Record \Relation
  class Relation
    MULTI_VALUE_METHODS  = [:includes, :eager_load, :preload, :select, :group,
                            :order, :joins, :left_outer_joins, :references,
                            :extending, :unscope, :optimizer_hints, :annotate]

    SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
                            :reverse_order, :distinct, :create_with, :skip_query_cache]

    CLAUSE_METHODS = [:where, :having, :from]
    INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :group, :having]

    VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS

    include Enumerable
    include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation

    attr_reader :table, :klass, :loaded, :predicate_builder
    attr_accessor :skip_preloading_value
    alias :model :klass
    alias :loaded? :loaded
    alias :locked? :lock_value

(と中略)

    # Initializes new record from relation while maintaining the current
    # scope.
    #
    # Expects arguments in the same format as {ActiveRecord::Base.new}[rdoc-ref:Core.new].
    #
    #   users = User.where(name: 'DHH')
    #   user = users.new # => #<User id: nil, name: "DHH", created_at: nil, updated_at: nil>
    #
    # You can also pass a block to new with the new record as argument:
    #
    #   user = users.new { |user| user.name = 'Oscar' }
    #   user.name # => Oscar
    def new(attributes = nil, &block)
      block = _deprecated_scope_block("new", &block)
      scoping { klass.new(attributes, &block) }
    end

    alias build new

(途中略)

def _deprecated_spawn(name)
        spawn.tap { |scope| scope._deprecated_scope_source = name }
      end

      def _deprecated_scope_block(name, &block)
        -> record do
          klass.current_scope = _deprecated_spawn(name)
          yield record if block_given?
        end
      end

    def new(attributes = nil, &block)
      block = _deprecated_scope_block("new", &block)
      scoping { klass.new(attributes, &block) }
    end

    alias build new

まずは漠然と理解する

1.
新しいものレコードを作るから attribute(属性)はnil
2.
ブロック引数を渡しているが、ブロックはどこにあるのか?
3.
_deprecated_scope_block メソッドが下に定義されているが、意味がわからない
4.
klassとは何か?

疑問は尽きない
もうちょっとさぐってみる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]rails-i18nを用いた日本語化

はじめに

rails-i18nというgemを用いることでエラーメッセージなどを日本語化することができます。

目次

  1. 言語を日本語に設定する
  2. rails-i18nのインストール
  3. 日本語に設定するためのファイルを作成

1. 言語を日本語に設定する

application.rbを編集します。

:jaとすることで日本語に設定することができます。

config/application.rb
module CosmeticReview
  class Application < Rails::Application
    config.load_defaults 6.0
    #以下の記述を追記します
    config.i18n.default_locale = :ja
  end
end

2. rails-i18nのインストール

gemfileに以下を追記します。
その後、コマンドでbundle installを実行します。

gemfile
gem 'rails-i18n'

3. 日本語に設定するためのファイルを作成

localファイルを作成し、その中に日本語へ翻訳するためのYAMLファイルを作成します。
今回はモデルのエラーメッセージを日本語化しました。

locales/ja.yml
ja:
 activerecord:
   attributes:
     user:
       nickname: ニックネーム
       gender: 性別
       introduce: 自己紹介
       birthday: 生年月日 
     post:
       name: 商品名
       description: 商品の説明
       image: 画像
       shop_name: 購入店
       evaluation: 商品の評価
       price: 購入価格
       category_id: カテゴリー
   time:
     formats:
       default: "%Y/%m/%d %H:%M:%S"

階層が少しでもずれているとエラーが出るので気をつけましょう。

参考リンク

https://github.com/svenfuchs/rails-i18n

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQL 8.0 を 5.7 感覚で触っていたらハマった my.cnf の設定問題

概要

スクリーンショット 2020-10-22 12.39.42.png

ここではRailsアプリの開発ではありますが、Webアプリを開発しているとこのエラーに引っかかった方はわかると思います。

this is incompatible with sql_mode=only_full_group_by

問題の詳細はいろんな記事で解説されているので以下の記事などを読んでいただければなと。
今回は、MySQL 8.0 を 5.7 感覚で触っていたらハマった内容となります。

環境

$ mysql --version
mysql  Ver 8.0.21 for Linux on x86_64 (MySQL Community Server - GPL)

現象

mysqldの設定は、上記の記事を参考に設定した内容です。
そうすると以下のエラーが発生しました。

$ mysql --help | grep my.cnf
                      order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf
$ sudo vi /etc/my.cnf

---
[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
---

$ systemctl restart mysqld.service
Failed to restart mysqld.service: The name org.freedesktop.PolicyKit1 was not provided by any .service files

$ sudo systemctl status mysqld.service
● mysqld.service - MySQL Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since 木 2020-10-22 03:50:33 UTC; 27s ago
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
  Process: 8909 ExecStart=/usr/sbin/mysqld $MYSQLD_OPTS (code=exited, status=1/FAILURE)
  Process: 8885 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
 Main PID: 8909 (code=exited, status=1/FAILURE)
   Status: "Server startup in progress"
    Error: 2 (No such file or directory)
10月 22 03:50:32 xxx-xxx-xxx-xxx.yyyyy.zzz systemd[1]: Starting MySQL Server...
10月 22 03:50:33 xxx-xxx-xxx-xxx.yyyyy.zzz systemd[1]: mysqld.service: main process exited, code=exited, status=1/FAILURE
10月 22 03:50:33 xxx-xxx-xxx-xxx.yyyyy.zzz systemd[1]: Failed to start MySQL Server.
10月 22 03:50:33 xxx-xxx-xxx-xxx.yyyyy.zzz systemd[1]: Unit mysqld.service entered failed state.
10月 22 03:50:33 xxx-xxx-xxx-xxx.yyyyy.zzz systemd[1]: mysqld.service failed.

$ sudo less /var/log/mysqld.log
...
2020-10-22T03:50:33.416784Z 0 [ERROR] [MY-000077] [Server] /usr/sbin/mysqld: Error while setting value 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' to 'sql_mode'.
2020-10-22T03:50:33.416979Z 0 [ERROR] [MY-010119] [Server] Aborting

原因

使用していたMySQLは 8.0 で特に意味もなく 5.7 感覚で使用していたことで起きた問題でした汗
MySQL 8.0 では、 sql_mode の内容が 5.7 から一部変更があり、今回は NO_AUTO_CREATE_USER が削除されていたことでハマりました。

対処

NO_AUTO_CREATE_USERを削除した以下の設定で無事にMySQLが起動して、概要のエラーが解消できました。

[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vagrant上で作成したポートフォリオをdockerの開発環境に移行してみた

はじめに

初めまして、初投稿になりますので自己紹介と記事のきっかけについて書かせていただきます。

  • 自己紹介
    2020年9月にDMMWEBCAMPを卒業し、現在転職活動中のエンジニアです。

  • 記事のきっかけ
    他のプログラミングスクールが同じかはわかりませんが、スクール生で共通の開発環境にするために全てvagrant上で仮想環境を構築しカリキュラムとポートフォリオの作成を行っていました。そのため、0からの自力で環境構築を行ったことがなく実務を意識するのならDockerぐらいは自力で入れておきたいと思い学習し始めたのがきっかけです。
    まだまだ勉強中のため、正直かなり怪しいところは多いとは思いますが同じような勉強中の方の参考に少しでもなれば嬉しいです!

この記事で扱うこと

  • Dockerを使用した開発環境の構築
    Vagrant上でできていたことがDocker上でもできるようにするイメージです

  • Dockerfile、docker-composeなどの表記
    参考までに、Vagrantを使用していた時の開発環境は下記になります

    • OS:macOS Catalina 10.15.4
    • バックエンド: Ruby 2.5.7、Rails 5.2.4.3
    • 開発環境: Vagrant 2.2.4、SQLite (※MySQLやPostgreSQLの場合、この後の見本の表記が異なります)
    • 本番環境: MySQL2、AWS (EC2、RDS for MySQL、Route53)、Nginx、 Puma、Capistrano

スクリーンショット 2020-09-13 12.40.05.png

  • 0からの開発環境の構築で起こりうるエラーと解決した方法
    記事のきっかけにもあるように、ローカル環境の構築自体も初めてのためdocker以前のエラーもいくつかありました。解決のために参考にさせていただいた記事をメインに紹介していきたいと思います。

この記事で扱わないこと

  • Dockerfile、docker-composeなどの基礎知識

    Dockerに関する記事やyoutube多くありますがほとんどがコピペでなんとなく進んでしまうので、最初は自分でドキュメントを読みながら手を動かして全体の仕組みをなんとなく先に掴んでおくのが理解しやすいと思いました。
    参考までに自分は下記サイトで学習を始めました。各用語調べながらでも半日〜2日ほどでできる内容かつDockerのイメージが掴めるかと思いますのでおすすめです。

事前準備

$ docker version
Client: Docker Engine - Community
 Cloud integration  0.1.18
 Version:           19.03.13
 API version:       1.40
  • ポートフォリオ(Dockerの開発環境にしたいプロジェクト)をgit cloneしてくる
    記事のきっかけにもありますよう、既にポートフォリオを作成している段階のため環境構築したいものをgithubからローカル上に持ってきましょう
$ mkdir docker
 # Desktopからもしくはvagrantを使用していた時のworkディレクトリなどで実行
$ git clone git@github.com:ユーザー名/リポジトリ名.git

各ファイルの準備

Dockerとプロジェクトの準備ができたので、環境構築に必要なファイルを作成していきます

①Dockerfile

# 先ほどクローンしたディレクトリ上で
$ touch Dockerfile

下記内容を記入していきましょう

# 元となるdocker imageを指定。ポートフォリオのrubyのバージョンと合わせましょう
FROM ruby:2.5.7

RUN apt-get update -qq && apt-get install -y nodejs postgresql-client

RUN apt-get update && apt-get install -y nodejs --no-install-recommends && rm -rf /var/lib/apt/lists/*
#sqlite3を指定
RUN apt-get update && apt-get install -y sqlite3 --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

# コンテナ起動した時に、コンテナ内でmyappディレクトリを作成
RUN mkdir /myapp

# コンテナ内の作業ディレクトリの指定(上のRUNで作成したディレクトリ)
WORKDIR /myapp

# ホストマシンのgemfileをコピーし、コンテナ内のディレクトリに貼り付け
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock

# 貼り付けたgemfileを読み込み。bundlerバージョンが2以降だとこれが必要
ENV BUNDLER_VERSION 2.1.4
RUN gem install bundler
RUN bundle install

# アプリケーション(カレントディレクトリ)をコピーして、コンテナ内のディレクトリに貼り付け
COPY . /myapp

# ポートを3000で公開
EXPOSE 3000

# コンテナにてコマンドを実行
CMD ["rails", "server", "-b", "0.0.0.0", "-p", "3000"]
  • ENV BUNDLER_VERSION 2.1.4について
    Gefile.lockの一番下にこのような表記があるかと思いますので確認してみて下さい
Gemfile.lock
BUNDLED WITH
   2.1.4

②docker-compose.yml

# 同じディレクトリ上で
$ touch docker-compose.yml

下記内容を記入していきましょう

docker-compose.yml
version: '3'
services:
  web:
    build:
      context: ./
      dockerfile: Dockerfile 
    # 変更を保存するファイルを指定
    volumes:
      - .:/myapp
    # ポートを指定
    ports:
      - "3000:3000"
    # コンテナの起動を維持させる
    tty: true
    stdin_open: true

MySQLやPostgreSQLを使用している場合だと、web+DBの記述も必要なのですがSQLiteの場合はこちらのみで大丈夫みたいです。まだこの辺りの知識が乏しいため、ゆくゆくはMySQLに変更したいと思っております・・・

コンテナを起動してみましょう

# Dockerfileを元にdocker imageの作成
$ docker-compose build 

# docker container をバックグランドで起動
$ dokcer-compose up -d

# コンテナ内にてmigrationを更新
docker-compose run web rails db:migrate

これで、いつものlocalhost:3000で表示ができればひと段落です!

引っかかったエラーと解決した方法

大体ですが引っかかった時系列順に記載していきます。最初にも記載しておりますが、エラー内容とおそらくの原因の考察がサブで、メインが解決参考にさせていただいた記事の紹介になります。ありがとうございました

①ActiveRecord::PendingMigrationError Migrations are pending

「dokcer-compose up -d で動いているのにっ・・・!」

$ docker-compose up -d                                                  
Creating network "~~~_default" with the default driver
Creating ~~~_web_1 ... done

localhost:3000のページへアクセス時に起きたエラーです
コンテナの起動後、docker-compose run web rails db:migrate を行いましょう、あるあるな気がします
参考:docker-compose upで立ち上げたRailsでActiveRecord::PendingMigrationError Migrations are pending

②To install the missing version, run 'gem install bundler:2.1.4'

「bundleで始まるコマンド(デプロイ・Rspecなど)ができないっ・・・!」

Traceback (most recent call last):
    2: from 
    1: from 
~
Could not find 'bundler' (2.1.4) required by your /Users/ユーザー名/ディレクトリ名/Gemfile.lock. (Gem::GemNotFoundException)
To update to the latest version installed on your system, run `bundle update --bundler`.
To install the missing version, run `gem install bundler:2.1.4`

Dockerfileを作成した時に確認した、Gemfile.lockの「BUNDLED WITH 2.1.4」がローカル上で見つからないイメージです。
参考:To install the missing version, run gem install bundler:2.1.4と出たときの対処法

エラー文の通りにインストールを試してみましょう、ダメだった場合は③へ

gem install bundler -v 2.1.4

③ERROR: While executing gem ... (Gem::FilePermissionError)

ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /Library/Ruby/Gems/2.3.0 directory.

「gemのインストールの権限がありませんっ・・・!」
sudoを頭につけて行うという記事も多かったですが、そのままインストールよりも「rbenv」というバージョン管理のツールを用いて行う方法の方が今後のことを考えるといい気がします。

参考1:gem installでpermissionエラーになった時の対応方法
参考2:rbenvによるRubyのインストールからHello, World!まで

rbenvの用意ができたら、もう一度やってみましょう

gem install bundler -v 2.1.4

④bundle installができない

「bundleが・・・まだダメっ・・・!」

gem installができたところで、デプロイなどの「bundle~」系を入力するとまだエラー文がでます

Install missing gem executables with `bundle install`

エラー文に従って、bundle installをしてみると

# 長いため、最後の部分だけ抜粋
An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  mysql2

mysql周辺のエラーですが、原因は自力ではわかりませんでした。
下記の参考にさせていただいた記事通りで私は解決できました、本当にありがたい。

参考:【Rails】MySQL2がbundle installできない時の対応方法

これでデプロイはできるようになると思います。

⑤Could not find a JavaScript runtime ~

「動いているけどっ・・・!」

Rspecを走らせた時のエラーです

$ bundle exec rspec spec/ --format documentation

An error occurred while loading ./spec/models/cart_item_spec.rb.
Failure/Error: require File.expand_path('../config/environment', __dir__)

ExecJS::RuntimeUnavailable:
  Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes.

githubに飛んでみると、ExecJSのどれかをダウンロードするよう勧めています。
gemをいれる方法もありましたが、Node.jsを選択してダウンロードに進めばスムーズに解決できました。

これでRspecもできるようになりました。

終わりに

vagrantからdockerへの移行の手順とエラーの紹介をさせていただきました。
まだまだ勉強不足なところも多いため、dockerを十分に活用できていない点が多くあると改めて思いました。
参考にさせていただいた記事が多かったこともあり、当初思っていたよりも短い時間で導入まではできたので挑戦してみて良かったと感じています。

以前のvagrant環境と同じことはできるようになったので、次はCircleCIの導入でより良い開発環境にできるよう学習を続けたいと思います。

初投稿ということもあり、わかりにくい部分もあったかとは思いますが最後までみていただきありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vagrant上で作成したポートフォリオをDockerの開発環境に移行してみた

はじめに

初めまして、初投稿になりますので自己紹介と記事のきっかけについて書かせていただきます。

  • 自己紹介
    2020年9月にDMMWEBCAMPを卒業し、現在転職活動中のエンジニアです。

  • 記事のきっかけ
    他のプログラミングスクールが同じかはわかりませんが、スクール生で共通の開発環境にするために全てvagrant上で仮想環境を構築しカリキュラムとポートフォリオの作成を行っていました。そのため、0からの自力で環境構築を行ったことがなく実務を意識するのならDockerぐらいは自力で入れておきたいと思い学習し始めたのがきっかけです。
    まだまだ勉強中のため、正直かなり怪しいところは多いとは思いますが同じような勉強中の方の参考に少しでもなれば嬉しいです!

この記事で扱うこと

  • Dockerを使用した開発環境の構築
    Vagrant上でできていたことがDocker上でもできるようにするイメージです

  • Dockerfile、docker-composeなどの表記
    参考までに、Vagrantを使用していた時の開発環境は下記になります

    • OS:macOS Catalina 10.15.4
    • バックエンド: Ruby 2.5.7、Rails 5.2.4.3
    • 開発環境: Vagrant 2.2.4、SQLite (※MySQLやPostgreSQLの場合、この後の見本の表記が異なります)
    • 本番環境: MySQL2、AWS (EC2、RDS for MySQL、Route53)、Nginx、 Puma、Capistrano

スクリーンショット 2020-09-13 12.40.05.png

  • 0からの開発環境の構築で起こりうるエラーと解決した方法
    記事のきっかけにもあるように、ローカル環境の構築自体も初めてのためdocker以前のエラーもいくつかありました。解決のために参考にさせていただいた記事をメインに紹介していきたいと思います。

この記事で扱わないこと

  • Dockerfile、docker-composeなどの基礎知識

    Dockerに関する記事やyoutube多くありますがほとんどがコピペでなんとなく進んでしまうので、最初は自分でドキュメントを読みながら手を動かして全体の仕組みをなんとなく先に掴んでおくのが理解しやすいと思いました。
    参考までに自分は下記サイトで学習を始めました。各用語調べながらでも半日〜2日ほどでできる内容かつDockerのイメージが掴めるかと思いますのでおすすめです。

事前準備

$ docker version
Client: Docker Engine - Community
 Cloud integration  0.1.18
 Version:           19.03.13
 API version:       1.40
  • ポートフォリオ(Dockerの開発環境にしたいプロジェクト)をgit cloneしてくる
    記事のきっかけにもありますよう、既にポートフォリオを作成している段階のため環境構築したいものをgithubからローカル上に持ってきましょう
$ mkdir docker
 # Desktopからもしくはvagrantを使用していた時のworkディレクトリなどで実行
$ git clone git@github.com:ユーザー名/リポジトリ名.git

各ファイルの準備

Dockerとプロジェクトの準備ができたので、環境構築に必要なファイルを作成していきます

①Dockerfile

# 先ほどクローンしたディレクトリ上で
$ touch Dockerfile

下記内容を記入していきましょう

# 元となるdocker imageを指定。ポートフォリオのrubyのバージョンと合わせましょう
FROM ruby:2.5.7

RUN apt-get update -qq && apt-get install -y nodejs postgresql-client

RUN apt-get update && apt-get install -y nodejs --no-install-recommends && rm -rf /var/lib/apt/lists/*
#sqlite3を指定
RUN apt-get update && apt-get install -y sqlite3 --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

# コンテナ起動した時に、コンテナ内でmyappディレクトリを作成
RUN mkdir /myapp

# コンテナ内の作業ディレクトリの指定(上のRUNで作成したディレクトリ)
WORKDIR /myapp

# ホストマシンのgemfileをコピーし、コンテナ内のディレクトリに貼り付け
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock

# 貼り付けたgemfileを読み込み。bundlerバージョンが2以降だとこれが必要
ENV BUNDLER_VERSION 2.1.4
RUN gem install bundler
RUN bundle install

# アプリケーション(カレントディレクトリ)をコピーして、コンテナ内のディレクトリに貼り付け
COPY . /myapp

# ポートを3000で公開
EXPOSE 3000

# コンテナにてコマンドを実行
CMD ["rails", "server", "-b", "0.0.0.0", "-p", "3000"]
  • ENV BUNDLER_VERSION 2.1.4について
    Gefile.lockの一番下にこのような表記があるかと思いますので確認してみて下さい
Gemfile.lock
BUNDLED WITH
   2.1.4

②docker-compose.yml

# 同じディレクトリ上で
$ touch docker-compose.yml

下記内容を記入していきましょう

docker-compose.yml
version: '3'
services:
  web:
    build:
      context: ./
      dockerfile: Dockerfile 
    # 変更を保存するファイルを指定
    volumes:
      - .:/myapp
    # ポートを指定
    ports:
      - "3000:3000"
    # コンテナの起動を維持させる
    tty: true
    stdin_open: true

MySQLやPostgreSQLを使用している場合だと、web+DBの記述も必要なのですがSQLiteの場合はこちらのみで大丈夫みたいです。まだこの辺りの知識が乏しいため、ゆくゆくはMySQLに変更したいと思っております・・・

コンテナを起動してみましょう

# Dockerfileを元にdocker imageの作成
$ docker-compose build 

# docker container をバックグランドで起動
$ dokcer-compose up -d

# コンテナ内にてmigrationを更新
docker-compose run web rails db:migrate

これで、いつものlocalhost:3000で表示ができればひと段落です!

引っかかったエラーと解決した方法

大体ですが引っかかった時系列順に記載していきます。最初にも記載しておりますが、エラー内容とおそらくの原因の考察がサブで、メインが解決参考にさせていただいた記事の紹介になります。ありがとうございました

①ActiveRecord::PendingMigrationError Migrations are pending

「dokcer-compose up -d で動いているのにっ・・・!」

$ docker-compose up -d                                                  
Creating network "~~~_default" with the default driver
Creating ~~~_web_1 ... done

localhost:3000のページへアクセス時に起きたエラーです
コンテナの起動後、docker-compose run web rails db:migrate を行いましょう、あるあるな気がします
参考:docker-compose upで立ち上げたRailsでActiveRecord::PendingMigrationError Migrations are pending

②To install the missing version, run 'gem install bundler:2.1.4'

「bundleで始まるコマンド(デプロイ・Rspecなど)ができないっ・・・!」

Traceback (most recent call last):
    2: from 
    1: from 
~
Could not find 'bundler' (2.1.4) required by your /Users/ユーザー名/ディレクトリ名/Gemfile.lock. (Gem::GemNotFoundException)
To update to the latest version installed on your system, run `bundle update --bundler`.
To install the missing version, run `gem install bundler:2.1.4`

Dockerfileを作成した時に確認した、Gemfile.lockの「BUNDLED WITH 2.1.4」がローカル上で見つからないイメージです。
参考:To install the missing version, run gem install bundler:2.1.4と出たときの対処法

エラー文の通りにインストールを試してみましょう、ダメだった場合は③へ

gem install bundler -v 2.1.4

③ERROR: While executing gem ... (Gem::FilePermissionError)

ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /Library/Ruby/Gems/2.3.0 directory.

「gemのインストールの権限がありませんっ・・・!」
sudoを頭につけて行うという記事も多かったですが、そのままインストールよりも「rbenv」というバージョン管理のツールを用いて行う方法の方が今後のことを考えるといい気がします。

参考1:gem installでpermissionエラーになった時の対応方法
参考2:rbenvによるRubyのインストールからHello, World!まで

rbenvの用意ができたら、もう一度やってみましょう

gem install bundler -v 2.1.4

④bundle installができない

「bundleが・・・まだダメっ・・・!」

gem installができたところで、デプロイなどの「bundle~」系を入力するとまだエラー文がでます

Install missing gem executables with `bundle install`

エラー文に従って、bundle installをしてみると

# 長いため、最後の部分だけ抜粋
An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  mysql2

mysql周辺のエラーですが、原因は自力ではわかりませんでした。
下記の参考にさせていただいた記事通りで私は解決できました、本当にありがたい。

参考:【Rails】MySQL2がbundle installできない時の対応方法

これでデプロイはできるようになると思います。

⑤Could not find a JavaScript runtime ~

「動いているけどっ・・・!」

Rspecを走らせた時のエラーです

$ bundle exec rspec spec/ --format documentation

An error occurred while loading ./spec/models/cart_item_spec.rb.
Failure/Error: require File.expand_path('../config/environment', __dir__)

ExecJS::RuntimeUnavailable:
  Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes.

githubに飛んでみると、ExecJSのどれかをダウンロードするよう勧めています。
gemをいれる方法もありましたが、Node.jsを選択してダウンロードに進めばスムーズに解決できました。

これでRspecもできるようになりました。

終わりに

vagrantからdockerへの移行の手順とエラーの紹介をさせていただきました。
まだまだ勉強不足なところも多いため、dockerを十分に活用できていない点が多くあると改めて思いました。
参考にさせていただいた記事が多かったこともあり、当初思っていたよりも短い時間で導入まではできたので挑戦してみて良かったと感じています。

以前のvagrant環境と同じことはできるようになったので、次はCircleCIの導入でより良い開発環境にできるよう学習を続けたいと思います。

初投稿ということもあり、わかりにくい部分もあったかとは思いますが最後までみていただきありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails使うときの細かなTips

残しておかないと後で忘れそうな奴を書いておく。随時追記予定。

Datadogにエンドポイントでの挙動を細かく出したい (grape使用時)

このリファレンスを参照
https://docs.datadoghq.com/ja/tracing/setup/ruby/#grape

下記の実装例のように、リファレンスのoptionsにある analytics_enabled をtrueにするといい感じになる。
grapeとrails両方指定するのがポイント。

実装例

  require 'grape'
  require 'ddtrace'

  Datadog.configure do |c|
    c.use :grape, service_name: 'hoge-app', analytics_enabled: true
  end

  Datadog.configure do |c|
    c.use :rails, service_name: 'hoge-app', analytics_enabled: true
  end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

外部キーを持つデータの削除方法

環境

この記事ではmacOS Catalina10.15.6にインストールしたRuby 2.6.5を使っています。

前提

3つのモデルを作成し、以下の状況となっています。

User / ユーザー
Report / レポート
Comment / ユーザーとレポートの関連付けテーブル

コメントがついているレポートの削除を行う際に、以下のエラーが発生しました。

エラー発生

ActiveRecord::InvalidForeignKey in ReportsController#destroy
外部キーエラー
スクリーンショット 2020-10-22 10.00.46.png

何が原因なのか、その解決策を考えます。

原因

レポートの削除を行う際に、コメントテーブルのユーザーとレポートのidの値がなくなることが原因と判断。(外部キー制約のため)
ユーザーとレポートのidの関連付けがなくなったものは、コメントも削除できるようにしたい。

解決策

dependent: :destroyUserモデルReportモデルに記述する。
この記述により、親モデル(Report)を削除する際に、その親モデルに紐づく「子モデル(Comment)」も一緒に削除できる」ようになります。

検証

app/models/user.rb
class User < ApplicationRecord
  has_many :reports
  has_many :comments, dependent: :destroy
end
app/models/report.rb
class Report < ApplicationRecord
  belongs_to :user
  has_many :comments, dependent: :destroy
end

無事解決しました!
以上です。
同じような悩みや壁にぶつかっている方のお役に立てれば幸いです!

参考

下記を参考にしたので、より深く内容を理解したい方は、見てみてください!
https://qiita.com/Ushinji/items/650fa295a3054d2fe582
https://qiita.com/ITmanbow/items/2170ccaceafd5d401df8
https://qiita.com/Tsh-43879562/items/fbc968453a7063776637

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】System Spec 統合テストの同じ記述をまとめる

ディレクトリとファイルを用意

例として、サインインについての記述をまとめる
specディレクトリ配下にsupportディレクトリを作成
Screen Shot 2020-10-22 at 10.47.58.png

モジュールファイルへの記述

sign_in_support.rb
module SignInSupport
  def sign_in(user)
    visit new_user_session_path
    fill_in 'Email', with: user.email
    fill_in 'Password', with: user.password
    find('input[name="commit"]').click
    expect(current_path).to eq root_path
  end
end

作成したファイルを読み込めるように、rails_helper.rbを編集

rails_helper.rbのコメントアウトを外してモジュールを設定する。

SignInSupport = ジュールファイルのsign_in_support

rails_helper.rb
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
rails_helper.rb
RSpec.configure do |config|
  config.include SignInSupport #SignInSupport = ジュールファイル名のsign_in_support
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

#以下省略

テストファイルへの記述

spec/system/tweets_spec.rb
require 'rails_helper'

RSpec.describe 'ツイート投稿', type: :system do
  before do
    @user = FactoryBot.create(:user)
    @tweet_text = Faker::Lorem.sentence
    @tweet_image = Faker::Lorem.sentence
  end
  context 'ツイート投稿ができるとき'do
    it 'ログインしたユーザーは新規投稿できる' do
      # ログインする
      sign_in(@user)
      # 新規投稿ページへのリンクがあることを確認する
      expect(page).to have_content('投稿する')
      # 投稿ページに移動する
      visit new_tweet_path
      # フォームに情報を入力する
      fill_in 'tweet_image', with: @tweet_image
      fill_in 'tweet_text', with: @tweet_text
      # 送信するとTweetモデルのカウントが1上がることを確認する
      expect{
        find('input[name="commit"]').click
      }.to change { Tweet.count }.by(1)
      # 投稿完了ページに遷移することを確認する
      expect(current_path).to eq tweets_path
      # 「投稿が完了しました」の文字があることを確認する
      expect(page).to have_content('投稿が完了しました。')
      # トップページに遷移する
      visit root_path
      # トップページには先ほど投稿した内容のツイートが存在することを確認する(画像)
      expect(page).to have_selector ".content_post[style='background-image: url(#{@tweet_image});']"
      # トップページには先ほど投稿した内容のツイートが存在することを確認する(テキスト)
      expect(page).to have_content(@tweet_text)
    end
  end
  context 'ツイート投稿ができないとき'do
    it 'ログインしていないと新規投稿ページに遷移できない' do
      # トップページに遷移する
      visit root_path
      # 新規投稿ページへのリンクがないことを確認する
      expect(page).to have_no_content('投稿する')
    end
  end
end

RSpec.describe 'ツイート編集', type: :system do
  before do
    @tweet1 = FactoryBot.create(:tweet)
    @tweet2 = FactoryBot.create(:tweet)
  end
  context 'ツイート編集ができるとき' do
    it 'ログインしたユーザーは自分が投稿したツイートの編集ができる' do
      # ツイート1を投稿したユーザーでログインする
      sign_in(@tweet1.user)
      # ツイート1に「編集」ボタンがあることを確認する
      expect(
        all(".more")[1].hover
      ).to have_link '編集', href: edit_tweet_path(@tweet1)
      # 編集ページへ遷移する
      visit edit_tweet_path(@tweet1)
      # すでに投稿済みの内容がフォームに入っていることを確認する
      expect(
        find('#tweet_image').value
      ).to eq @tweet1.image
      expect(
        find('#tweet_text').value
      ).to eq @tweet1.text
      # 投稿内容を編集する
      fill_in 'tweet_image', with: "#{@tweet1.image}+編集した画像URL"
      fill_in 'tweet_text', with: "#{@tweet1.text}+編集したテキスト"
      # 編集してもTweetモデルのカウントは変わらないことを確認する
      expect{
        find('input[name="commit"]').click
      }.to change { Tweet.count }.by(0)
      # 編集完了画面に遷移することを確認する
      expect(current_path).to eq tweet_path(@tweet1)
      # 「更新が完了しました」の文字があることを確認する
      expect(page).to have_content('更新が完了しました。')
      # トップページに遷移する
      visit root_path
      # トップページには先ほど変更した内容のツイートが存在することを確認する(画像)
      expect(page).to have_selector ".content_post[style='background-image: url(#{@tweet1.image}+編集した画像URL);']"
      # トップページには先ほど変更した内容のツイートが存在することを確認する(テキスト)
      expect(page).to have_content("#{@tweet1.text}+編集したテキスト")
    end
  end
  context 'ツイート編集ができないとき' do
    it 'ログインしたユーザーは自分以外が投稿したツイートの編集画面には遷移できない' do
      # ツイート1を投稿したユーザーでログインする
      sign_in(@tweet1.user)
      # ツイート2に「編集」ボタンがないことを確認する
      expect(
        all(".more")[0].hover
      ).to have_no_link '編集', href: edit_tweet_path(@tweet2)
    end
    it 'ログインしていないとツイートの編集画面には遷移できない' do
      # トップページにいる
      visit root_path
      # ツイート1に「編集」ボタンがないことを確認する
      expect(
        all(".more")[1].hover
      ).to have_no_link '編集', href: edit_tweet_path(@tweet1)
      # ツイート2に「編集」ボタンがないことを確認する
      expect(
        all(".more")[0].hover
      ).to have_no_link '編集', href: edit_tweet_path(@tweet2)
    end
  end
end

RSpec.describe 'ツイート削除', type: :system do
  before do
    @tweet1 = FactoryBot.create(:tweet)
    @tweet2 = FactoryBot.create(:tweet)
  end
  context 'ツイート削除ができるとき' do
    it 'ログインしたユーザーは自らが投稿したツイートの削除ができる' do
      # ツイート1を投稿したユーザーでログインする
      sign_in(@tweet1.user)
      # ツイート1に「削除」ボタンがあることを確認する
      expect(
        all(".more")[1].hover
      ).to have_link '削除', href: tweet_path(@tweet1)
      # 投稿を削除するとレコードの数が1減ることを確認する
      expect{
        all(".more")[1].hover.find_link('削除', href: tweet_path(@tweet1)).click
      }.to change { Tweet.count }.by(-1)
      # 削除完了画面に遷移することを確認する
      expect(current_path).to eq tweet_path(@tweet1)
      # 「削除が完了しました」の文字があることを確認する
      expect(page).to have_content('削除が完了しました。')
      # トップページに遷移する
      visit root_path
      # トップページにはツイート1の内容が存在しないことを確認する(画像)
      expect(page).to have_no_selector ".content_post[style='background-image: url(#{@tweet1.image});']"
      # トップページにはツイート1の内容が存在しないことを確認する(テキスト)
      expect(page).to have_no_content("#{@tweet1.text}")
    end
  end
  context 'ツイート削除ができないとき' do
    it 'ログインしたユーザーは自分以外が投稿したツイートの削除ができない' do
      # ツイート1を投稿したユーザーでログインする
      sign_in(@tweet1.user)
      # ツイート2に「削除」ボタンが無いことを確認する
      expect(
        all(".more")[0].hover
      ).to have_no_link '削除', href: tweet_path(@tweet2)
    end
    it 'ログインしていないとツイートの削除ボタンがない' do
      # トップページに移動する
      visit root_path
      # ツイート1に「削除」ボタンが無いことを確認する
      expect(
        all(".more")[1].hover
      ).to have_no_link '削除', href: tweet_path(@tweet1)
      # ツイート2に「削除」ボタンが無いことを確認する
      expect(
        all(".more")[0].hover
      ).to have_no_link '削除', href: tweet_path(@tweet2)
    end
  end
end

RSpec.describe 'ツイート詳細', type: :system do
  before do
    @tweet = FactoryBot.create(:tweet)
  end
  it 'ログインしたユーザーはツイート詳細ページに遷移してコメント投稿欄が表示される' do
    # ログインする
    sign_in(@tweet.user)
    # ツイートに「詳細」ボタンがあることを確認する
    expect(
      all(".more")[0].hover
    ).to have_link '詳細', href: tweet_path(@tweet)
    # 詳細ページに遷移する
    visit tweet_path(@tweet)
    # 詳細ページにツイートの内容が含まれていることを確認する
    expect(page).to have_selector ".content_post[style='background-image: url(#{@tweet.image});']"
    expect(page).to have_content("#{@tweet.text}")
    # コメント用のフォームが存在することを確認する
    expect(page).to have_selector 'form'
  end
  it 'ログインしていない状態でツイート詳細ページに遷移できるもののコメント投稿欄が表示されない' do
    # トップページに移動する
    visit root_path
    # ツイートに「詳細」ボタンがあることを確認する
    expect(
      all(".more")[0].hover
    ).to have_link '詳細', href: tweet_path(@tweet)
    # 詳細ページに遷移する
    visit tweet_path(@tweet)
    # 詳細ページにツイートの内容が含まれていることを確認する
    expect(page).to have_selector ".content_post[style='background-image: url(#{@tweet.image});']"
    expect(page).to have_content("#{@tweet.text}")
    # フォームが存在しないことを確認することを確認する
    expect(page).to have_no_selector 'form'
    # 「コメントの投稿には新規登録/ログインが必要です」が表示されていることを確認する
    expect(page).to have_content 'コメントの投稿には新規登録/ログインが必要です'
  end
end
spec/system/comments_spec.rb
require 'rails_helper'

RSpec.describe 'コメント投稿', type: :system do
  before do
    @tweet = FactoryBot.create(:tweet)
    @comment = Faker::Lorem.sentence
  end

  it 'ログインしたユーザーはツイート詳細ページでコメント投稿できる' do
    # ログインする
    sign_in(@tweet.user)
    # ツイート詳細ページに遷移する
    visit tweet_path(@tweet)
    # フォームに情報を入力する
    fill_in 'comment_text', with: @comment
    # コメントを送信すると、Commentモデルのカウントが1上がることを確認する
    expect{
      find('input[name="commit"]').click
    }.to change { Comment.count }.by(1)
    # 詳細ページにリダイレクトされることを確認する
    expect(current_path).to eq tweet_path(@tweet)
    # 詳細ページ上に先ほどのコメント内容が含まれていることを確認する
    expect(page).to have_content @comment
  end
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsコントローラーで同じ記述をprivate以下にメソッドとして切り分け、before_actionで呼び出せるように実装してみた

この記事ではインストールしたRails 6.0.0を使っています。
*初めての投稿です。見づらければ申し訳ないです:smile_cat:

やること

複数の記述をまとめる
コントローラーを見やすくする
privateメゾットを使用
before_actionを使用

初期コード

items_controller.rb
def show 
   @item = Item.find(params[:id])
end

def edit
   @item = Item.find(params[:id])
end

def update
   @item = Item.find(params[:id])
end 
【見ていていただくとわかるように同じような記述が複数のアクション内で使われています。こちらを切り分けて呼び出したいと思います!】

方法1 〜private以下に切り分けてあげる〜

items_controller.rb
private
 def set_item
    @item = Item.find(params[:id])
  end

まず初期コードにある@(インスタンス変数)の記述を削除します。
そしてprivateを下部に作ります。メゾット set_itemを作りその中に先ほど削除した記述を入れてあげます。
(メゾット名はわかり易ければなんでも大丈夫です)
こうすることで、メゾットとして切り分けができます。ですがこれだけでは、切り出しただけで呼び出すことができません。

方法2 ~before_actionで呼び出してあげる〜

items_controller.rb
before_action :set_item, only: [:show, :edit, :update]

コントローラー上部にこちらを記述します。一つ一つ説明すると
before_action :各アクションが実行される前に呼び出すための記述
set_item :  方法1のprivate内で作ったメゾット名
only:    特定のアクションだけでつかいますよという感じの意味。
反対語としてexpectがあり、それは特定のアクション以外で使うという意味!
そのあとは指定するアクション名を記述!

最後に

初期コードの方が分かりやすいしやる意味あるかな?と最初は思うかもしれません。僕もそうでした。笑
ですが例えばこのあと他のアクションにまた同じ記述が必要になった時などに、before_actionにアクション名を追加するだけになるのでとても便利です!
コードを他の方がみても分かりやすく長ったるい記述じゃないように書けます!
これからも他の方が見やすいコードをかけるよう意識していこうと思っています!

    

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

文字列

文字列

文字列は、プログラミングの中で文字を扱うための値です。

文字列を生成するには、文字をダブルクォーテーション"
または、シングルクォーテーション'で囲みます。
以下の例を見てください。

【例】Rubyファイル
"This is string."

'This is string, too.'

このように、文字列は簡単に生成できます。

irbで以下のコードを実行してみましょう

irbでRubyの文字列を記述し、実行してみましょう。

ターミナル
# irbを起動
% irb
irb
# 文字列を書いてエンターキーで実行
irb(main):001:0> "Hello! こんにちは!"

# 続けてこのように表示されれば成功
=> "Hello! こんにちは!"

全角スペースや日本語が含まれているとプログラムはエラーが生じますが、
文字列の値として扱う場合は、エラーにはなりません。

まとめ

文字列とは、プログラミングの中で文字を扱うための値のこと。

以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Heroku上の画像をAWSのS3へ保存する方法

はじめに

AWSはAmazon Web Servisesの略で、Amazonが提供しているクラウドサーバーのサービスです。
多くの人や企業で使用されているサービスであり、使う容量や期間によっては完全に無料で使うことができます。

Heroku上の画像をAWSに保存する理由

Herokuに保存した画像は24時間に一度リセットされる仕様になっています。
画像を外部のサーバーに保存することで、画像が消えてしまうという現象を防ぐことができるため、今回は外部サーバーとしてAWSを利用します。

S3とは

AWSのサービスの一つで、12ヶ月間、5GBまでのストレージを無料で利用することができるサービスで、画像などを保存しておくことができます。

今回の手順

AWSへの登録はできている前提で進めます。(登録していない方はAWSで検索して、新規登録してください。)

  • IAMユーザーを作成する
  • S3に画像の保存先を用意する
  • ローカル環境で画像の保存先をS3に変更する
  • 本番環境で画像の保存先をS3に変更する

IAMユーザーを作成する

IAMとは

IAMとはAWSのサービスの一つです。
AWSで作成したアカウントはすべての権限を持つルートユーザーとなり、万が一、情報漏洩してしまうと悪用されてしまうリスクがあります。
そのため、使える権限を制限したユーザーを作成し、通常の作業はそのユーザーで行うようにします。
その制限された権限を持つユーザーを作成する機能を持つのがIAMです。

IAMユーザーの作成

IAMで作成されるユーザーをIAMユーザーと呼びます。
まず、AWSのサービス検索でIAMを検索し、IAMページへ遷移します。
サイドバーのユーザーから「ユーザーを追加」をクリックします。
そして、任意のユーザー名を入力し、プログラムによるアクセスにチェックを入れ、「次のステップ」をクリックします。
既存のポリシーを直接アタッチを選択し、ポリシーのフィルタにamazons3と入力し、、「AmazonS3FullAccess」にチェックを入れ、「次のステップ」をクリックします。
タグの追加はやりたい人のみやって、「次のステップ」をクリックします。
設定の確認画面が出るので、問題なければ「ユーザーの作成」をクリックします。
この時に出てくる「.csvのダウンロード」は忘れずに、行います。(後々、使うため。)

IAMユーザーのパスワードを設定

上で作成したAWS上のIAMユーザーの中で、認証情報のタブをクリックすると、コンソールのパスワード欄があります。
ここの管理をクリックした後に出てくるページで、コンソールへのアクセスは有効化、パスワードの設定は自動生成パスワードを選択し、適用します。
そうすると、パスワードが生成されます。
この時に出てくる「.csvのダウンロード」は忘れずに、行います。(後々、使うため。)

S3に画像の保存先を用意する

バケットの作成

S3で実際にデータが格納される場所のことをバケットと呼びます。
AWSにログイン後、サービス検索でS3のページに遷移すると、バケットという文字が出てきます。
サイドバーのバケットという項目の中には「バケットを作成する」というボタンが存在するので、そのボタンをクリックします。

バケット名とリージョンの設定

バケット名とリージョンの入力画面に遷移するため、自身で考えたバケット名を入力します。
※バケット名はAWSを使う誰かのバケットと同じ名前はつけられません。

リージョンは地域という意味ですが、ここではサーバーの場所を表します。
日本人ならアジアパシフィック(東京)を選択で良いと思います。

オプションの設定

オプションを設定したい方はここで設定します。
設定が終われば、次へをクリックします。

アクセス許可の設定

デフォルトでは「パブリックアクセスをすべてブロック」にチェックが入っています。
このチェックを外すと、パブリックアクセスのお好みの設定ができます。
設定が終われば、次へをクリックします。

確認

確認ページではこれまで行った設定の一覧が表示されるので、問題なければ、「バケットを作成」をクリックします。

バケットポリシーの設定

バケットポリシーとは、どのようなアクセスに対してS3への保存やデータの読み取りを許可するか決められる仕組みです。
今回は先ほど作成したIAMユーザーからのアクセスを許可します。

まず、IAMユーザーのARNをコピーして、どこかにメモしておきます。

作成したバケットから、アクセス権限をクリックし、バケットポリシーをクリックし、以下を記述します。

{
   "Version": "2012-10-17",
   "Id": "Policy1544152951996",
   "Statement": [
       {
           "Sid": "Stmt1544152948221",
           "Effect": "Allow",
           "Principal": {
               "AWS": "コピーしたIAMユーザーのARN"
           },
           "Action": "s3:*",
           "Resource": "arn:aws:s3:::バケット名"
       }
   ]
}

保存すれば、完了です。

ローカル環境で画像の保存先をS3に変更する

Gemのインストール

rubyでS3を使用するためにaws-sdk-smというGemをインストールします。

Gemfile
一番下に下記を追記
gem "aws-sdk-s3", require: false

その後、ターミナルでbundle installを入力します。

保存先を指定する

config/environments/development.rb
config.active_storage.service = :local

上の記述を以下に変更

config.active_storage.service = :amazon
config/storage.yml
以下のコードを追記

amazon:
 service: S3
 access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
 secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
 region: ap-northeast-1
 bucket: ご自身のバケット名

※regionのap-northease-1はアジアパシフィック(東京)の番号

環境変数の設定

ターミナル
% vim ~/.zshrc

iを押して、以下を追記

export AWS_ACCESS_KEY_ID="ここにCSVファイルのAccess key IDの値をコピー"
export AWS_SECRET_ACCESS_KEY="ここにCSVファイルのSecret access keyの値をコピー"
(CSVファイルはIAMユーザー作成時にダウンロードしたファイルのこと。)

:wqで保存する

ローカル環境で、アプリケーションから画像を投稿し、問題なくS3に保存されていることが確認できたら、本番環境でも画像の保存先をS3に変更します。

本番環境で画像の保存先をS3に変更する

保存先を指定する

ローカル環境と同様の作業を行います。

config/environments/production.rb
config.active_storage.service = :local

上の記述を以下に変更

config.active_storage.service = :amazon

環境変数の設定

本番環境にはHerokuを用いるため、Heroku上で環境変数を設定します。
heroku config:setコマンドで環境変数の設定をすることができます。

ターミナル
% heroku config:set AWS_ACCESS_KEY_ID="ここにCSVファイルの「Access key ID」の値をコピー"
% heroku config:set AWS_SECRET_ACCESS_KEY="ここにCSVファイルの「Secret access key」の値をコピー"

環境変数が設定できたか確認するときは
% heroku config

編集内容をHerokuに反映させる

ターミナル
% git push heroku master

参考

テックキャンプのカリキュラム
「AWSに画像をアップロードする」

最後に

本投稿が初学者の復習の一助となればと幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む