20190828のRailsに関する記事は18件です。

Railsでメール送信機能を実装する手順を結構丁寧に(development環境編)

次からもっとスムースにできるように、ここに執筆します。

前提

  • バージョンは Rails 5.2.3 です。
  • テンプレートエンジンはHamlを使っていますが、ERBでもSlimでもそんなに変わらないはずです。
$ rails -v
Rails 5.2.3

要件(仕様、やりたいこと)

  • 問い合わせフォームで必要事項を入力して送信すると、その内容をDBに保存するとともに、管理者にテキストメールで通知する。

letter_opener を導入する

  • letter_opener というgemを導入すると、開発中にテストで送信したメールが実際にアドレス先に飛んでいく代わりに、ブラウザのポップアップで確認できるようになります。
  • 導入することで、テスト用のメールが誤って実際に使われているアドレス先に送信されるのを防ぐことができます。
  • 実際にやってみればどうなるかわかると思いますので、とりあえず以下の手順で導入だけ済ませておきます。
Gemfile
group :development do
  gem 'letter_opener'
end
$ bundle install
config/environments/development.rb
config.action_mailer.delivery_method = :letter_opener

実装

では実装していきます。

config/environments/development.rb を編集する

  • config.action_mailer.raise_delivery_errors = false をコメントアウトすることで、development環境からもメールを送信する設定に切り替えることができます。
  • config.action_mailer.delivery_method は先ほど追加した部分です。
  • config.action_mailer.default_url_options は、後述のメールテンプレート内でURLヘルパーを使用できるようにする設定です。
config/environments/development.rb
Rails.application.configure do

  #...(中略)...

  # コメントアウトすることでdevelopment環境からもメールを送信する設定になる
  # config.action_mailer.raise_delivery_errors = false

  # smtpで実際にメール送信させるのではなく、letter_openerというgemを用いてテストする
  # config.action_mailer.delivery_method = :smtp
  config.action_mailer.delivery_method = :letter_opener

  # メールテンプレートはviewと違ってURLヘルパーを使ってもドメインが取得できず、メール本文にURLを載せられないので、その対策をする
  config.action_mailer.default_url_options = {:host => 'localhost:3000'}
end

メーラークラスを作成する

  • rails generate コマンドが使用できます。
  • 今回はHTMLメールではなくテキストメールを実装したいため、app/views/notice_mailer/sendmail_contact.html.haml は削除します(HTMLテンプレートの方が優先して呼ばれるみたいなので、そちらを残しておくとエラーになったり意図しない内容のメールになってしまいます)。
$ rails g mailer Notice sendmail_contact
Running via Spring preloader in process 1180
      create  app/mailers/notice_mailer.rb
      invoke  haml
      create    app/views/notice_mailer
      create    app/views/layouts/mailer.text.haml
      create    app/views/layouts/mailer.html.haml
      create    app/views/notice_mailer/sendmail_contact.text.haml
      create    app/views/notice_mailer/sendmail_contact.html.haml ->削除する
  • メーラークラスは以下の内容にします。
app/mailers/notice_mailer.rb
class NoticeMailer < ApplicationMailer

  # メール送信元アドレスを設定する
  default from: "noreply@example.com"

  def sendmail_contact(contact)
    @contact = contact
    # メール送信先アドレスを設定する
    mail to: "admin@example.com",
         subject: "お問い合わせが届きました"  # メール件名
  end

end

メールテンプレートを作成する

  • ここに記述した内容がメール本文になります。
  • メーラークラスのメソッド内で使用したインスタンス変数は、ここで参照できます。
  • バックスラッシュを使うことで、改行できます。
  • 先述した通り、config/environments/development.rb に必要な設定をしていれば、URLヘルパーを使うこともできます。
app/views/notice_mailer/sendmail_contact.text.haml
お問い合わせが届きました。
\
= "会社名: #{@contact.company}"
= "お名前: #{@contact.name}"
= "メールアドレス: #{@contact.email}"
= "電話番号: #{@contact.telephone}"
= "お問い合わせ内容:"
= @contact.message

メーラークラスのメソッドを呼び出す

  • 追加しているのは、NoticeMailer.sendmail_contact(@contact).deliver の1行です。
app/controllers/contacts_controller.rb
class ContactsController < ApplicationController

  def new
    @contact = Contact.new
  end

  def create
    @contact = Contact.new(contact_params)
    if @contact.save
      NoticeMailer.sendmail_contact(@contact).deliver # ここで呼び出している
      redirect_to new_contact_url, notice: '問い合わせの送信に成功しました。'
    else
      render :new
    end
  end

  private

  def contact_params
    params.require(:contact).permit(:company, :name, :email, :telephone, :message)
  end

end

これで一通りの実装が完了しました。実際に動かしてみましょう!

(option)development環境から実際にメール送信する

  • letter_opener を使わず、実際にメールを送信してみる場合は、config/environments/development.rb を以下のように記述します。
  • 今回は、ドメインはGmailのものを設定します。
  • Gmailのアプリパスワードというのは、普段Googleのアカウントにログインするために使っているパスワードとは異なりますので、ご注意ください。
config/environments/development.rb
Rails.application.configure do

  #...(中略)...

  # コメントアウトすることでdevelop環境からもメールを送信する設定になる
  # config.action_mailer.raise_delivery_errors = false

  # smtpで実際にメール送信させる
  config.action_mailer.delivery_method = :smtp
  # config.action_mailer.delivery_method = :letter_opener

  # メールテンプレートはviewと違ってURLヘルパーを使ってもドメインが取得できず、メール本文にURLを載せられないので、その対策をする
  config.action_mailer.default_url_options = {:host => 'localhost:3000'}

  config.action_mailer.smtp_settings = {
      :enable_starttls_auto => true,
      :address => 'smtp.gmail.com',
      :port => 587,
      :domain => 'gmail.com',
      :authentication => :plain,
      # 本当に飛ばす場合(letter_openerを使わない場合)は、Gmailのメールアドレスが必要
      :user_name => 'aaaaa@gmail.com',
      # 本当に飛ばす場合(letter_openerを使わない場合)は、Gmailのアプリパスワードが必要
      :password => 'aaaabbbbccccdddd'
  }
end

(WIP)production環境から実際にメール送信する

  • 本番環境については別記事にまとめる予定です。まだ私も実装できていないので…。

参考

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

Railsチュートリアル(第12章)

はじめに

Railsチュートリアルの第12章が終わりました。
この章では、パスワード再設定を行います。
メールを送って再設定用のリンクにアクセスする基本的な流れは11章と同じです。
ポイントだけメモしておきます。

隠しフィールド

メールアドレスからユーザーを特定するために、メールで送信したリンクからアクセスした際のeditアクションと、その後のパスワード再設定フォームからの送信時のupdateアクションでそれぞれメールアドレスが必要です。
リンクからアクセスする際は、リンクのパラメータにメールアドレスを含めていますが、フォームの送信で消えてしまいます。そのために、フォーム内に隠しフィールドとして保持します。

以下のように、hidden_field_tagで記述します。

    <%= form_for(@user, url: password_reset_path(params[:id])) do |f| %>
      ...
      <%= hidden_field_tag :email, @user.email %>
      ...
    <% end %>

f.hidden_fieldを使用しないのは、以下のようにパラメータの取得の仕方が変わるからです。

hidden_field_tag :email, @user.email # params[:email] 
f.hidden_field :email, @user.email   # params[:user][:email] 

時間の比較

時間も数値等と同じように比較することができます。
以下のように記述することで、reset_sent_atが2時間より前かどうか判定しています。

reset_sent_at < 2.hours.ago

考え方としては、reset_sent_at2.hour.ago(2時間前の時間)より前であればtrueです。

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

Rails & Nuxt.jsのアプリケーションにGraphQLを導入する

前提

Rails & Nuxt.jsのDocker環境をalpineイメージで構築する

こちらのポストの環境をもとに進めるので、Dockerのサービス名等は適宜読み替えていただくようにお願いします。

ディレクトリ構成

後述のコマンドでは、Railsは backend、Nuxtは frontend がDockerのサービス名になっています。

.
├── backend <- Ruby on Rails
│   ├── Dockerfile
│   ├── Gemfile
│   ├── Gemfile.lock
│   (中略)
│   
├── frontend <- Nuxt.js
│   ├── Dockerfile
│   ├── README.md
│   ├── nuxt.config.js
│   ├── package-lock.json
│   ├── package.json
│  (中略)
│
├── docker-compose.yml
└── .env

ライブラリ追加

Rails

./backend/Gemfile を修正し、 bundle install します。

## (中略) ##

gem 'graphql' #added

group :development do
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'

  gem 'graphiql-rails' #added
end

## (中略) ##
$ docker-compose exec backend bundle install

Nuxt

こちらのライブラリをインストールします。

本記事では graphql-tag は使いません。

$ docker-compose exec frontend yarn add @nuxtjs/apollo

実装

Rails

generator で雛形を作成します。

$ docker-compose exec backend rails g graphql:install

graphiql-railsの Readme にしたがって、Railsのconfigファイルを修正します。

./backend/config/routes.rb

GraphiQLエンジンをマウントし、ブラウザからアクセスできるようにします。

Rails.application.routes.draw do
  post "/graphql", to: "graphql#execute" #generatorでinsertされる
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html

  #added
  if Rails.env.development?
    mount GraphiQL::Rails::Engine, at: '/graphiql', graphql_path: '/graphql'
  end
end

./backend/config/application.rb

APIモードの場合に必要な修正です。

## (中略) ##

- # require "sprockets/railtie"
+ require "sprockets/railtie"

## (中略) ##

GraphiQLで動作確認

dockerコンテナを再起動後、ブラウザで http://localhost:3000/graphiql にアクセスし、GraphiQLを開きます。

./backend/app/graphql/types/query_type.rb のサンプルを利用して、下記のようにqueryの結果が返ってくればOKです。

$ docker-compose restart backend

graphiql.png

Nuxt

Nuxtアプリのルートに、下記のディレクトリ、ファイルを追加、編集します。

今回はmutationは使いませんが、あわせて作成しておきます。

.
└── frontend 
    ├── nuxt.config.js
    │
    ├── pages
    │   └── index.vue
    │
    └── apollo
        ├── client-configs
        │   └── default.js
        └── gqls
            ├── mutations
            └── queries
                └── getTestField.gql

./frontend/nuxt.config.js

Nuxtでapolloクライアントを使用するための設定を追加します。

default.js を読み込まず、nuxt.config.jsに直書きしてもOKです。

export default {

  /* (中略) */

  modules: [
    '@nuxtjs/apollo', //added
  ],

  /* (中略) */

  apollo: {
    clientConfigs: {
      default: '~/apollo/client-configs/default.js'
    }
  }
}

./frontend/apollo/client-configs/default.js

apolloには様々なオプションありますがが、今回はqueryの実行が確認できればよいので最低限です。
uriのホスト名は、DockerのRailsアプリのサービス名 backend になります。

import { HttpLink } from 'apollo-link-http'

export default () => {
  const httpLink = new HttpLink({ uri: 'http://backend:3000/graphql' })
  return {
    link: httpLink
  }
}

./frontend/apollo/gqls/queries/testField.gql

GraphiQLで実行したものです。

query {
  testField
}

./frontend/pages/index.vue

queryを実行した結果を表示します。

<template>
  <p>{{ testField }}</p>
</template>

<script>
import testField from '~/apollo/gqls/queries/testField';

export default {
  data() {
    return {
      testField: {}
    }
  },
  apollo: {
    testField: {
      query: testField
    }
  }
}
</script>

nuxt.png

お疲れさまでした。

(簡略化シすぎた感)

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

【Rails】dotenvで管理していた環境変数が反映されなくなった時やってみること

dotenvで管理していた環境変数が反映されなくなって大変こまった

環境変数をカンタンに管理できる便利gem、dotenvを利用していましたがプルリクやマージやら重ねてるうちに環境変数が反映されなくなってしまいました...。

この記事を必要としていた人に教えられること

ない、結論から言うとbundle updateしたら直った。原因わからないから教えて欲しい。

私が使っていた環境とか

$ rails -v
Rails 5.2.3

dotenv 2.7.5
dotenv-rails 2.7.5

ちなみに次のようにGemfileに書き込み、dotenvを利用しています。

Gemfile
gem 'dotenv-rails'

.envはルートディレクトリに置いてあった

image.png

参考

spring stopしたらいいらしいです、私はやってませんが...
https://qiita.com/metafalse/items/7294afa3d1be3315e999

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

Railsチュートリアルメモ 第3章

個人的なメモ。

Railsチュートリアルでは2章ではScaffoldを使ってあらましを、
3章から本格的にアプリ制作に入る。
3章では「静的なページの制作」、「自動テストのあらまし」の学習をする

メモでは気になった部分、忘れそうな部分を記述。

3章 ほぼ静的なページの作成

3.2 静的ページ

3.2.1 静的なページの生成

コントローラ生成(rails generate)時にアクションは複数指定できる

$ rails generate controller StaticPages home help

home helpのようにcontroller名のあとに複数指定可能

Rubyの命名規則の特徴

クラス名にはキャメルケース(例:StaticPages)が使われる
ファイル名にはスネークケース(例:static_pages)が使われる
※あくまで慣習だが、同様に習うべき

Railsコマンドの短縮

完全なコマンド 短縮形
$ rails server $ rails s
$ rails console $ rails c
$ rails generate $ rails g
$ rails test $ rails t
$ bundle install $ bundle

Railsでの手戻し

コントローラ, モデル
$ rails destroy controller HogeHoges

generate に対しての destroy

※ destroy時、/config/routes.rb内にルーティングが残っているかもしれない。手作業で削除

DB

DBも逐一マイグレーションが必要

$ rails db:migrate

だが、1手手戻しもできる

$ rails db:rollback

またdbのマイグレーションは逐一バージョンが付与されているので、最初に戻す場合、以下

$ rails db:migrate VERSION=0

3.2.2 静的なページの調整

viewsの場所

app/views/コントローラ名/アクション名.html.erb
erb (Embedded Ruby)
htmlにrubyを埋め込んである。

3.3 テストから始める

テスト駆動開発 (test-driven development; TDD)
RailsチュートリアルではガチガチのTDDでは進みが悪いので、必要に応じてTDD

チュートリアル内で行うテストは3つ

  • コントローラテスト (3章〜)
  • モデルテスト (6章〜)
  • 統合テスト (7章〜)

結局テストはいつ行えばよいのか

3.3.1

コントローラテスト

$ rails generate controller hogehoge の時点でテストが既に作成されている。
/test/controllers/

3.3.2

テスト駆動のサイクル

  1. 失敗するテストを最初に書く
  2. アプリケーションのコードを書いて成功させる (パスさせる)
  3. 必要ならリファクタリングする

それぞれステータスから

  1. RED
  2. GREEN
  3. REFACTOR

とも。
このサイクルを繰り返す。

以下テストを元に、$ rails testを確認しながら、通るようにしていく。
テストを書き、通るように開発。簡単なTDD。

require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  # 省略

  test "should get about" do
    get static_pages_about_url
    assert_response :success
  end
end

リファクタリング

「1匹いたら30匹いると思え」
金言。BUGでなくとも腐敗臭漂うだけでリファクタリングもの。
ネズミもGもBUGもスパゲッティコードも。早いうちからのリファクタリングが大事。

3.4 少しだけ動的なページ

HTML内でheadのtitleタグを動的に表示し、TDDでつなぐ。

3.4.2

リファクタリング。
2,3回出てくる文字列を変数化
(インスタンス変数、文字列の式展開について、触れられている)

3.4.3

DRY (Donot Repeat Yourself)
Rubyの原則。
共通部分をRailsの機能でまとめる。
/app/views/layouts/application.html.erb
上記に大枠のレイアウトを記述。
その他アクションのerb内の内容は、application.html.erb内に
<%= yield %>
と記述し、挿入する。

3.5 最後に

コミットとデプロイ
masterブランチに変更をmerge
herokuにデプロイ

$ git checkout master
$ git merge 作業ブランチ名

# プッシュとデプロイ
$ git push # github側 push
$ rails t # herokuデプロイ前テスト
$ git push heroku # heroku側 push
$ heroku open # 確認

デプロイ前に rails test を実行。癖をつけるようにする。

3.6 高度なセットアップ

3.6.1 minitest reporters

minitest-reporters (gem) でRailsのテストを見やすくする。
RED、GREENで色がつくようになる。

3.6.2 Guardによるテストの自動化

Guardというgemでファイルを監視、自動テスト

$ bundle exec guard init # 初期化
$ bundle exec guard # 監視スタート

guardのプロンプトが開く。
フルスキャンはそのままEnter。
終了は <C-d> でデタッチ。

GuardはSpringサーバ(Railsの機能)を使うが、バグが有りプロセスが残ることが有るので、重いときには余計なものをkillする。

Linux killコマンド

プロセスのkill

$ ps aux | grep spring

パイプでgrepに渡し、springのみ抽出
pid(数字5桁)を指定してkill

$ kill -15 12345 #pidはあくまで例

ここのoptionで指定するシグナルは15がterminationで一緒か?
どうやらCPUごとに一部変わるそうで、x86なら-15SIGTERM(termination)で終了できるらしい。
我が家のintelmacさんはx86かと思うので-15

Springなら
1. 一括終了を最初に試す、
2. ダメならpkill

$ spring stop
$ pkill -15 -f プロセス名 # ダメなら

所感

テスト駆動で書きながら、コントローラからビューに至るまでの流れをトレースできたように思う。
簡単なテストだが、まだ苦に思わない程度で済んでいる。
演習で2,3度同じような作業が繰り返されるので、少しずつ馴染めそう。

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

Railsチュートリアル(第4版)メモ 第3章

Railsチュートリアル(第4版)の個人メモ
気になった部分、忘れそうな部分を記述。

  • Ruby 2.6.1
  • Rails 5.1.6

2章ではScaffoldを使ってあらましを、
3章から本格的にアプリ制作に入る。
3章では「静的なページの制作」、「自動テストのあらまし」の学習をする

3章 ほぼ静的なページの作成

3.2 静的ページ

3.2.1 静的なページの生成

コントローラ生成(rails generate)時にアクションは複数指定できる

$ rails generate controller StaticPages home help

home helpのようにcontroller名のあとに複数指定可能

Rubyの命名規則の特徴

クラス名にはキャメルケース(例:StaticPages)が使われる
ファイル名にはスネークケース(例:static_pages)が使われる
※あくまで慣習だが、同様に習うべき

Railsコマンドの短縮

完全なコマンド 短縮形
$ rails server $ rails s
$ rails console $ rails c
$ rails generate $ rails g
$ rails test $ rails t
$ bundle install $ bundle

Railsでの手戻し

コントローラ, モデル
$ rails destroy controller HogeHoges

generate に対しての destroy

※ destroy時、/config/routes.rb内にルーティングが残っているかもしれない。手作業で削除

DB

DBも逐一マイグレーションが必要

$ rails db:migrate

だが、1手手戻しもできる

$ rails db:rollback

またdbのマイグレーションは逐一バージョンが付与されているので、最初に戻す場合、以下

$ rails db:migrate VERSION=0

3.2.2 静的なページの調整

viewsの場所

app/views/コントローラ名/アクション名.html.erb
erb (Embedded Ruby)
htmlにrubyを埋め込んである。

3.3 テストから始める

テスト駆動開発 (test-driven development; TDD)
RailsチュートリアルではガチガチのTDDでは進みが悪いので、必要に応じてTDD

チュートリアル内で行うテストは3つ

  • コントローラテスト (3章〜)
  • モデルテスト (6章〜)
  • 統合テスト (7章〜)

結局テストはいつ行えばよいのか

3.3.1

コントローラテスト

$ rails generate controller hogehoge の時点でテストが既に作成されている。
/test/controllers/

3.3.2

テスト駆動のサイクル

  1. 失敗するテストを最初に書く
  2. アプリケーションのコードを書いて成功させる (パスさせる)
  3. 必要ならリファクタリングする

それぞれステータスから

  1. RED
  2. GREEN
  3. REFACTOR

とも。
このサイクルを繰り返す。

以下テストを元に、$ rails testを確認しながら、通るようにしていく。
テストを書き、通るように開発。簡単なTDD。

require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  # 省略

  test "should get about" do
    get static_pages_about_url
    assert_response :success
  end
end

リファクタリング

「1匹いたら30匹いると思え」
金言。BUGでなくとも腐敗臭漂うだけでリファクタリングもの。
ネズミもGもBUGもスパゲッティコードも。早いうちからのリファクタリングが大事。

3.4 少しだけ動的なページ

HTML内でheadのtitleタグを動的に表示し、TDDでつなぐ。

3.4.2

リファクタリング。
2,3回出てくる文字列を変数化
(インスタンス変数、文字列の式展開について、触れられている)

3.4.3

DRY (Donot Repeat Yourself)
Rubyの原則。
共通部分をRailsの機能でまとめる。
/app/views/layouts/application.html.erb
上記に大枠のレイアウトを記述。
その他アクションのerb内の内容は、application.html.erb内に
<%= yield %>
と記述し、挿入する。

3.5 最後に

コミットとデプロイ
masterブランチに変更をmerge
herokuにデプロイ

$ git checkout master
$ git merge 作業ブランチ名

# プッシュとデプロイ
$ git push # github側 push
$ rails t # herokuデプロイ前テスト
$ git push heroku # heroku側 push
$ heroku open # 確認

デプロイ前に rails test を実行。癖をつけるようにする。

3.6 高度なセットアップ

3.6.1 minitest reporters

minitest-reporters (gem) でRailsのテストを見やすくする。
RED、GREENで色がつくようになる。

3.6.2 Guardによるテストの自動化

Guardというgemでファイルを監視、自動テスト

$ bundle exec guard init # 初期化
$ bundle exec guard # 監視スタート

guardのプロンプトが開く。
フルスキャンはそのままEnter。
終了は <C-d> でデタッチ。

GuardはSpringサーバ(Railsの機能)を使うが、バグが有りプロセスが残ることが有るので、重いときには余計なものをkillする。

Linux killコマンド

プロセスのkill

$ ps aux | grep spring

パイプでgrepに渡し、springのみ抽出
pid(数字5桁)を指定してkill

$ kill -15 12345 #pidはあくまで例

ここのoptionで指定するシグナルは15がterminationで一緒か?
どうやらCPUごとに一部変わるそうで、x86なら-15SIGTERM(termination)で終了できるらしい。
我が家のintelmacさんはx86かと思うので-15

Springなら
1. 一括終了を最初に試す、
2. ダメならpkill

$ spring stop
$ pkill -15 -f プロセス名 # ダメなら

所感

テスト駆動で書きながら、コントローラからビューに至るまでの流れをトレースできたように思う。
簡単なテストだが、まだ苦に思わない程度で済んでいる。
演習で2,3度同じような作業が繰り返されるので、少しずつ馴染めそう。

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

rails specで特定のファイルを指定してテストする

ググると

rails spec spec/models/user_spec.rb

のようなのが出てきますが、実際は全部テスト実行されます。どこかのバージョンで変わったみたい。

うちのRails 5.2環境ではこれでいけた。

rails spec SPEC=spec/models/user_spec.rb
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker Compose + Railsでgemが無いとエラーがでる。

背景

docker-composeでrails環境を構築したが起動せず。
gemが無いと言われているのでdocker-compose run 'コンテナ' bundle intallの実行で解決したが、なんでDockerfile内でbundle installしているのに再度bundle intsallしないといけないんだろうと疑問に思ったので調査してみました。

構築時のファイル例

Dockerfile
FROM ruby:2.6.3

RUN apt-get update -qq && \
    apt-get install -y build-essential \
                       libpq-dev \
                       postgresql-client &&\
    rm -rf /var/lib/apt/lists/*

# install nodejs
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
&& apt-get install -y nodejs

# install yarn
RUN apt-get update && apt-get install -y curl apt-transport-https wget && \
    curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
    echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
    apt-get update && apt-get install -y yarn

ENV APP_HOME /my_app
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
ADD Gemfile Gemfile
ADD Gemfile.lock Gemfile.lock

RUN bundle install

ADD . $APP_HOME
docker-compose.yml
version: '3'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    command:
      [ "bash", "-c", "rm -f tmp/pids/server.pid; RAILS_ENV=development bundle exec rails s -b 0.0.0.0" ]
    volumes:
      - .:/my_app
      # volumeを使用してbundle installしてきたものを永続化
      - bundle:/usr/local/bundle 
volumes:
  bundle:
Gemfile
source 'https://rubygems.org'
gem 'rails', '6.0.0'

空のGemfile.lock

$ touch Gemfile.lock

よくある構築コマンド例

# railsプロジェクトを作成
$ docker-compose run web bundle exec rails new . --force --skip-bundle

# Dockerfileからイメージを作成
$ docker-compose build

# コンテナ(rails)の起動
$ docker-compose up

を実行すると

web_1  | bundler: failed to load command: rails (/usr/local/bundle/bin/rails)
web_1  | Bundler::GemNotFound: Could not find gem 'sqlite3 (~> 1.4)' in any of the gem sources listed in your Gemfile.
...

と出て起動しない。

コンテナに入ってgemを確認してみると

$ docker-compose run web ls /usr/local/bundle/gems
actioncable-6.0.0      erubi-1.8.0          rack-test-1.1.0
actionmailbox-6.0.0    globalid-0.4.2       rails-6.0.0
actionmailer-6.0.0     i18n-1.6.0           rails-dom-testing-2.0.3
actionpack-6.0.0       loofah-2.2.3         rails-html-sanitizer-1.2.0
actiontext-6.0.0       mail-2.7.1           railties-6.0.0
actionview-6.0.0       marcel-0.3.3         rake-12.3.3
activejob-6.0.0        method_source-0.9.2  sprockets-3.7.2
activemodel-6.0.0      mimemagic-0.3.3      sprockets-rails-3.2.1
activerecord-6.0.0     mini_mime-1.0.2      thor-0.20.3
activestorage-6.0.0    mini_portile2-2.4.0  thread_safe-0.3.6
activesupport-6.0.0    minitest-5.11.3      tzinfo-1.2.5
builder-3.2.3          nio4r-2.5.0          websocket-driver-0.7.1
concurrent-ruby-1.1.5  nokogiri-1.10.4      websocket-extensions-0.1.4
crass-1.0.4            rack-2.0.7           zeitwerk-2.1.9

docker-compose buildのときにbundle installしたはずなのにgem 'rails'でインストールしたgemしか入っていない。(rails newで更新されたGemfileのgemがインストールされていない)

なぜ起きるのか

下記条件で発生します。

  • bundle installしてきた内容をvolumeを使用してデータを永続化をしている。
  • rails newで--skip-bundleしている。

ポイント

  • docker-compose buildではvolumeと紐付かない
  • docker-compose runはvolumeと紐づく。

原理

# 初回のbuildが走る。bundle installで ”railsのみ” がコンテナ内の/usr/local/bundleにインストールされる。
# volumeと紐づくので ”railsのみ” がvolumeに保存される。
$ docker-compose run web bundle exec rails new . --force --skip-bundle

# 新しいGemfileのgemがコンテナ内の/usr/local/bundleにインストールされる。
# volumeと紐づかないのでvolumeは更新されない。
$ docker-compose build

# volumeと紐付いたタイミングで/usr/local/bundleがvolumeに上書かれてしまう。
$ docker-compose up

対応

  • docker-compose run bundle installでvolumeを更新する。
  • volumeを一回削除し再度作成することによって、volumeの中身を/usr/local/bundleと同じにする。
  • rails newする時に--skip-bundleを使用しない。

疑問

docker-compose run bundle installをどうせ走らせるのならDockerfileからbundle installを削除していいのでは。

イメージとdocker-compsoeを1セットと考えるとそう思いますが、同じイメージを使ってvolumeを使わないパターンもあり得るのでbundle installをDockerfileから削除するのが必ずしも正しいわけではないのかなと感じました。
開発する上で下記を意識すれば問題ないか思います。

  • gemをvolumeで管理しない:docker-compose buildでgemを管理する。
  • gemをvolumeで管理する:docker-compose run 'コンテナ' bundle installでgemを管理する。(docker-compose buildbundle installが走っちゃうのは我慢する?)

さいごに

Qiitaとかにあるチュートリアルをそのまま実行して起動できなくてハマった方もいると思うので、少しでも参考になればと思います。
間違えや不足などあればご指摘頂ければと思います。

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

他言語経験者がRailsの案件にジョインしたときに、何を足掛かりにすべきか

はじめに

 この記事はOmotesando.rb #50で、参加者から質問を募集して、LTを行うという企画の中で、未経験者・初学者からのRailsプロジェクトに参画する際の質問が多かったことから、「実際に案件に参画するときにどのようなキャッチアップをしていけばよいか」という観点で話してみようと思い立ち、作成しました。

対象読者・想定プロジェクト

 Ruby/Railsのプロジェクトに参画したことのない、Ruby/Railsプロジェクト未経験なWeb技術者を対象としています。また、Ruby/Railsの知識については、Railsチュートリアルは一通り目を通しているという前提で書いています。また、想定しているプロジェクトとしては、既に案件はスタートしており、gitリポジトリの整備、環境等の整備が一通り終わっており、人の受け入れ態勢が整っているプロジェクトであることを想定しています。
 最初の関門である、環境構築の部分から書こうと思ったのですが、ここはプロジェクトによって様々なケースがあり、ボリュームが大きくなりそうだったので、今回の記事の中ではスキップして、環境構築は完了したという前提で話を勧めます。

全体を把握する

 プロジェクトに初めて入った時に、最初にやるべきことは全体の把握です。というのも、現実のRailsプロジェクトはRailsチュートリアルのようにシンプルではありません。むしろ基本に忠実に作られていることの方が稀です。いくつかのRuby/Railsプロジェクトに参画した経験があれば、どの程度しっかり作られているのかの勘が利くのですが、Rails未経験者・初学者の場合、そのあたりの感覚がよく分からないため、まず関わるプロジェクトがどの程度基本を押さえて作られているのかを把握しておく必要があります。

 全体を把握するのに、まず以下を見ておくとよいでしょう。

  • Gemfile / Gemfile.lock
  • routes.rb
  • app以下、lib以下
  • config/initializers以下
  • spec、もしくはtest以下

Gemfile / Gemfile.lock

 Railsでは多数のGem(ライブラリ)が使われていて、中規模ぐらいのRailsプロジェクトになってくると、依存するGemも含めて100以上のGemが使われていることも珍しくはありません。Railsチュートリアルでは、極力Gemを使わない構成になっているので、あまり触れることはありませんが、現実のプロジェクトではGemが大量に導入されています。
 ライブラリによってはRailsの挙動を大きく変更するものがあったり、プロジェクトのルールとしてGem特有の記法を強制するものもあるので、まずどのようなGemが使われているのかを把握しておく必要があります。

 Gemfileの中のgemを調べるときはrubygems.orgから、調べたいGem名を入力して、詳細画面からgithubやHomepage等のサイトに飛んで、README.md等のドキュメントを参照します。初学者のうちは分からないGemが多いと思いますので、調べるのも大変でしょうが、経験が蓄積されてくると全体の作りやプロジェクトのルールなども見えてくるので、ざっくりと概要をつかんでおくとよいと思います。

 以下は私がプロジェクトにジョインしたときにあったら注意すべきGemと対応例の一例です。

gem 対応例
devise 認証処理がある。ユーザ名・パスワードの管理のテーブルにUsers等が使われていると考えられるので、app/models以下からdeviseの文字列を検索する
omniauth-xxxx 外部認証連携が存在する。config/以下に認証連携用の設定が書き込まれていると考えておく。
acts_as_paranoid フラグを立ててデータを消したことにする論理削除と呼ばれる概念がある。対象のモデルは強制的にdeleted_at is not nullのクエリが付加されるため、app/models以下からacts_as_paranoidの文字列を検索し、対象となるモデルを把握しておく。
paranoia 同上
ruby-grape ActionControllerではないAPIエンドポイントを持っている。app/以下からGrape::APIを検索して、場所を把握しておく。また、エンドポイントはroutes.rbに書かれていることが多いため、合わせて参照しておく。
sidekiq 実際のURLリクエストとは別タスクとして実行される非同期処理がある。perform / perform_laterなどの文字列を検索し、非同期処理の内容自体やトリガー部分を確認しておく。
resque 同上
sequel DB検索にActiveRecordを使っていない可能性がある。プロジェクトのルールを確認する。
composite_primary_keys データベースの主キーがidではない可能性がある。app/models以下でprimary_keyで検索し、各テーブルの主キーを確認する。
sassc-rails CSSの代わりにassets/stylesheetsにSASSが使用されている可能性がある。
haml-rails ERBの代わりにhamlが採用されている。hamlの記法を用いてViewを書く必要がある。
slim-rails ERBの代わりにslimが採用されている。slimの記法を用いてViewを書く必要がある。
simple_form Form Objectと呼ばれる概念が導入されている可能性がある。

 一つ一つ詳細に見ている時間がないという場合には、そのGemがどういう用途で導入されているかぐらいは確認しておきましょう。
 The ruby toolboxというサイトで、Gem名で検索するとGemのカテゴリが分かるので、大まかに使用用途を推測することができます。

routes.rb

 RailsではRESTful URLでリソースベースのアクセスになるようにURL設計をしていくのが一般的ですが、現実のプロジェクトがしがらみなくRailsの推奨される構成でURL設計されているかというと、そういうわけではありません。例えば他のプロジェクトから移行するようなリプレース案件では、以前のURLと整合性がとれるようにURLをマッピングしなおさなければいけませんし、Railsを良く知らない設計者の趣味ですべてのURLをPOSTで記述しなければならないというトンデモルールが強制されている可能性すらあります。routes.rbを読んで、まずRails一般的なURL設計になっているかどうかを理解しておく必要があります。

 Rails GuidesのRailsルーティングを熟読し、URL定義のパターンを理解しておきましょう。普通にget/postなどのメソッドで個別に定義する表現、matchメソッドでパターンマッチさせる表現、resourcesを使った表現や、複数のresourcesメソッドをネスト構造にしたnested resourcesやnamespaceと組み合わせた表現など、色々あります。

 routes.rbを読む前にrake routesを叩いて、エンドポイントをざっくりと俯瞰しておきましょう。

app以下、lib以下

app以下

 app以下にはassets, controllers, models, views, helpers, mailersがRailsの標準のディレクトリとして作成されています。これらのディレクトリの中身については、後で詳しく確認するとして、その他にディレクトリが存在しないかを確認しましょう。例えばservicesというディレクトリが存在していたら、そのプロジェクトではServiceクラスという独自のレイヤが存在する可能性がありますし、formsというディレクトリが存在していたら、そのプロジェクトではForm Objectという独自のレイヤが存在する可能性があります。

 いずれもmodelクラスやcontrollerクラスが混沌としないように、プロジェクトの誰かが導入したものですので、これらの独自のレイヤをどのようなケースで使うべきなのかについては、導入した人物がまだ在籍しているのであれば直接質問する。そうでなければ、既存のコードから、どのようなメソッドが定義されていて、どのようなケースで、どこから呼ばれるのか、については把握しておく必要があります。

 ServiceクラスもForm Objectも賛否両論あるものですが、プロジェクトの中できちんとルールが統一されているのであれば、導入自体はあまり問題ではありません。問題となるケースとしては責務が曖昧である、もしくは使用用途を逸脱した神クラスになっている場合や、導入が中途半端であるものは使っていて、あるものは使っていないなどの混在が存在する場合です。そのような可能性も含めて、プロジェクトとして使うべきなのか・使わないべきなのかの意思統一をしておく必要があります。

参考文献
Railsで重要なパターンpart1:Sercice Object(翻訳)
Rails: Form Objectと#to_modelを使ってバリデーションをモデルから分離する(翻訳)

lib以下

 lib以下は古くからGemにするまでもないようなプロジェクトの内部だけで完結するプライベートなファイルの置き場として利用されています。よく見る例としてはomniauthの独自strategyのファイルの置き場や、隠れオレオレライブラリ、オープンクラスで既存の振る舞いを書き換えたモジュールなどが配置されていることがあります。プロジェクトのファイルはapp以下に並ぶので、見落としがちなのですがlib以下にファイルがある場合は、そのファイルがどこでrequireされていて、何をしているのかは簡単に把握しておくとよいでしょう。コードが分からなくても、git log / git blameや、チケットから目的が理解できる場合もあります。

config/initializers以下

 config/initializers以下はRailsが起動するプロセスの中で呼び出されます。起動プロセスの詳細についてはRailsガイドのRailsの初期化プロセスに詳しく載っているので、そちらを参照してください。ここもlib以下と同様に、app以外でプロジェクトのファイルが配置される可能性があるため見落としがちなのですが、Gemの初期化処理や、lib以下に置いたファイルのrequire処理など、アプリケーションの重要な手掛かりとなるコードが置かれていることがあります。

spec(もしくはtest以下)

 参画しているプロジェクトにテストコードが十分に書かれていれば、キャッチアップを早める足がかりとなります。テストコードがどの程度書かれているかについては、rake statsで、本体コードとテストコードのコード行数の比率を見てみましょう。あくまで個人的な目安ですが、本体コードとテストコードが同程度書かれていれば、正常系程度の最低限のテストコードが用意されていると見込める。本体コードの2~3倍程度テストコードがあれば、十分な分量のテストコードが用意されていると判断しても良いでしょう。
 注意点としては過去にはテストコードが用意されていたが、メンテナンスする文化がなくなり、現在はテストコードはFailするものばかりで役に立っていないようなケースもあるため、まずはテストコードを手元で実行して、全部Passするかの確認はしておきましょう。大抵のRailsプロジェクトはbundle exec rake specbundle exec rspec spec/**/*_spec.rbで動くようになっていますが、特殊な初期化が必要なために起動は別のコマンドで行っていたり、巨大なプロジェクトではRSpecが多すぎるため、分割して実行しているような場合もあります。プロジェクトでどのようにテストコードを実行するかの手順は確認しておきましょう。

app以下を詳細に確認していく

 全体を軽く見通した後は、app以下の個別のファイルについて目を通していきます。
 個別のファイルについて詳細に目を通すのは実作業に取り掛かる段にして、先に確認しておくのは以下のようなことです。

app/controllers以下

  • application_controller.rbに定義されている共通のコールバック
  • application_controller.rbにMix-inされている各種モジュールの意味
  • app/controllers/concernsディレクトリ以下にあるモジュール群
  • controllers以下の各コントローラに定義されているコールバック
  • controllers以下の各コントローラにMix-inされているモジュール

app/models以下

  • application_record.rbに定義されている共通のコールバック
  • application_record.rbにMix-inされている各種モジュールの意味
  • app/models/concernsディレクトリ以下にあるモジュール群
  • models以下の各モデルに定義されているコールバック
  • models以下の各モデルにMix-inされているモジュール
  • models以下の各のhas_one / has_many / belongs_toの対応関係
  • 各種バリデーションの充足度

application_controller.rbやapplication_record.rbに定義されているコールバックはコントローラ・モデルに影響するため、個別のモデルだけを見ていても分からないような振る舞いをすることがあります。またRubyではMix-inと呼ばれる方法でinclude / extend / prepend等でモジュールが差し込まれることがあり、これがapplication_controller.rbやapplication_record.rbに入っていると、すべてのクラスで影響を受けるようになっています。

モジュールはGemによって利用可能なものだったり、concerns以下のディレクトリに配置されたものを呼び出したりするものが一般的なので、concernsディレクトリを見ておけば振る舞いを変えるようなモジュールを先に見つけておくことができるでしょう。

application_record.rbについては、Rails5以降で導入された概念なので、もしかするとActiveRecord::Base.include AwesomeModuleのような形でモジュールがincludeされているケースもあります。このような記述をしているときは、大抵イレギュラーな処理が挟み込まれているので、includeされているモジュールが何者なのかは把握しておけると良いです。

コールバックについてはRailsチュートリアルにもあるので、細かい説明は不要かと思いますが、より詳細に知りたい場合はRailsガイドのActiveRecordコールバックに目を通しておきましょう。

バリデーションについては、プロジェクトによっては全く書かれていなかったり、とても厳密に記述していたりと記述がまちまちなので、参画するプロジェクトがどの程度しっかりと書かれているのかを見ておきましょう。ベースとなる設計書や、バリデーションのガイドラインがプロジェクトとして用意されているのであれば、当然それに従うのが良いと思います。

app/views以下

 views以下については、コントローラとメソッドの対応が、ディレクトリとファイル名の関係になっていることが多いので、コントローラから追っていけば対応関係は大体把握できるので、特に留意点もないのですが、layoutsファイルにapplication.html.erb以外のファイルがある場合は、controller側からlayoutメソッドを呼び出している箇所を検索しておくとよいです。views以下で使われているテンプレートエンジンはプロジェクトによってerbだったり、slimだったり、hamlだったり、jbuilderだったり、rablだったりしますが、記述の仕方が違うだけで、最終的にはhtmlやjsonファイルに変換されるという点では本質的には同じことなので、記述方法は公式ドキュメントで学びましょう。

app/helpers以下

 ActionView内でレシーバなしで呼び出されているメソッドがあれば、Gemのメソッド、もしくはapp/helpers以下に定義されている可能性が高いです。application_helper.rbにまとめて書かれていて、他のモジュールは空という場合もあります。Railsではconfig.action_controller.include_all_helpersを明示的にfalseにしない限り、どこのhelperに記述しても結果は同じということもあり、どのhelperに書くかはプロジェクト次第なところがあります。まずはhelpers以下のファイルをざっと読んでみて、どういう指針で定義されているかは見ておきましょう。

app/assets以下、もしくはapp/javascript以下

 まだ多くのRailsプロジェクトはapp/assets以下で管理されていると思いますが、最近はWebpackerなどを導入するプロジェクトもあり、app/javascript以下にJavascriptが配置されていることもあります。ビルド時に何か問題が発生したときに、sprocketsなのかwebpackなのかは知っておく必要があります。

まとめ

 以上、Railsのプロジェクトに参画しておくときに見ておくとよいものを、簡単にまとめてみました。
 ここまで一通り読んでおくと、エンドポイントから機能をたどる時は、routes.rb → app/controllers/ → app/models → app/viewsと辿って、該当の機能を追うことができますし、新しい機能を追加するときも、周りの記述方針と合わせることができます。Railsに慣れないうちは、残念ながら目の前にあるコードが全てだと思うので、良し悪しを判断することは難しいと思いますが、まずは全体的に一貫性のある、統一感のあるコードが書けるようになることから始めましょう。

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

Ruby on RailsのアプリをGAEでデプロイする方法

1.まずはじめに

ポートフォリオを作成する上で少しオリジナル性を出したくてherokuではなくGCPを利用しようとしたのがきっかけになります。
その中で一番時間を取らなさそうなGAEでアプリをデプロイすることにしましたのでその際にやったことを記述しております。

2.準備したもの

2-1.rubyのバージョン

サーバーのrubyにバージョンとアプリのバージョンを揃えました。
こちらでバージョンアップについて書いてます

2-2.GitHubのレポジトリ

GitHubのレポジトリをクローンしますので必須になります。

2-3.app.yaml

ルートディレクトリーにapp.yamlファイルを作成しておきます。

app.yaml
entrypoint: bundle exec rackup --port $PORT
env: flex
runtime: ruby

3.GCP操作方法

3-1.GAE内での操作

GCPでApp Engineをクリックします。
GCPでGAEの選択

クリックすると下記の画面になるかと思います。
その中の赤枠でカッコってあるものをクリックします。(Cloud Shellが起動されます)

Cloud Shellの起動

3-2.GitHubのクローン

Cloud Shellが起動したらまず初めに自身のレポジトリをクローンします。

$ git clone https://github.com/Nash-BETA/test.git
Cloning into 'test'...
remote: Enumerating objects: 8394, done.
remote: Counting objects: 100% (8394/8394), done.
remote: Compressing objects: 100% (6611/6611), done.
remote: Total 8394 (delta 1502), reused 7935 (delta 1047), pack-reused 0
Receiving objects: 100% (8394/8394), 34.13 MiB | 9.60 MiB/s, done.
Resolving deltas: 100% (1502/1502), done.

3-4.GAEのgemのインストールおよびDBの作成

クローンが完了したらディレクトリを移動してアプリケーションコードを表示させます。

$ cd test
$ cat app.yaml

次にbundle installを行います。

$ bundle install

DBの作成をします。

$ rake db:migrate

3-5.サーバーの選択

GCPコマンドでアプリの作成およびサーバーの選択

$ gcloud app create
You are creating an app for project [First project].
WARNING: Creating an App Engine application for a project is irreversible and the region
cannot be changed. More information about regions is at
<https://cloud.google.com/appengine/docs/locations>.
Please choose the region where you want your App Engine application
located:
 [1] asia-east2    (supports standard and flexible)
 [2] asia-northeast1 (supports standard and flexible)
 [3] asia-northeast2 (supports standard and flexible)
 [4] asia-south1   (supports standard and flexible)
 [5] australia-southeast1 (supports standard and flexible)
 [6] europe-west   (supports standard and flexible)
 [7] europe-west2  (supports standard and flexible)
 [8] europe-west3  (supports standard and flexible)
 [9] europe-west6  (supports standard and flexible)
 [10] northamerica-northeast1 (supports standard and flexible)
 [11] southamerica-east1 (supports standard and flexible)
 [12] us-central    (supports standard and flexible)
 [13] us-east1      (supports standard and flexible)
 [14] us-east4      (supports standard and flexible)
 [15] us-west2      (supports standard and flexible)
 [16] cancel
Please enter your numeric choice:

14を選択。(特に理由がないのですがus-east4を選択しました)

3-5.app.yamlファイルにシークレットコードの追加

$ bundle exec rails secret
[シークレットキーが表示されます]
$ vim app.yaml
 entrypoint: bundle exec rackup --port $PORT
 env: flex
 runtime: ruby

vim上でoをタイピングして挿入モードにして、下記の様に追加する。

app.yaml
 entrypoint: bundle exec rackup --port $PORT
 env: flex
 runtime: ruby
 env_variables:
  SECRET_KEY_BASE: [シークレットキー]

escキーを押して:wqを入力すれば、変更内容の保存完了

3-6.デプロイして完了

$ gcloud app deploy
Updating service [default] (this may take several minutes)...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://Firstproject.appspot.com]

これで完了

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

Rails 画像アップロード機能の実装方法 メモ

初めに

railsで画像をアップロードする機能を実装するには、carrierwaveというgemを使う方法があります。
今回、画像を投稿する機能について学習したので、自分なりにまとめておこうと思います。

使用するgem

・Carrierwave

画像をアップロードするために必要な機能を追加するためのgem

※Carrierwaveの導入には「ImageMagick」がインストールされている必要があるので、
実装前に以下のコマンドを入力して置くといいかもです。

$ brew install imagemagick

・Minimagick

画像に対して、画像同士を合成したり、リサイズしたりと編集することができるようになるためのgem

実装

では実装に入っていきます。
1.まずは上記の2つのgemを扱えるようにするためGemfileに以下のように追記します。

Gemfile
gem 'carrierwave'
gem 'mini_magick' #画像に対して処理を行う場合

2.gemをGemfileに追記したのでターミナルで以下のコマンドを実行します。

$ bundle install

3. 次にcarrierwaveを利用するためのアップローダーを作成します。carrierwaveを導入したことで以下のコマンドが利用できるようになったので、ターミナルで実行しましょう。

$ rails g uploader image ※imageの箇所は任意の名前でOKです。例:pictureなど

するとapp/uploadersディレクトリ以下にimage_uploader.rbが作成されます。
このファイルに別途記述を行うことで、アップロードの仕方を設定できます。
※設定方法は下記5.以降を参照

4.アップローダーが作成できたので、画像アップロード機能を実装したいモデルに対して編集を行っていきます。

モデル名.rb
# app/models/モデル名.rb
  mount_uploader :image, ImageUploader

上記を追記することで、アップローダーを任意のモデルに対して
マウントすることができました。
※マウント
取り付ける、搭載するなどの意味

↑↑↑画像をアップロードする機能のみの場合はここまで↑↑↑

5.アップロードする画像に対して別途処理を行いたい場合は
以下の設定を行います。
3.で行ったrails g uploader imageで作成された
image_uploader.rbを確認し、
include CarrierWave::MiniMagickがコメントアウトされているので、これを以下のように解除しましょう。
コメントアウトを解除することでgem 'mini_magick'を使用することができるようになります。

app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick

これでmini_magickの機能が使用できるようになったので
例えば、image_uploader.rbの任意の箇所に以下のコードを追記すると、縦横比を維持したまま、width, heightを800pxにリサイズしアップロードすることができるようになります。

app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick
  # ~省略~
  process resize_to_fit: [800, 800]
end

おわりに

以上がgemのCarrierwaveとmini_magickを使用した画像のアップロード機能の実装になります。
画像の投稿はwebアプリケーションにおいて基本的な機能ですので抑えて置きたいと思います。

使用したgemのGithub

・Carrierwave
https://github.com/carrierwaveuploader/carrierwave
・mini_magick
https://github.com/minimagick/minimagick

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

Rails6 のちょい足しな新機能を試す71(implict_order_column 編)

はじめに

(多分)Rails 6 に追加された新機能を試す第71段。 今回は、 implicit_order_column 編です。
Rails 6 では、 firstlast で使われるソートのカラムを implicit_order_column で指定できるようになっています。
これは、id を UUID にしていた場合に、 firstlast が予測できる結果となるようにするためのようです。
(Rails 6.0.0 がリリースされましたが、確認当時は、 Rails 6.0.0.rc2 が最新でした。悪しからず :bow:)

Ruby 2.6.3, Rails 6.0.0.rc2, PostgreSQL 10.7 で確認しました。Rails 6.0.0.rc2 は gem install rails -v 6.0.0rc2 --prerelease でインストールできます。

$ rails --version
Rails 6.0.0.rc2

今回は、 User モデルを作成して rails console を使って確認します。

プロジェクトを作る

rails new rails_sandbox --database postgresql
cd rails_sandbox

User モデルを作る

bin/rails g model User name

id を UUID にする

id を UUID にするために、マイグレーションのファイルを変更します。

db/migrate/20190803221758_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto') #この行を追加
    create_table :users, id: :uuid do |t| # id: :uuid オプションを追加
      t.string :name

      t.timestamps
    end
  end
end

seed データを作成する

seed データを作成します。 name の昇順にデータを登録します。

db/seeds.rb
User.create(name: 'Andy')
User.create(name: 'Bob')
User.create(name: 'Cindy')

マイグレーションを実行し seed データを登録する

bin/rails db:create db:migrate db:seed

rails console で確認する

rails console で確認します。

User.first を実行してみます。

irb(main):001:0> User.first
  User Load (0.3ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<User id: "5da612ca-f055-4678-9c87-927b0a1a28d2", name: "Cindy", created_at: "2019-08-03 22:24:51", updated_at: "2019-08-03 22:24:51">

結果が Cindy になってしまいました。 (結果は必ず Cindy になるとは限りません。)
SQL を確認すると id でソートされていることもわかります。

User.last を実行してみます。

irb(main):002:0> User.last
  User Load (0.5ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<User id: "fe31d9a5-8de0-4d35-8a6f-183902f2884b", name: "Bob", created_at: "2019-08-03 22:24:51", updated_at: "2019-08-03 22:24:51">

結果が Bob になりました。
SQLを確認すると id の降順にソートした最初のレコードが検索されているのがわかります。

implicit_order_column を使う

User モデルを変更して implicit_order_column で :name を指定してみます。

app/models/user.rb
class User < ApplicationRecord
  self.implicit_order_column = :name
end

rails console で確認する

修正を反映させるため reload! します。

irb(main):003:0> reload!
Reloading...
=> true

User.first の結果は、 Andy になります。 name の昇順でソートされていることがわかります。

irb(main):004:0> User.first
  User Load (0.2ms)  SELECT "users".* FROM "users" ORDER BY "users"."name" ASC LIMIT $1  [["LIMIT", 1]]
=> #<User id: "cc7ff0b1-4dc3-47f4-a5cd-259a804c9690", name: "Andy", created_at: "2019-08-03 22:24:51", updated_at: "2019-08-03 22:24:51">

User.last の結果は、 Cindy になります。 name の降順でソートされていることがわかります。

irb(main):005:0> User.last
  User Load (0.6ms)  SELECT "users".* FROM "users" ORDER BY "users"."name" DESC LIMIT $1  [["LIMIT", 1]]
=> #<User id: "5da612ca-f055-4678-9c87-927b0a1a28d2", name: "Cindy", created_at: "2019-08-03 22:24:51", updated_at: "2019-08-03 22:24:51">

複数カラムの指定はできない

app/models/user.rb
  self.implicit_order_column = %i[name created_at]

とした場合は、 ActiveRecord::StatementInvalid エラーになりました。
まあ、そりゃそうですよね。 複数形 ( implicit_order_columns ) じゃないですもんね。

irb(main):011:0> User.first
Traceback (most recent call last):
        2: from (irb):11
        1: from (irb):11:in `rescue in irb_binding'
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR:  column users.[:name, :created_at] does not exist)
LINE 1: SELECT "users".* FROM "users" ORDER BY "users"."[:name, :cre...
                                               ^

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try071_implicit_order_column

参考情報

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

scaffoldの使い方

scaffoldとは

モデルやコントローラー、ビューを作っていき、さらに必要なルーティングを作成していく必要があるがrailsには簡単にアプリケーションの雛形を作ってくれる機能があり、それがscaffoldです。scaffoldを使うことで素早くrailsアプリケーションを作ることができる。

作成手順

rails new sample

作成後、該当ディレクトリへ移動する

cd sample

移動後に下記コマンドを実行

rails generate scaffold モデル名 カラム名1:データ型1 カラム名2:データ型 2 …
example
rails g scaffold user name:string age:integer

指定できる型一覧

  • string : 文字列
  • text : 長い文字列
  • integer : 整数
  • float : 浮動小数
  • decimal : 精度の高い小数
  • datetime : 日時
  • timestamp : タイムスタンプ
  • time : 時間
  • date : 日付
  • binary : バイナリデータ
  • boolean : Boolean

作成されるもの

  • マイグレーションファイル
    • db/migrate/xxxxxxxxx_create_users.rb
  • モデル
    • app/models/user.rb
  • コントローラー
    • app/controllers/users_controller.rb
  • ルーティング
    • config/routes.rb
  • ビュー
    • app/views/users/index.html.erb
    • app/views/users/edit.html.erb
    • app/views/users/show.html.erb
    • app/views/users/new.html.erb
    • app/views/users/_form.html.erb

routes.rbでは7つのアクションが自動的に定義される。

rake db:migrate

テーブルの作成

以上

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

herokuでのデプロイ

 はじめに

herokuを使ってデプロイができたので、その方法を記録として残しておく。

 準備

gemfileの設定

Gemfile
# sqlite

sqliteをコメントアウト

Gemfile
group :production do
  gem 'pg'
end

上記コードはgemfile最下部に記載

環境ごとのデータベースの設定変更を行う
開発時にはmysql使用、本番環境(heroku)ではPostgreSQL(pg)を使用
環境にあうように設定

ターミナル
bundle install

config/datebase.ymlの設定

config/database.yml
production:
  <<: *default
  adapter: postgresql  #postgreSQLに接続
  encoding: unicode    #文字コード
  pool: 2              #データベース接続可能上限数

config/environments/production.rbの設定

config/environments/production.rb
  config.assets.compile = true
# falseとなっているのでtrueにする

binフォルダ内の設定

スクリーンショット 2019-08-28 09.43.20.png

binフォルダ内の各ファイル.rb
    #!/usr/bin/env ruby #ここに記載のバージョンを削除

Git

gitにコミットをしておく

heroku

herokuに登録しておく

会員登録後、
https://devcenter.heroku.com/articles/heroku-cli
上記から個人の使用にマッチするものをダウンロード

ターミナル操作

$heroku login

上記コマンド入力後に下記コマンドが表示されるので適当にキーを叩く

Press any key to open up the browser to login or q to exit:

スクリーンショット 2019-08-28 09.58.19.png
ターミナル上に上記画像の表示が現れ、自動でブラウザが開かれるのでlog inする
スクリーンショット 2019-08-28 09.58.45.png

ログイン後、再びターミナルへ

$heroku create アプリ題名

デプロイ

$git push heroku master

デプロイ成功後に下記コマンドの実行

heroku run rails db:migrate

上記コマンド入力後に先程、実行した下記コマンドで表示されるurlにログインすれば、自分の作成したアプリが表示されるはず!!

$heroku create アプリ題名

補足

git push heroku master時にCould not find 'bundler'のエラーが発生しました。

私は色々とググった結果
rubyとbundlerのバージョンをあげることで解決しました。

最後に

コマンドの一覧やデプロイ時のエラー対処方法なども調べてまとめていきたいです。
デプロイは凄い大変なイメージがありましたがherokuでのデプロイは操作が簡単、userのやることが少なくて楽だという印象を受けました。

参考記事

https://qiita.com/amuyikam/items/989300248f471020ca18
https://qiita.com/tktcorporation/items/0ef8c930fc18ce72c301

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

Win上でRails+Bootstrapを使用した時に出てくるExecJS エラーを直したい(直す)

はじめに

WindowsでRailsアプリケーションを作成し、
Bootstrapを導入したところ、ExecJSエラーが出て、起動しない。
- Windows 10 proもしくはhomeで確認
- Railsのバージョンは5.2.3
- Rubyのバージョンは2.6.3

最近Rails6にアップデートされたので、この記事は今後使えなくなる可能性があります。

詳細

こんなエラーがターミナル上で出てるのではないでしょうか。

ExecJS::ProgramError in Home#index
Showing C:/Source/Repos/graph-tutorials/ruby-test/app/views/layouts/application.html.erb where line #8 raised:

identifier '(function(opts, pluginOpts) {return eval(process' undefined
Rails.root: C:/Source/Repos/graph-tutorials/ruby-test

解決策

僕はこのissueをみて使えるようになりました。
https://github.com/twbs/bootstrap-rubygem/issues/157

やり方

1.Gemfileの修正

duktapeのgemを探してコメントアウト、もしくは削除します。

2.Node.jsのインストール(Node.jsがインストールされていない場合のみ)

Node.jsの公式ページからダウンロードします。
https://nodejs.org/ja/download/
推奨版と最新版があって、最新版をダウンロードしたくはなりますが、
ここはその気持ちを押し殺して推奨版をダウンロードします。その後インストールをしてください。
nodejs.org_ja_download_.png

その後Windowsで環境変数の設定を開き、PATHを通してください。
PATHの通し方はこちらを参考にするといいです。
いろんな方法がありますね。
https://qiita.com/yuki12/items/9723f60907508b11504b

最後にコマンドプロンプト or Gitbash or PowerShellを開いて
下記のコマンドを入力し、バージョンが表示されるか確認してください。

$ node -v

config/boot.rbに追記する。

下記のコードを貼り付けてください。
runtime時にnodeを使うように指示します。

config/boot.rb
ENV['EXECJS_RUNTIME'] = 'Node'

サーバーを再起動

サーバーを再起動して、エラーが出ないか確認してください。

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

Win上でRails+Bootstrapを構築の時に出てくるExecJS エラーを解決したい(解決する)

はじめに

WindowsでRailsアプリケーションを作成し、
Bootstrapを導入したところ、ExecJSエラーが出て、起動しない。
- Windows 10 proもしくはhomeで確認
- Railsのバージョンは5.2.3
- Rubyのバージョンは2.6.3

最近Rails6にアップデートされたので、この記事は今後使えなくなる可能性があります。

詳細

こんなエラーがターミナル上で出てるのではないでしょうか。

ExecJS::ProgramError in Home#index
Showing C:/Source/Repos/graph-tutorials/ruby-test/app/views/layouts/application.html.erb where line #8 raised:

identifier '(function(opts, pluginOpts) {return eval(process' undefined
Rails.root: C:/Source/Repos/graph-tutorials/ruby-test

解決策

僕はこのissueをみて使えるようになりました。
https://github.com/twbs/bootstrap-rubygem/issues/157

やり方

1.Gemfileの修正

duktapeのgemを探してコメントアウト、もしくは削除します。

2.Node.jsのインストール(Node.jsがインストールされていない場合のみ)

Node.jsの公式ページからダウンロードします。
https://nodejs.org/ja/download/
推奨版と最新版があって、最新版をダウンロードしたくはなりますが、
ここはその気持ちを押し殺して推奨版をダウンロードします。その後インストールをしてください。
nodejs.org_ja_download_.png

その後Windowsで環境変数の設定を開き、PATHを通してください。
PATHの通し方はこちらを参考にするといいです。
いろんな方法がありますね。
https://qiita.com/yuki12/items/9723f60907508b11504b

最後にコマンドプロンプト or Gitbash or PowerShellを開いて
下記のコマンドを入力し、バージョンが表示されるか確認してください。

$ node -v

config/boot.rbに追記する。

下記のコードを貼り付けてください。
runtime時にnodeを使うように指示します。

config/boot.rb
ENV['EXECJS_RUNTIME'] = 'Node'

サーバーを再起動

サーバーを再起動して、エラーが出ないか確認してください。

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

Ruby on Rails + MySQLのアプリケーションをHerokuにデプロイする手順(Heroku.yml)

どんな記事か

  • Rails+MySQLのアプリケーションをDockerで環境構築した人が、herokuで本番環境を構築できるようになる。

対象読者

  • DockerでRails+MySQLを起動して、「Yay! You’re on Rails!」を表示している人。
  • 本番環境にも反映して誰からにも見せたい人。
  • デプロイのエラーで躓いて困っている人。

完成後のイメージと各ツールのバージョン

今回こちらの実機で確認しました。
- macOS Mojave 10.14.5
- Ruby 2.6.3
- MySQL 5.7
- Heroku 7.29
- Git 2.20.1

localhost_3002_.png

そもそもどうやって、DockerでRails+MySQLの環境構築をすればいいのという方へ??

こちらのgithubのページで、確認してもらえたらと思います。。
https://github.com/YutakaYamasaki/docker_setup_rubyonrails

ちなみに、今回のソースは全て上記の手順を行なった後、デプロイする形になります。

やること

  • Railsのアプリケーション修正、追加
  • Herokuにデプロイ

Railsアプリケーションのファイルを修正、追加する。

Gemfile(修正、追加)

ここで、mysqlとpgのgemを修正、追加します。
開発環境ではMySQLを使用しますが、本番環境(デプロイ)ではPostgreSQLを使用していきます。

変更前と変更後です。

Gemfile
##変更前
gem 'mysql2', '>= 0.4.4', '< 0.6.0'

##変更後
gem 'mysql2', '>= 0.4.4', '< 0.6.0', groups: %w(test development), require: false
gem 'pg', '~> 0.19.0', group: :production, require: false

database.yml(修正、追記)

こちらのファイルにも、本番環境ではPostgreSQLを使用するので、下記のように修正してください。
productionの項目がなければ、追記してください。
項目があれば、削除してください。

database.yml
production:
  <<: *default
  adapter: postgresql
  encoding: unicode
  pool: 5

heroku.yml(新規ファイル作成)

heroku.ymlファイルを作成します。
アプリのファイルの直下に、heroku.ymlファイルを作成して、下記のように記載してください。

heroku.yml
build:
  docker:
    web: Dockerfile
run:
  web: bundle exec puma -C config/puma.rb

これで各ファイルの編集が完了しました。
Docker側にもファイルの変更を反映させておきましょう。

$ docker-compose build

誤字脱字がないか確認した後に、
Herokuへデプロイを進めましょう!

Herokuにデプロイ

基本全てターミナルで行います。ターミナルの操作に慣れているという前提で進めていきます。

Herokuにログイン

下記のコマンドを打ちます。
途中でエンターキーを押すとブラウザが立ち上がるので、ブラウザで操作してログインが終わると、
ターミナルの方でもログインができます。

$ heroku login                                                                                                               
heroku: Press any key to open up the browser to login or q to exit: 
##ここでエンターキーを押すとブラウザが開くので、ログインを行う。

##ブラウザでログインができてターミナルに戻ると、下記が表示されるはず
Opening browser to https://cli-auth.heroku.com/auth/browser/**************
Logging in... done
Logged in as *******@email.com

Herokuにアプリケーションを作成する。

下記のコマンドを打ちます。
すると、URLが自動発行されます。

$ heroku create
##ちなみにcreateの後にスペースキーを押して、好きなアプリ名を入力すると、そのアプリ名のURLが自動発行されます。お試しあれ
Creating app... done, ⬢ *******
https://******.herokuapp.com/ | https://git.heroku.com/*******.git

Heroku側でPostgreSQLを使用する。

Heroku側でPostgreSQLを使用するように設定します。
クレジットカードを登録したり、有料会員になるとMySQLも使用できます。

$ heroku addons:create heroku-postgresql:hobby-dev                                                                             
Creating heroku-postgresql:hobby-dev on ⬢ ******... free
Database has been created and is available
 ! This database is empty. If upgrading, you can transfer
 ! data from another database with pg:copy
Created postgresql-transparent-70433 as DATABASE_URL
Use heroku addons:docs heroku-postgresql to view documentation

ちなみに、このURLにアクセスしてもエラーが出てきます。なぜなら、アプリがHeroku側にないから。
これからアプリをheroku側にアップロードして、デプロイします。

Heroku.ymlを使ってデプロイする。

Herokuではコンテナ諸々をデプロイすることができます。
その中で、デプロイする方法は2通りあります。
- Container Registry GAを使用してデプロイ
- Heroku.ymlを使用してデプロイ←今回はこちらを使用。

詳細は下記見てもらえると
https://devcenter.heroku.com/categories/deploying-with-docker
まずは、Heroku側でStackをcontainerにセットします。

$ heroku stack:set container

その後、下記のコマンドを打って、デプロイをしましょう。

$ git init
$ git add .
$ git commit -m "******"
$ git push heroku master

デプロイできたか確認する。

下記のコマンドでブラウザが立ち上がり、Railsのアプリケーションがデプロイされているか確認します。

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

大学2年生のオリジナルWebアプリケーション開発7日目

今日の流れ

  1. Eventモデル
  2. Event一覧の表示
  3. dateの短縮日付表示

改めて僕の開発しているアプリをご紹介しますと、出欠管理アプリを開発しています。
そのきっかけはサークルの出欠管理が非効率だったので、せっかくだから自分で作ってみようというところから始まりました。

管理する出欠は何かしらのイベント(Event)なので、Eventモデルを構築することを考えました。

1. Eventモデル

Eventモデルには何が必要なのか考えた結果、次のようなカラムとそのデータ型を選択しました。

カラム名 データ型
user_id references
event_name string
date datetime
memo text

カラム以外は基本的にRailsチュートリアルのmicropostをeventに置き換えただけとなっています。

次にイベントモデルのバリデーションを考えました。
user_id, event_name, dateには存在の、event_nameとmemoには文字数制限のバリデーションを施しました。

そして、userとeventを関連付けるためにbelong_to/has_manyを利用しました。

models/event.rb
belongs_to :user
models/user.rb
has_many :events, dependent: :destroy

2. Event一覧の表示

次にユーザーのページにそのユーザーの企画したEvent(フォームから作成予定)を一覧表示させました。
この部分はRailsチュートリアル第13章の13.2にあたります。
micropostの部分をeventに変更させるだけでしたが、後述するdateの表示で手間取りました。

3. dateの短縮日付表示

今日最も時間がかかったのはこの部分です。Railsチュートリアルにはdatetimeや日付表示に関して記述はなかったので自分で模索しながら進めました。

Event一覧中のdateの表示は短縮日付(正確な呼び名は知りません)、yyyy/mm/dd(曜日)という形で表示したかったのです。

調べているとすぐにstrftimeというメソッドを用いればよいことがわかりました。
しかし、以下の多くの要因で混乱してなかなかうまく表示されませんでした。具体的には、yyyy/mm/dd(曜日)としたいのに、2019-08-026 17:52:54 +0900みたいな感じで表示されていました。
要因:

  • strftimeで作られるオブジェクトはStringクラスであること
  • ブロック付きメソッドを用いていた
  • 時間を表すクラスには、Timeクラス, Dateクラス, DateTimeクラスなど複数存在すること

一つ目の要因

まず、一つ目の要因への策として、一回dateカラムのデータ型をstringに変更して解決はできたのですが(その方法が気になる方はこちら)、後のフォームのことを考えてやはりdatetimeでいくことにしました。
最終的な結論は、viewで表示される2019-08-026 17:52:54 +0900をview側でyyyy/mm/dd(曜日)表示にしてしまうということです。これに気づいたことが大きかったです。

これらのサイトを参考にさせていただきました。
https://www.javadrive.jp/ruby/date_class/index5.html
https://techracho.bpsinc.jp/hachi8833/2016_10_06/25960

二つ目の要因

db/seeds.rb
40.times do |n|
end

の "n" が混乱させてきたのですが、まあこれはdb/seeds.rbの中でRailsチュートリアルと同様にしていれば平気でした。
とりあえず、rails cを多用して実験しまくりました!

三つ目の要因

こちらのサイトなどを拝見したところ、どうも時間を扱うクラスは奥が深くここではすべてを理解することはやめました。
試行錯誤していると、dateのデータ型はdatetimeですが、timeとかでもうまくRailsがやっていてくれている感じはしていました。
まあ、面倒くさいという理由からすべての時間は

to_datetime

でdatetimeに無理やり直しました。

最終的に

最終的には次のようにした結果、うまくいきました。

db/seeds.rb
users = User.order(:created_at).take(2)
40.times do |n|
  event_name = "練習#{n}"
  date = n.days.ago.to_datetime # datetimeに変更
  memo = "楽しみましょう"
  users.each { |user| user.events.create!(event_name: event_name,
                                          date:       date, #seed.rbでstrftimeを使うとstringとなるが、viewで(date)time?に変更されてしまう(2019-08-026 17:52:54 +0900の表示になる)
                                          memo:       memo) }
end
views/events/_event.html.erb
<% d = event.date %> <%# この時点ではdatetimeとして受け取っている %>
<% wd = ["日", "月", "火", "水", "木", "金", "土"] %>
<span class="date">日時:<%= d.strftime("%Y/%m/%d(#{wd[d.wday]})") %></span> <%# datetimeのdをここでstrftimeを用いてstringに変更している(yyyy/mm/dd(曜日)の表示になる) %>

終わりに

今日から本格的にオリジナルの部分を作り始めました。まぁRailsチュートリアルの第13章を参考にしているのですが。とにかく大変で時間がかかるのですが、その大変さを乗り越えるために必要なものとして今回気づいたのは

  • ググる力
  • rails c

が大事だということ。
ググる力はもちろんですが、Railsチュートリアルでなんとなく使っていたrails cがこんなに大事だとは思いませんでした。コンソールでの実験がいかに強力かわかりました。
明日はフォームの作成をしようと思います。個人的にはまだモデルや、モデルのカラムが足りないかなと思っていて、今後はEventにパスワード?やShareLinkモデルやAnswerモデルなんかが必要になるのかと思っていますので、モデルを考える時間がさらに必要だと考えています。

とりあえず今日はこの辺で。

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