20200330のRailsに関する記事は29件です。

Typeformのかっこいい入力フォームをWebhookを使って自作アプリに実装した話

概要

非エンジニアビジネス職(カスタマーサクセス職)の@yuta_maruyamaが、動的でイケてるかっこよい入力フォームを自力で作ろうと思ったけれど難易度が高すぎたので米国産SaaSのTypeformをWebhookで組み込んでフォームを実装した話です。
ちなみにカスタマーサクセスの話は一切なく、大好きなクラフトビールのテイスティングノートアプリを作ろうとしている中での話。

環境

  • Ruby 2.6.2
  • Rails 6.0
  • heroku

作ろうとしているもの

BEER BASH

  • ビールのテイスティングノートアプリ
  • 飲んだビールに関する評価やコメントをnoteとして残す
  • Rails練習用なので見てくれは勘弁
  • 「ノートを残す煩わしさ」がないことをサービスのユニークな価値にしたかったのでそこにはこだわりたい

Typeformとは

  • フォームやサーベイに特化した米国のサービス
  • 無料で使える
  • 有料版だとHidden Fields機能など色々使える
  • 日本語対応も(一応)している

やったこと

Typeform側

フォームの作成

マグマパスタばりのすっ飛ばし方だが、まずはTypeformにアカウント作成し、フォーム作成をする。Googleフォームを作るのとほぼ変わらない。

Webhookの設定

WebhookなのでPOSTリクエストが前提となる。なので勝手にアクションを指定しなくとも勝手にPOSTになる。今回はPOST /notesで設定。保存。
Connect___Tasting_note___Typeform.png

hidden_filedの設定(オプショナル)

Hidden Fieldsは有料オプションなので有料化するつもりなければ飛ばして良い。Hidden Fieldsを用いない場合フォーム内で必要な値を入力してもらうのが良さそう(ユーザーにとってはひと手間だが)

今回の場合は、どこのBrewery(醸造所)のなんていうBeerのnoteを書いているかの値を渡して、
- Typeformに遷移した際にどのビールに関してのnoteかをはっきり示す
- わざわざTypeform側でユーザーがなんのビールについてのnoteか入力させないようにする

を実現したい。なのでbeer_id brewery_id beer_name brewery_name のフィールドを用意しておく

Fullscreen_2020_03_30_21_51.png
Create___New_typeform___Typeform.png

サービス側

Controller

notes#create をいじる。

データのもらい方

Typeformのフォームへの回答をイベントとし、JSON形式でwebhookは送られる。
要素としては大きく
- Event information
- definition
- answers

だが階層がややこしい。コードはこんな感じ。

  def create
    @note = Note.new()
    @note.beer_id = params["form_response"]["hidden"]["beer_id"]

    params["form_response"]["answers"].each do |answer|
      if answer["field"]["ref"] == "rating"
        @note.rating = answer["rating"]
      end

      if answer["field"]["ref"] == "sweetness"
        @note.sweetness = answer["number"]
      end

      if answer["field"]["ref"] == "bitterness"
        @note.bitterness = answer["number"]
      end

      if answer["field"]["ref"] == "sourness"
        @note.sourness = answer["number"]
      end

      if answer["field"]["ref"] == "aroma"
        @note.aroma = answer["number"]
      end

      if answer["field"]["ref"] == "comment"
        @note.comment = answer["text"]
      end

      if answer["field"]["ref"] == "serving_type"
        @note.serving_type = answer["choice"]["label"]
      end
    end

View

beer#showからTypeformにパラメータを渡しながら遷移する。こんな感じで書けばOK。

<%= link_to("Add note", "https://beerbash.typeform.com/to/******?beer_id=#{@beer.id}&beer_name=#{@beer.name}&brewery_name=#{@brewery.name}") %>

最後に

感謝

自分はカスタマーサクセス職としてSQLを業務中に書くことは多いが、Railsに関してはまさに勉強中といった感じ。
そんな中メンターとして色々教えてくれる勤め先のCTO @showwin には本当に感謝が尽きない。

SaaSとの共存

showwin先生には #write-code-or-die というSlackチャンネルでご指導いただいている。そのチャンネルでこんなことを述べたが
Slack___write-code-or-die___LAPRAS.png
非エンジニアの自分でも、外部サービスをきちんと使えれば学習時間を大幅に節約してそれなりのアプリケーションを作れる実感がわいた。ZapierなどのノンコーディングでSaaSを連携できるSaaSのためのSaaSもどんどん進化を遂げており、非エンジニアでもプロトタイプレベルならガンガン自分で作ってみて欲しい

見た目

最後に、こんな感じの見た目になった。

beers#show
好みのビールが見つかるテイスティングノートサービス___BEER_BASH.png

Typeformに遷移。ちゃんとビール名とブルワリー名が出ている。
Tasting_note.png

元々Javascriptで自分でどうにかしようとおもってたがこれは無理
Tasting_note.png

そして、Yorroco Beerが好きな人はぜひ連絡ください!!

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

Typeformのかっこいい入力フォームを自作アプリに実装した話

概要

非エンジニアビジネス職(カスタマーサクセス職)の@yuta_maruyamaが、動的でイケてるかっこよい入力フォームを自力で作ろうと思ったけれど難易度が高すぎたので米国産SaaSのTypeformを組み込んでWebhookで連携しようとした話です。
ちなみにカスタマーサクセスの話は一切なく、大好きなクラフトビールのテイスティングノートアプリを作ろうとしている中での話。

環境

  • Ruby 2.6.2
  • Rails 6.0
  • heroku

作ろうとしているもの

BEER BASH

  • ビールのテイスティングノートアプリ
  • 飲んだビールに関する評価やコメントをnoteとして残す
  • Rails練習用なので見てくれは勘弁
  • 「ノートを残す煩わしさ」がないことをサービスのユニークな価値にしたかったのでそこにはこだわりたい

Typeformとは

  • フォームやサーベイに特化した米国のサービス
  • 無料で使える
  • 有料版だとHidden Fields機能など色々使える
  • 日本語対応も(一応)している

やったこと

Typeform側

フォームの作成

マグマパスタばりのすっ飛ばし方だが、まずはTypeformにアカウント作成し、フォーム作成をする。Googleフォームを作るのとほぼ変わらない。

Webhookの設定

WebhookなのでPOSTリクエストが前提となる。なので勝手にアクションを指定しなくとも勝手にPOSTになる。今回はPOST /notesで設定。保存。
Connect___Tasting_note___Typeform.png

hidden_filedの設定(オプショナル)

Hidden Fieldsは有料オプションなので有料化するつもりなければ飛ばして良い。Hidden Fieldsを用いない場合フォーム内で必要な値を入力してもらうのが良さそう(ユーザーにとってはひと手間だが)

今回の場合は、どこのBrewery(醸造所)のなんていうBeerのnoteを書いているかの値を渡して、

  • Typeformに遷移した際にどのビールに関してのnoteかをはっきり示す
  • わざわざTypeform側でユーザーがなんのビールについてのnoteか入力させないようにする

を実現したい。なのでbeer_id brewery_id beer_name brewery_name のフィールドを用意しておく

Fullscreen_2020_03_30_21_51.png
Create___New_typeform___Typeform.png

サービス側

Controller

notes#create をいじる。

データのもらい方

Typeformのフォームへの回答をイベントとし、JSON形式でwebhookは送られる。
要素としては大きく

  • Event information
  • definition
  • answers

だが階層がややこしい。コードはこんな感じ。

  def create
    @note = Note.new()
    @note.beer_id = params["form_response"]["hidden"]["beer_id"]

    params["form_response"]["answers"].each do |answer|
      if answer["field"]["ref"] == "rating"
        @note.rating = answer["rating"]
      end

      if answer["field"]["ref"] == "sweetness"
        @note.sweetness = answer["number"]
      end

      if answer["field"]["ref"] == "bitterness"
        @note.bitterness = answer["number"]
      end

      if answer["field"]["ref"] == "sourness"
        @note.sourness = answer["number"]
      end

      if answer["field"]["ref"] == "aroma"
        @note.aroma = answer["number"]
      end

      if answer["field"]["ref"] == "comment"
        @note.comment = answer["text"]
      end

      if answer["field"]["ref"] == "serving_type"
        @note.serving_type = answer["choice"]["label"]
      end
    end

View

beer#showからTypeformにパラメータを渡しながら遷移する。こんな感じで書けばOK。

<%= link_to("Add note", "https://beerbash.typeform.com/to/******?beer_id=#{@beer.id}&beer_name=#{@beer.name}&brewery_name=#{@brewery.name}") %>

最後に

感謝

自分はカスタマーサクセス職としてSQLを業務中に書くことは多いが、Railsに関してはまさに勉強中といった感じ。
そんな中メンターとして色々教えてくれる勤め先のCTO @showwin には本当に感謝が尽きない。

SaaSとの共存

showwin先生には #write-code-or-die というSlackチャンネルでご指導いただいている。そのチャンネルでこんなことを述べたが
Slack___write-code-or-die___LAPRAS.png
非エンジニアの自分でも、外部サービスをきちんと使えれば学習時間を大幅に節約してそれなりのアプリケーションを作れる実感がわいた。ZapierなどのノンコーディングでSaaSを連携できるSaaSのためのSaaSもどんどん進化を遂げており、非エンジニアでもプロトタイプレベルならガンガン自分で作ってみて欲しい

見た目

最後に、こんな感じの見た目になった。

beers#show
好みのビールが見つかるテイスティングノートサービス___BEER_BASH.png

Typeformに遷移。ちゃんとビール名とブルワリー名が出ている。
Tasting_note.png

元々Javascriptで自分でどうにかしようとおもってたがこれは無理
Tasting_note.png

そして、Yorroco Beerが好きな人はぜひ連絡ください!!

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

Docker環境でRailsアプリにvue.jsを導入する

目的

railsアプリにvue.jsを導入するために、練習もかねてサンプルのアプリにvueを導入してみたいと思う。

サンプルアプリのディレクトリ作成

任意のワークスペースでディレクトリを作成します。

ターミナル
mkdir sample_app
cd sample_app

Dockerの設定ファイルを作成

Dockerfile
FROM ruby:2.5.3

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && apt-get update && \
    apt-get install -y nodejs --no-install-recommends && rm -rf /var/lib/apt/lists/*

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev

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

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

RUN yarn add node-sass

RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app
docker-compose.yml
version: '3'
services:
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app
    ports:
      - 3000:3000
    depends_on:
      - db
    tty: true
    stdin_open: true
  db:
    image: mysql:5.7
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
volumes:
  db-volume:
Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.3'

あとは、Gemfile.lockの空ファイルを作成。

Railsプロジェクトを作成する

ターミナル
$ docker-compose run web rails new . --force --database=mysql

※rails newの . は現在いるディレクトリにそのままプロジェクトを作成するというもの)だそうです。

database.ymlを編集

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  host: db

hostの部分をdbに変更する。

vue.jsの導入

Gemfile
gem 'webpacker', github: 'rails/webpacker'

その後、

$ docker-compose exec web bash

でwebコンテナに入る。

コンテナ内でコマンドを以下のコマンドを実行

$ rails webpacker:install
$ rails webpacker:install:vue
$ bin/webpack

Railsのviewファイルに以下を記述する

<%=javascript_pack_tag 'hello_vue'%>

こんな画面が出てきたら成功です。

55425ab4b1d58a46d5041eeb75e2128e.png

以上

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

Dockerのコマンドについて詳しくなろう

build

buildコマンドはimageを構築するのみ。コンテナ作成はしない。

$ docker-compose build

up

upコマンドでは、キャッシュがある場合はそれを使って一発でイメージの構築から、コンテナの構築・起動までします。

$ docker-compose up

start

startコマンドは既存のコンテナを起動します。

$ cocker-compose start

run

runコマンドはimageの構築から、コンテナの構築・起動までする。引数でサービスを指定する必要あり。

$ docker-compose run web

exec

コンテナの中に移動できる

$ docker-compose exec web bash

bash ashの違いは、ashの方が軽量なコマンドらしい。

新たなrailsプロジェクトを立ち上げるコマンド

ターミナル
docker-compose run web rails new . --force --database=mysql

rails newの . は現在いるディレクトリにそのままプロジェクトを作成するというもの)だそうです。

以上

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

テスト

これから、Rails tutorialのアウトプットをします。

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

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

masterからサブブランチに切り替えて、

rails s

をしたら、

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

とエラー分が表示され、Javascriptになにか関係が??初めて見るエラー分で、何かしたかと思っていると、、、、

最近、何かとこのエラーに遭遇する人が多いだとか、、、、、

私の場合は、masterからサブブランチに切り替えたときに起こりましたが、これはタイミングが被っただけではないでしょうか。

解決策としては、gemfileに

gem 'therubyracer'
gem 'libv8'

として、bundle installでいけるのかと、思いきやここでエラー分が出たため、node.jsをインストールすることにしました。

一度、上記のgemをインストールできるか試してみてください。

node.jsをhomebrewを使ってインストールする場合は、

 brew install nodejs

でインストールできます。

見事rails sが可能になりました。

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

renderの処理について

本記事を書いた経緯

私はエンジニアになるために、プログラミングスクールにて学習を行なっています。
そこで、renderの処理について学び、備忘録として残したい使い方がありましたので本記事を書くに至りました。

renderの使い方

下記の[A]と[B]は書き方に違いがあれど、どちらも描画されるビューは全く同じです。
しかしながら、ある理由により、[A][B]いずれかの記述の方が好まれます。より良い記述は[A][B]はどちらでしょうか...?

[A]の場合
@users = User.all
@users.each do |user|
  = render 'user', user: user

[B]の場合
@users = User.all
  = render 'user', users: @users

良い記述は[B]となります。
[B]の方が好まれます。
理由は、[B]の方が処理が速いからです。

[A]では、@usersにeachを使用して、user一人一人に対してrenderを実行しています。
この書き方だと、userが100人いると100回、50000人いると50000回、どの部分テンプレートを利用するのか探しにいく処理が実行されるため、ユーザーが多ければ多くなるほどパフォーマンスが低下していきます。

一方、[B]では、renderする際の変数に、@usersを渡しています。
この書き方だと、どの部分テンプレートを利用するのか探しにいく処理は一度しか実行されないため、[A]より高速にビューを描画することができます。

なお、render @users と省略して記述することも可能です。

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

bundle installのエラー解決法(can't find gem bundler (>= 0.a) with executable bundler)

エラー内容と状況

エラー内容はタイトルの通り。bundle installしたとき、can't find gem bundler (>= 0.a) with executable bundler (Gem::GemNotFoundException)と怒られてしまった。
そもそもこの時はgithubのリモートからpullして、rails sをした時に、bundle installしてくださ〜いってエラーから始まっています。チーム開発でよくある事象かと思い、自分も何回か直面してその都度調べていたので、そろそろ自分でまとめようと思います!

開発環境

  • ruby 2.5.1p57
  • Rails 5.2.4.1

bundlerとは

そもそもbundlerとは何だったのかを復習しましょう!
Railsアプリケーションにおいては非常に複雑なgemの管理をする必要があります。これらのgemを管理するのがbundlerというgemになります。
管理するものが無いのでbundle installできないってことだったのですね。

ターミナルでbundlerをインストールするコマンドを入力しましょう。

gem install bundler

解決するエラー内容の場合、上記コマンドで解決すると思います。(同様のエラーの記事を読むと)しかし今回は上手くbundlerをインストールできませんでした。

原因

今回の場合、gemfile.lockにbundlerのバージョンが記載されてえいるため、バージョンを指定しないとインストールができないことによるものでした。

gemfile.lock
BUNDLED WITH
   2.0.2
gem install bundler -v2.0.2

上記を実装することでエラーを解決することができます。

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

DBから取得したデータの中身を取得する方法 Ruby on Rails

MySQLからデータを取得してきた

whereメソッドを使って、特定条件下で検索に該当するクエリを発行させると、条件に当てはまったレコード全てを引っ張ってくる。

log_in.rb
yesterday_time = Time.now.yesterday
log_in_collection = LogIn.all #LogInというモデルを作成してあり、そこからデータを全て引っこ抜いている
log_in_list = log_in_collection.where("loged_in_at >= ?", yesterday_time)

そうすると、log_in_listをpメソッドで出力すると、

#<ActiveRecord::Relation [#<LogIn id: 456,  uid: "hogehoge", log_in_at: "2020-03-25 05:49:43", created_at: "2020-03-25 05:50:47", updated_at: "2020-03-25 05:50:47">]>

こんな感じのデータが取れる。パッと見、ハッシュに見える物が取ってこれているのが分かる。今回必要なのはこのuidにおけるhogehogeだけを引っ張ってくることがゴールです。

以下の自分の考え方に間違いがあったら、指摘をお願いします。

最初に犯したミス

欲しいデータを手に入れたければ、ハッシュのキーになっているものでメソッドチェーンすればいいってことだったので、安直に前述したコードの変数であるlog_in_listを使って、

hogehoge.rb
p log_in_list.uid

と書いて、hogehogeが取れているかを確認してみました。すると、ログはおろか、localhostでこの処理部分を走らせてみると、画面に真っ赤な文字でundefined uidと表示されてしまう。何でやねん。

ハッシュみたいなものからオブジェクトを取り出すような書き方はできん

ハッシュみたいなやつと書いているのは、ActiveRecordから取ってきているデータのことをなんて呼んでいいかわからないからですが、こう考えてみると、log_in_listを最初にpした時、これはデータの型がハッシュみたいなやつであって、オブジェクトになっていない。これが本当にハッシュで、ハッシュの値を取り出すには、

example.rb
log_in_list["uid"]

とかにせねばならない。今回のデータはActiveRecordから引っ張ってきているものなので、これでのアクセスもできない・・・ハズ。

また、whereは条件にあった全てのレコードを引っ張ってくるので、条件にあった全てのuidを抜き取る作業を必要とする。それじゃどうするか・・・一旦、このハッシュっぽい奴のデータをオブジェクトにしてやればいい。

hogehoge.rb
log_in_list.each do |data|
  log_in_users = data.uid
  p log_in_users
end

eachを使って、log_in_listの中身をdata変数へと入れ込むと、オブジェクト化してくれるので、オブジェクトへのアクセスする書き方が可能になる。これでhogehogeだけを引っ張ってこれる。

補足

後で知ったことですが、ハッシュ用のループ処理で使えるeachもある。この記事によると、やはりハッシュにはハッシュオブジェクトがちゃんと存在してそのオブジェクトへのアクセスの仕方も違うようだ・・・

ハッシュに対する繰り返し

考察

重要なのは2つあるかなと思いました。

書いているコードに内包されているデータの型を意識的に脳内で可視化すること。脳内で可視化って意味不明かもしれませんが、言わんとしていることは分かると思うんですよ。「今持ってきているデータは〇〇型で、まだ日オブジェクトだな」みたいな意識を持つイメージでしょうか。

また、それをオブジェクト化した時のアクセス方法を知っていること、もしくはそこから検索をかけて調べる足掛かりにする、ということでしょうか。

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

ActiveModelSerialize で has_many の N+1 SQLクエリを防止するために eager_load する例 ( #Rails )

Controller

class UsersController < ActiveController
  def index
    # render json: User.eager_load(:includes).all
    render json: User.eager_load(:books).all
  end
end

Serializer

class UserSerializer < ActiveModel::Serializer
  attributes :id,
             :name

  has_many :books
end

NOTE

途中 eager_load / includes が効かないような気がして gem も試したのだが、効かないというのは気のせいだった。

ams_lazy_relationships は Star数は少ないが includes のちょっとした問題点を解決してくれそうなgem?
httpリクエスト単位でのキャッシュや、もっと長いキャッシュを実現してくれそうな気もする。

Bajena/ams_lazy_relationships: ActiveModel Serializers addon for eliminating N+1 queries problem from the serializers.

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3056

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

GitHubから、gemの脆弱性の通知がきたので、バージョンアップをする

はじめに

rubyzipというgemで、割と危険度が高い脆弱性があるという主旨の通知メールがGitHubから届いたため、いちいち面倒ではあるが、バージョンアップを行っておく。

手順

Gemfileの中身にrubyzipがないか探すが、どうも、rubyzipというgemは使っていないようだったため、Gemfile.lockの中身を検索する。すると、2ヶ所で検索される。どうも、他のgemの中から、依存関係として利用されている事のようだ。

Gemfile.lock
rubyzip (1.2.3)
selenium-webdriver (3.142.4)
      childprocess (>= 0.5, < 3.0)
      rubyzip (~> 1.2, >= 1.2.2)

先に、Ubuntuにインストールされているrubyzipのバージョンを確認しておく。

gem list | grep rubyzip
rubyzip (1.3.0, 1.2.4, 1.2.3)

rubyzipのバージョンを最新にする。

gem update rubyzip

2.0.0が追加されて、rubyzipのバージョンが、確かに上がった事を確認する。

gem list | grep rubyzip
rubyzip (2.0.0, 1.3.0, 1.2.4, 1.2.3)

Gemfile.lockを最新に更新する

bundel update

上記だと、全てのgemがバージョンアップされるため、特定のgemのみバージョンアップさせたい場合は、このようにしてもOK。

bundle update rubyzip

Gemfile.lockの中身を見ると、確かに、rubyzipのバージョンが上がっています。

Gemfile.lock
rubyzip (2.0.0)

selenium-webdriver (3.142.6)
      childprocess (>= 0.5, < 4.0)
      rubyzip (>= 1.2.2)

GitHubに最新を反映させます。

git add .
git commit -m 'rubyzipの脆弱性のバージョンアップ'
git push origin master
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Rails とかで docker 環境なのに #VSCode で ruby-rubocop 拡張を有効にするにはどうすれば良いのか? ( #Rails #Ruby )

ruby-rubocop

image

エラー

なんかいろいろと言われますけれど。

image
image

解決法

local に同じバージョンの ruby + rubocop 関連で必要なgemをインストーするれば動くっぽい

gem install rubocop
gem install rubocop-performance
gem install rubocop-rails

以上。

VsCodeがdockerまで見に行けないですもんね。いや、やり方はあるのかもしれないけど。やれたにしても激遅でしょ?たぶん。

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3055

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

rails6のwebpacker.ymlインストールエラー

エラー内容

実行コマンド
dockder-compose up
:エラー
Webpacker configuration file not found /app_name/config/webpacker.yml. 
Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /app_name/config/webpacker.yml (RuntimeError)

意味

webpacker.ymlに設定が見つからない。

解決

単純にコンテナ内でwebpackerをインストールをしたら解決したました。

実行コマンド
docker-compose run web bundle exec rails webpacker:install
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

#Rails #rspec で SQLクエリ発行を標準出力する

ActiveRecord::Base.logger = Logger.new(STDOUT) をどこかに書くだけでok

よく使う場合は rails_helper に定義するなり、 before after できれいに処理するなりするする

require 'rails_helper'

RSpec.describe do
  before do
    ActiveRecord::Base.logger = Logger.new(STDOUT)
  end

  it do
    ...
  end
end

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3054

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

初めてのBitbucket

rails チュートリアルを進めるにあたって、bitbucketを一番初めに使用するときにわからないことがあって苦しんだためメモ

・cloud9(aws)環境で実施
・アカウント作成は省略

公開鍵の作成

console
cat ~/.ssh/id_rsa.pub

上記のコマンド入力で公開鍵を所持しているか確認できます。所持していない場合にはNo such file or directoryと表示されます。
鍵を所持していない場合は

console
cd ~/.ssh #sshフォルダに移動
ssh-keygen -t rsa -C saber@example.com  # 自分のメールアドレス入力

Entキー押すと色々と出てくるが特にいじる必要ないのでそのままEntキー何回か押して鍵を作成。鍵を作成した後に先ほどの

console
cat ~/.ssh/id_rsa.pub

を実行して鍵を表示させます。

公開鍵の追加

bitbucketにログイン後、
ユーザーアイコン
  ↓
Bitbucket setting
  ↓
セキュリティー
  ↓
SSH鍵
  ↓
鍵追加
  ↓
さきほど表示した鍵をコピペ
  ↓
作成
これで完了です。

bitbucketへリポジトリ作成

+アイコンを押し、空のリポジトリを作成します。リポジトリ名はなんでも大丈夫せす(わかりやすくするなら自身のアプリケーション名が良いかと)。
bitbucketにリポジトリを作成するとバケツに何かを入れましょうというページに移動しgit remote add origin git@bitbucket.org:ユーザー名/先ほど作成したリポジトリ名.gitgit push -u origin masterいうコマンドが表示されます。このコードそのまま入力してもいいのですが、まだ自身の環境にリポジトリを作成していない場合は

console
git init (自身の環境の新しいリポジトリの初期化)

ちなみにawsのcloud9の場合はgit導入済みのためこのコマンドが最初から使用できます。

console
git add -A
git commit -m "メッセージ"

上記のコマンド実行し、自身のgitにリポジトリを作成したあとは先ほどのgit remote add origin git@bitbucket.org:ユーザー名/作成したリポジトリ名.gitgit push -u origin masterいうコマンドを実行します。

console
git remote add origin git@bitbucket.org:ユーザー名/先ほど作成したリポジトリ名.git
git push -u origin master

これでBitbucketに内容が反映されます。

あとがき

自分なりにわかりやすいよう書いてみましたがわかりにくかったらすみません。
参考になれば幸いです。

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

#Rails ActiveModelSerializer で has_many に別の名前をつける例 ( Model class にはエイリアスを作らない )

  • User#books というメソッドがあるが items という名前でシリアライズしたい
  • User に alias を作れば可能だが model を汚したくない
  • Serializer に items メソッドを作ってエイリアスする
class User < ApplicationRecord
  has_many :books
end

class UserSerializer < ActiveModel::Serializer
  attributes :id,
             :items

  has_many :items

  def items
    object.books
  end
end
  • ActiveModel::Serializer 自体のオプション等でも出来るかどうかは不明

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3053

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

Railsのコールバッククラス(callback class)について調べたこと

狙い

本文は、前人の知見(@joker1007記事@k5trismegistus記事)踏まえて、コールバッククラスのメリットとデメリットを述べて、さらに実践において、どのような状況で、それを使ったほうが良いのかについて論じてみる。

利弊

メリット

  • モデルから、コールバックの処理Railsガイドでは、「Active Recordオブジェクトが作成/保存/更新/削除/検証/データベースからの読み込み、などのイベント発生時に常に実行されるコード」と定義)といった責務を切り離れる。
    • 異なるモデルでのコールバック処理の中から、汎用性の高い部分を抽出さして、カプセル化することで、メンテナンスしやすくなり、テストもしやすくなる。

デメリット

  • いくつのモデルに使われた共通のコールバッククラスでの処理を変更したい時に、特定のモデルに対してその変更がいい、特定のモデルに対してその変更が悪いのようなケースが生じる可能性がある。
    • 各モデルにコードバックを書くことと比べて、他のモデルにも影響が出るため、変更の際の確認・検証のコストが高くなる。
    • 「他のモデルにも影響が出る」を見落としてしまった状況とつなぎやすくなり、ビジネスロジックの非意図的な変更やサービスの障害が起きる恐れがある。

適用条件

  1. コールバックの処理のコードの量が異常に多くて、かつ処理の複雑度が高くて、コードをメンテナンスしにくい場合
    • メンテナンスをしやすくなることを目的として、コールバックの処理を切り離れる
    • 切り離れたコールバックの処理をカプセル化する時に、他の人がそれを非意図的に使わないように、「明確な名前と境界」を付けることは重要である。
  2. 複数のモデルの中にある特に注力したい大事なコールバックの処理があり、それをドメイン知識として表現したい場合
    • 上記の1と同じく、「明確な名前と境界」を付けることは重要である。(これはドメイン知識として成立する前提条件であるので、特に大事)
    • 将来的に仕様の変更によって、その処理を修正する必要な時に、既存の「ドメイン知識」を修正したら十分なので、あるいは新たなドメイン知識が生まれることで、それらを再整理しないとけいないのかを考えることは重要である。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6 のちょい足しな新機能を試す 126(upsert_all bug fix編)

はじめに

Rails 6 に追加された新機能を試す第126段。 今回は、upsert_all bug fix 編です。
Rails 6.0.0 では、 query のキャッシュが有効になっている状態で、 upsert_all を実行した後、キャッシュがクリアされないというバグがありました。

Rails 6.0.1 以降では修正されています。

Ruby 2.6.5, Rails 6.0.2.2, Rails 6.0.1, Rails 6.0.0 で確認しました。

$ rails --version
Rails 6.0.2.2

今回は、 スクリプトを作成して確認していきます。

Rails プロジェクトを作る

Rails プロジェクトを新たに作成します。

$ rails new rails_sandbox
$ cd rails_sandbox

User モデルを作成する

User モデルを作成します。

$ bin/rails g model User name

スクリプトを作成する

スクリプトを作成します。スクリプトは以下の処理を実行します。

  1. Andy というname を持つ User を1つ登録する。
  2. キャッシュを有効にする。
  3. 登録したUserを User.first で検索して、name を出力する。
  4. User.upsert_all を実行して、 Andy から Bob に name を更新する。
  5. User.first を使って name を出力する。
scripts/cache_clear.rb
User.delete_all
ActiveRecord::Base.connection.enable_query_cache!

User.create(name: 'Andy')
user = User.first
p user.name

User.upsert_all(
  [
    {
      id: user.id,
      name: 'Bob',
      created_at: user.created_at,
      updated_at: Time.now
    }
  ]
)

user = User.first
p user.name

Rails 6.0.0 では

Rails 6.0.0 では、 キャッシュがクリアされないため、名前が変わりません。、

$ bin/rails -v
Rails 6.0.0
$ bin/rails runner scripts/cache_clear.rb
Running via Spring preloader in process 369
"Andy"
"Andy"

Rails 6.0.1 以降では

キャッシュがクリアされるため、名前が期待通りに変化します。

$ bin/rails -v
Rails 6.0.1
$ bin/rails runner scripts/cache_clear.rb
Running via Spring preloader in process 447
"Andy"
"Bob"

試したソース

https://github.com/suketa/rails_sandbox/tree/try126_clear_cache_in_upsert

参考情報

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

rails newで良く使うオプション

はじめに

rails newで(個人的に)よく使うオプションについてのまとめです。

よく使うオプション

rails newのタイミングで、一緒に、bundle installを実行しない場合、-Bを付けます。
Gemfileを触る事が分かっていて、マシンのスペック上、同じ事を2回行わずに、無駄な待ち時間を短縮させたい時に有効です。

rails new project_name -B
rails new project_name --skip-bundle  # こっちでもOK

データベースにデフォルトのSqLite3を最初から使わない場合は、使用するデータベースを指定します。herokuにデプロイする予定であれば、最初から、PostgreSQLを指定しておいた方が無難でしょう。

rails new project_name -d postgresql

テストにはRSpecを利用して、デフォルトで用意されているminitestは、はなから利用しない場合は、minitestの設定をスキップする事ができます。
後から、minitest関連のディレクトリをrmしてもOK。

rails new project_name --skip-test

おまけ

プロジェクト名を指定せずに、.を指定すると、プロジェクトディレクトリを作成する事なく、rails関連のファイルが作成されます。整理がつかなくなるため、この使い方もあまりお薦めではないでしょう。

rails new .

プロジェクト名には、単数でも複数でもこだわる必要はありません。

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

【Rails】i18nを使って日本語対応する(追加したカラム名も変更したい)

Railsでアプリケーションを作成していて、i18nを使った日本語化のメモです。

バリデーション設定した時のエラーメッセージ表示で追加したカラム名の日本語化がなかなかうまくいかず。
あれこれ試して解消したので参考になればと思います。

状況


deviseを用いてユーザー登録機能を実装する際に、表現を日本語対応に変更する。
gemインストールもしたのに、ja.ymlも記載したし、configも書き換えたのに、一部の文言が日本語にならない。

インストールしたgemはこの2つ。

gem 'devise-i18n'
gem 'devise-i18n-views'

bundle install 忘れずに。

実施したこと(1) fileの作成


基本的には公式に沿ってQiitaなど参考にしながら記入やgenerationを実施しました。

読み込むための日本語yamlファイルdevise.yaml.jaを作成します。

rails g devise:views:locale ja

config/application.rbに追記します。

config.i18n.default_locale = :ja
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]

1つ目は、デフォルトでja(日本語)を読むように変更。
2つ目は、load_path〜の記述で、複数のロケールファイルを読み込むため(別途設定必要です)。

configを修正したので、rails s(再起動)して挙動を確認。これで基本的な日本語化は反映されているはずです。

実施したこと(2)追加カラム対応用の編集

追加したアプリ独自のカラム名を日本語対応にする(住所関係とか誕生年、誕生月を分けて登録したい等)。
config/locales にja.ymlファイルを作成します。

touch config/locales/ja.yml

作成したja.ymlファイルは自分で編集する必要があります。
まずはgithubからja.ymlの基本項目をコピペ。

https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml

続いて、自分のアプリに合わせた編集を追加します。
/locales/ja.yml のactiverecord::以下にモデル名とカラム名を記載。
ちなみに参考まで。

ja:
  activerecord:
    models:
      user: ユーザー
      address: アドレス
    attributes:
      user:
        first_name: 名前(名)
        last_name: 名前(姓)
        first_name_kana: ふりがな(名)
        last_name_kana: ふりがな(姓)
        phone_number: 電話番号
        year_birth_at: 誕生年
        month_birth_at: 誕生月
        day_birth_at: 誕生日
      address:
        zip: 郵便番号
        pref: 都道府県
        city: 市区町村
        block: 丁目、番地
        building: ビル、マンション名
        dst_first_name: 宛先(名)
        dst_last_name: 宛先(氏)
        dst_first_name_kana: ふりがな 宛先(名)
        dst_last_name_kana: ふりがな 宛先(氏)
    errors:
      messages:
        record_invalid: 'バリデーションに失敗しました: %{errors}'
        restrict_dependent_destroy:
          has_one: "%{record}が存在しているので削除できません"
          has_many: "%{record}が存在しているので削除できません"
・・・・
ここから先の記述内容はgithub参考にしてください。

ja.ymlはインデント下げで、カラム名とモデル名を認識するので
見出しのactiverecordsから
models と attributes
モデル名(user:とadress:)
カラム名(first_name等々) で1つづつ下げて改行して記載するようにしましょう。

念のため、デフォルトの言語設定が :ja になっていることをrails r で確認しておきます。

rails r "puts I18n.default_locale"

ja  
と出ればOK。

実施したこと(3) 実装内容確認

rails c を使って記述した内容が表示されるかを確認。
まずrails s(再起動)、もしくはreload!を実行して rails c でconsoleを立ち上げます。

確認コマンド例
[1] pry(main)> User.model_name.human #モデル名の日本語化を確認
=> "ユーザー"
[2] pry(main)> User.human_attribute_name :last_name_kana #カラム名の日本語化を確認
=> "ふりがな(姓)"
[3] pry(main)> Address.model_name.human
=> "アドレス"
[4] pry(main)> Address.human_attribute_name :pref
=> "都道府県"

無事反映されていれば成功です。
これ以外にもバリデーションメッセージの編集や追加などもできます。
興味ある方は参考URLを読んでみてください。

参考

https://blog.cloud-acct.com/posts/spa-rails-i18n-setting/
https://qiita.com/yutackall/items/0ff97132f31e5bacbf00
https://blog.tanebox.com/archives/590/

最後までお読みいただきありがとうございました。

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

has_secure_passwordについて

はじめに

パスワードを実装してみたのでメモ
userモデルにパスワードを実装していきます

1.has_secure_password

userモデルに

user.rb
class User < ApplicationRecord
has_secure_password
end

と追加することで
(1).セキュアにハッシュ化したパスワードを、データベース内のpassword_digestという属性に保存できるようになる。(条件あり
(2).2つのペアの仮想的な属性 (passwordpassword_confirmation) が使えるようになる。また、存在性と値が一致するかどうかのバリデーションも追加される。
(3).authenticateメソッドが使えるようになる (引数の文字列がパスワードと一致するとUserオブジェクトを、間違っているとfalseを返すメソッド) 。
この3つの機能が使えるようになります。順番に解説していきます。

(1)

ここでいうセキュアとは安全という意味です。設定したパスワードを暗号化(ハッシュ化)させて、password_dijestというカラムに保存できるようにします。すなわち、Userモデルにpassword_dijestカラムを追加する必要があります(先ほどの条件とはこのこと)。

console
rails generate migration add_password_digest_to_users password_digest:string

rails db:migrate

また、パスワードを暗号化するためのgemとして、bcrypt(最新ので大丈夫です)というgemをgemfailに追加してbundle installする必要があります。

(2)

passwordpassword_confirmationのセットというのはパスワードとパスワード(確認用)ということです。ちなみに、has_secure_passwordをUserモデルに追加したことで自動的にこの二つのバリデーションが追加されるようになっていますが、これは更新時には適用されないので

user.rb
validates :password, presence: true

と追加しておきましょう。パスワードの長さを制限したいときは

user.rb
validates :password, presence: true, length: {minimum:5}

とすれば5文字以上のパスワードに制限することができます。

(3)

authenticateメソッドではその説明の通り、引数の文字列がパスワードと一致しているか確認してくれます。

console
User.create(name: "saber",email: "saber@seihai.com",password: "shirou",password_confirmation: "shirou")
user = User.find_by(name:"saber")
user.authenticate("kotomine") => false
user.authenticate("kiritugu") => false
user.authenticate("shirou") => true

といった感じでそのユーザーのパスワードの正誤を確認してくれます。
autuenticateでは引数のパスワードをそのままデータベースの値と参照するわけではなく、一度ハッシュ化(暗号化)してからその値をデータベースにある値と参照してくれます。

最後に

has_secure_passwordを自分なりにかみくだいてみました。参考になれば幸いです。

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

#Rails + ActiveModelSerializers で API の JSON を自由に組み立てたいけど Controller の render で扱いづらいので、直接 each serializer で組み立てる例

やりたいこと

たとえばこんなふうに

  • JSON 全体はオブジェクト
  • オブジェクトの特定のキーが配列を持つ
  • キーの名前は任意につけたい

というような場合があるのだけど

{
  "all_users" : [
    {
      "id": 1,
      "name": "Alice"
    },
    {
      "id": 2,
      "name": "Bob"
    }
  ]
}

やってみた

  • 良いやり方はどうかは分からない
  • ActiveModelSerializers + Rails Controller の組み合わせは、自由なJSONを組み立てるのには、それほど向いていないような気もしている
  • render メソッドで勝手に model インスタンスを Serialize してくれる挙動は捨てて、ある程度、自分の実装で Serialize していく必要があるのかもしれない。
class UserController < ApplicationController
  def index
    render json: { all_users: index_json }
  end

  def index_json
    ActiveModel::SerializableResource.new(
      User.all,
      each_serializer: UserSerializer
    )
  end
end
class UserSerializer < ActiveModel::Serializer
  attributes :id,
             :name
end

Adapter を指定する

  • adapter: :json を指定すると JSON を Serializer の名前でネストして囲ってくれるみたいだ ( この場合は "users": [])
  • "all_users": [] などという好きなキー名にするには Serializer 自体を AllUserSerializer とかいう名前にする必要がありそう?
  • なんか挙動が暗黙的すぎて、いままで触っていたコードではよく分かっていなかった
    render json: User.all, each_serializer: UserSerializer, adapter: :json

active_model_serializers/serializers.md at v0.10.6 · rails-api/active_model_serializers

ルートのキーを指定する

root: "all_users" などと書けば 好きなキーも指定できるみたいだ。

    render json: User.all, root: "all_users", each_serializer: UserSerializer, adapter: :json

active_model_serializers/rendering.md at v0.10.6 · rails-api/active_model_serializers

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3052

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

dockerでカラムの変更ができないエラー

docker-composeで自作アプリのテーブルをいじっていたらこんなエラーに遭遇しました。

$ docker-compose run --rm app rails g migration rename_star_column_to_topics
Starting sakelog_db_1 ... done
Error response from daemon: OCI runtime create failed: container_linux.go:346: starting container process caused "exec: \"rails\": executable file not found in $PATH": unknown

再起動してみたり、appをdbに書き換えてみたり、色々試しましたが解決できず。

でも解決法は意外と単純でした。

$ docker-compose run --rm app bundle exec rails g migration rename_star_column_to_topics
Starting sakelog_db_1 ... done
      invoke  active_record
      create    db/migrate/20200330013557_rename_star_column_to_topics.rb

railsの前に bundle execを付け足したらよかったんですね。

今までよくわからずに放置して使ってたbundle exec。
今回のエラーを経て改めて検索し直したら、
bundle execをつけずに実行すると、グローバルにインストールされているgemが動くのに対し、
bundle execをつけて実行するとプロジェクト内にあるgemが動くんだそうで。

なるほど、dockerのことはまだよくわかって無いですが、なんとな〜く理解できてきた気がするぞ。

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

shoulda-matchersが便利すぎる

はじめに

RSpecを書くときに、shoulda-matchersというGemを使うと非常に便利でした。

shoulda-matchersとは

Shoulda Matchers provides RSpec- and Minitest-compatible one-liners to test common Rails functionality that, if written by hand, would be much longer, more complex, and error-prone.

Shoulda Matchersは、手書きで書くと長くて、複雑で、エラーが起きやすいRailsのテストをワンライナーにします。(意訳)
ワンライナーって1行ってことでいいのでしょうか...

使用方法

このようなuserモデルに対し、

user.rb
class User < ApplicationRecord
  validates :name, presence: true
  has_many :topics
end

shoulda-matchersを使うとこのようなRSpecを書くことができます!

user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  it { is_expected.to validate_presence_of(:name) }
  it { is_expected.to have_many(:topics) }
end

バリデーションやアソシエーションのテストを一行で書けるのは便利すぎますね。
普通のRSpecの書き方で書いて、テストケースに抜けや漏れが出てしまうなんてことを防げます。

上記の例ではpresencehas_manyを取り上げましたが、他にも使えそうな書き方がたくさんあるので追記していきたいと思います。

参考:Shoulda-MatchersのREADME

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

USERにいろいろと機能をつけてく。〜Railsチュートリアル7章〜

いよいよ7章目に突入していきます。
大体10日前くらいからRailsチュートリアルはじめてそろそろ折り返し地点になるのかな。勉強時間はだいたいですけど60時間くらい。この調子でがんばりますよー!

さて、今回はユーザーのページ作ったりプロフィール写真載せたりしてきます。

ユーザーを表示する

初めて動的なページを入れていきます。ビューの中にApplicationのデータベースから情報を取り出して各プロフィールの情報をカスタマイズしていきます。Applicationに動的なページを追加する準備としてデバック情報を追加します。
デバック情報ではコントローラはなにを使っているのか?アクションはなに使ってるのかといった動的ページを動かす際に必要な情報を確認することができます。

デバック情報入れるには

 <%= debug(params) if Rails.env.development? %>

これを大元のApplication.htmlのフッターの下辺りに入れる。
Rails.env.developmentとは開発環境のこと。ここだけ表示される用にするよう指定している。

railsにはテスト環境 (test)、開発環境 (development)、そして本番環境 (production) の3つの環境がデフォルトで装備されています。
rails consoleは開発環境 (development)です。

Applicationを本番環境で実行する場合、本番のデータベースを利用できるよう実行する必要がある。

$ rails server --environment production
そのため、rails db:migrateを本番環境で実行して本番データベースを作成します。

 $ rails db:migrate RAILS_ENV=production
console、server、migrateの3つのコマンドでは、デフォルト以外の環境を指定する方法がそれぞれ異なっている

id=1のユーザーにアクセスするためのページのURIは/users/1となるが、現時点ではこのURLを使ってもエラーになります。
/users/1 のURLを有効にするために、routesファイルに以下を追加する。

Resources:users

これを入力すると、ユーザー情報を表示するURLを追加するだけでなく、ユーザーのURLを生成するための多数の名前付きルートと共に、RESTfulなUsersリソースで必要となるすべてのアクションが利用できるようになる。

| HTTPリクエスト | URL | アクション | 名前付きルート |   用途  |
---------------------------------------------------
|   GET    | /users | index |  users_path | すべてのユーザーを一覧するページ |
|   GET    |/users/1|  show |  user_path(user) | 特定のユーザーを表示するページ |
|   GET   |/users/new|  new |  new_user_path | ユーザーを新規作成するページ (ユーザー登録) |
|   POST   | /users  |create|  users_path | ユーザーを作成するアクション |
|   GET | /users/1/edit|edit|  edit_user_path(user) | id=1のユーザーを編集するページ |
|   PATCH  | /users/1|update|  user_path(user) | ユーザーを更新するアクション |
|   DELETE | /users/1|destroy| user_path(user) | ユーザーを削除するアクション |

この時点でコントローラとroutesは指定できたものの、まだプロフィール画面(ビュー)ができていないためこれを作成していく。
まずapp/views/users/show.html.erbを手動で作成。
ビューへは

<%= @user.name %>, <%= @user.email %>

を入力。ユーザー名、Emailアドレスを表示する。
コントローラへは

 def show
    @user = User.find(params[:id])
  end

を追加。ユーザーのid読み出しにはparamsを使う。Usersコントローラにリクエストが正常に送信されると、params[:id]の部分はユーザーidの1に置き換わります。(技術的な補足: params[:id]は文字列型の "1" ですが、findメソッドでは自動的に整数型に変換されます)。このIDを変数@userへ代入し、上のビューへ表示するようにする処理を作成した。

debuggerメソッドを使用する

byebug gemによるdebuggerメソッドを使用すればもっと直接的に確認ができる。

  def show
    @user = User.find(params[:id])
    debugger
  end

メソッドを差し込んだらブラウザから /users/1 へアクセスしRailsサーバーを立ち上げてターミナルを確認する。dyebugプロンプトが表示される。

(byebug) @user.name
"Example User"
(byebug) @user.email
"example@railstutorial.org"
(byebug) params[:id]
"1"

このプロンプトではRailsコンソールのようにコマンドを呼び出すことができてApplicationのdebuggerが呼び出された瞬間の状態を確認することができる。

debuggerを終了させる

ControlーDを押すとプロンプトから抜け出せる。デバッグが終わったらshowアクション内のdebuggerの行を削除する。

ユーザー登録フォームを作成する

form_forを使用

ユーザー登録ページにはフォーム(入力する空欄のこと)が必要となる。
Railsではform_forヘルパーメソッドを使用する。
まずform_forの引数で必要となるUserオブジェクトを作成することになります。必要となる@user変数の定義は

class UsersController < ApplicationController

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end
end

と入力。
ビューは。。

<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@user) do |f| %>
      <%= f.label :name %>
      <%= f.text_field :name %>

      <%= f.label :email %>
      <%= f.email_field :email %>

      <%= f.label :password %>
      <%= f.password_field :password %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

と入力する。 f.label :name のfはオブジェクト。Labelは属性の設定。テキストフィールドは記載情報のこと。

正しいフォーム

/usersへのPOSTリクエスト(フォームからの入力情報)はcreateアクションに送られます。ここで、createアクションでフォーム送信を受け取り、User.newを使って新しいユーザーオブジェクトを作成し、ユーザーを保存 (または保存に失敗) し、再度の送信用のユーザー登録ページを表示するという方法で機能を実装する。

コントローラにはこんな入力となる。

  def create
    @user = User.new(params[:user])    # 実装は終わっていないことに注意!
    if @user.save
      # 保存の成功をここで扱う。
    else
      render 'new' #失敗したらnewへ戻る。
    end
  end

これは完璧な実装ではない。paramsハッシュ全体を初期化するという行為はセキュリティ上極めて危険だからです。
今のままだと、ユーザーが送信したデータをまるごとUser.newへ渡していることになります。(名前・アドレス・パスワード・再確認用パスワード)
これに追加で別の属性を一部に紛れ込ませて渡せてしまうという危険があります。(管理者権限等も渡せる危険があり非常に危険)

Strong Parameters

Rails 4.0では、先述している危険を防止するためコントローラ層でStrong Parametersというテクニックを使うことが推奨されています。

private

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

上記はparams[:user]の代わりとして使われる。これを追加することで許可された属性のみが含まれたparamsを使用できるように限定する。
このuser_paramsメソッドはUsersコントローラの内部でのみ実行され、Web経由で外部ユーザーにさらされる必要はない.
Rubyのprivateキーワードを使って外部から使えないようにしている。

エラーメッセージ

ユーザー登録に失敗した場合の最後の手順として、問題が生じたためにユーザー登録が行われなかったということをユーザーにわかりやすく伝えるエラーメッセージを追加する。
保存に失敗すると、@userオブジェクトの関連付けされたエラーメッセージの一覧が生成される。これをビューへ表示したい。このメッセージをブラウザで表示するには、ユーザーのnewページでエラーメッセージのパーシャル (partial) を出力します。このとき、form-controlというCSSクラスも一緒に追加することで、Bootstrapがうまく取り扱ってくれるようになります。

<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@user) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

'shared/error_messages'というパーシャルをrender (描画) している
複数のビューで使われるパーシャルは専用のディレクトリ「shared」によく置かれます
よって

$ mkdir app/views/shared

にて新しくディレクトリを作成。ここにファイルも作成し、下記を入力。

<% if @user.errors.any? %> →#もし変数ユーザーにエラーが一つでもあったら
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(@user.errors.count, "error") %>.
    </div>
    <ul>
    <% @user.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

メソッドがcountとany?の2つ使用されている。countは上記の内容だとエラーの数を返してくれる。any?はempty?と逆の動作で要素が一つでもある場合はtrueを返す。
pluralizeは英語専用のテキストヘルパー単数形と複数形をcountの数に応じて変換し出力してくれる。

失敗時のテスト

railsではフォーム用のテストを自動的に書くことができる。

$ rails generate integration_test users_signup
      invoke  test_unit
      create    test/integration/users_signup_test.rb

ここではユーザー登録ボタンを押したときに (ユーザー情報が無効であるために) ユーザーが作成されないことを確認します。

test/integration/users_signup_test.rb
require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
    assert_template 'users/new'
  end
end

ユーザー登録成功

ここまでではまだ完成ではなく、デフォルトのアクションに対応するビューを表示しようとするもcreateアクションに対応するビューのテンプレートがないためエラーが表示されてしまう。

createアクションに対応するテンプレートを作成することもできますが、Railsの一般的な慣習に倣って、ユーザー登録に成功した場合はページを描画せずに別のページにリダイレクト (Redirect) するよう設定する。

具体的には、新しく作成されたユーザーのプロフィールページにリダイレクトする。

class UsersController < ApplicationController
  .
  .
  .
  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user →ユーザーURLへ飛ばすを意味する
    else
      render 'new'
    end
  end

  private

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

さらにここに、登録完了後に表示されるページにメッセージを表示し (この場合は新規ユーザーへのウェルカムメッセージ)、2度目以降には表示しないようにするFrashという変数を使用する。

def create
    @user = User.new(user_params)
    if @user.save
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new'
    end
   end

このとき、:successキーはシンボルでしたが、テンプレート内に反映させる際に埋め込みRubyが自動的に"success"という文字列に変換している点に注意してください。この性質を利用することで、キーの内容によって異なったCSSクラスを適用させることができ、メッセージの種類によってスタイルを動的に変更させることができる。

frash変数の内容をWebサイトのレイアウトに追加

<!DOCTYPE html>
<html>
  .
  .
  .
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <% flash.each do |message_type, message| %>
        <div class="alert alert-<%= message_type %>"><%= message %></div>
      <% end %>
      <%= yield %>
      <%= render 'layouts/footer' %>
      <%= debug(params) if Rails.env.development? %>
    </div>
    .
    .
    .
  </body>
</html>

成功時のテスト

有効な送信に対するテストを書いていく。これによって、アプリケーションの振る舞いを検証し、もし今後バグが埋め込まれたらそれを検知できるようになります。今回の目的はデータベースの中身が正しいかどうか検証することです。すなわち、有効な情報を送信して、ユーザーが作成されたことを確認します。

require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest
  .
  .
  .
  test "valid signup information" do
    get signup_path
    assert_difference 'User.count', 1 do
      post users_path, params: { user: { name:  "Example User",
                                         email: "user@example.com",
                                         password:              "password",
                                         password_confirmation: "password" } }
    end
    follow_redirect! →POSTリクエストを送信した結果を見て、指定されたリダイレクト先に移動するメソッド
    assert_template 'users/show'
  end
end

一応7章目終了できました。やっていて思ったことは内容自体はprogateやってれば理解できる内容なのかなと思います。しかし、とにかくテストの書き方が難しい。これちゃんと自分で考えてできるようになるんですかね。
とりあえず今日はここまで。

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

Docker-compose+Rails

はじめに

Laravelで環境を構築するときは、Laradockが使えてとても楽だった。だけどrailsになると自分で作成しないといけないので、備忘録として作った。

目標

使いたいホストユーザーに合わせてユーザーを作成し、そのユーザーにsudo権限を付与したい。

環境構築

それでは環境を構築していく。パートは以下のように分かれる。
1.下準備
2.コマンド実行

下準備

フォルダとファイルを用意していく。またここで使いたいユーザーを確認しておく。

$ mkdir ディレクトリ名
$ cd ディレクトリ名
$ touch Dockerfile
$ touch Gemfile
$ touch Gemfile.lock
$ touch docker-compose.yml
$ id
uid=xxx(ユーザー名) gid=xxx(グループ名) groups=xxx(グループ名)

次に、DockerfileGemfileに書き込んでいく。
(vimを使っても良いが今回は省略)

Dockerfile
FROM ruby:2.5.3

# ユーザーを作成
ARG DOCKER_UID=先ほど出したuidの番号
ARG DOCKER_USER=先ほど出したuidのユーザー名
RUN useradd -m --uid ${DOCKER_UID} --groups sudo ${DOCKER_USER}

# インストールはrootで行う
RUN apt-get update -qq && \
    apt-get install -y build-essential \
                       libpq-dev \
                       nodejs

RUN mkdir /アプリ名
ENV APP_ROOT /アプリ名
WORKDIR $APP_ROOT

ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock

RUN bundle install

# 作成したユーザーに切り替える
USER ${DOCKER_USER}

ADD . $APP_ROOT
Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.2'

Gemfile.lockは空で良いので特にいじりません。

docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: root
    ports:
      - "3306:3306"

  web:
    build: .
    command: rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/アプリ名
    ports:
      - "3000:3000"
    links:
      - db

これで準備は完了です。

コマンド実行

$ docker-compose run web rails new . --force --database=mysql --skip-bundle

ここでdatabase.ymlを修正します。ファイルはconfigというフォルダの中に入っています。

database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password # 追加
  host: db # docker-composeに合わせて変更

コンテナのビルド

$ docker-compose build
$ docker-compose up -d
$ docker-compose run web rails db:create
$ docker-compose up -d

このままではRailsのコマンドを叩くことができません。なのでそのためにコンテナに入ります。

$ docker ps
CONTAINER ID   IMAGE     PORTS
xxxxxxxxxxxx   test_web  0.0.0.0:3000->3000/tcp
# ここのコンテナIDをコピーしておいてください

$ docker exec -it xxxxxxxxxxxx /bin/bash

# 以下のようになれば成功
ユーザー名@英数字12桁:/アプリ名$ railsのコマンド打ち込めます

おわりに

プログラミング初心者でもroot権限というのはなんか怖い。
抜けや、これは危ないんじゃないかというところはあると思うので、気づいた方はコメントお願いします。

参考

1.丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)
2.とにかく簡単にDockerでRuby on Railsを動かしてみる(初心者向け)
3.Docker コンテナ内に一般ユーザーを作成する

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

【MySQL版】プログラミング初心者と行うrails環境構築講座【Win版】

プログラミング初心者向けのRuby on Rails環境構築をまとめた記事です。
なかなか一つにまとまっている記事が見つからず、時間がかかったので忘備録的な意味も込めてここに記したいと思います。

動作環境

OS:Win10 (64bit)
Ruby2.4.9(x64)
Rails 5.0.7.2
db:MySQL

以上が僕のRailsを動かすにあたる環境です。
まず最初にこれらのものを順にインストールしていきましょう。

Rubyのインストール

インストーラのダウンロード

こちらのDEVKITの欄からRuby+Devkitをダウンロードしてください。
(64bitの方はx64、32bitの方はx86)
※バージョンはなんでも構いませんが、何もわからない!という方は推奨verの2.6.5-1をダウンロードするといいでしょう。

インストール

インストーラ(~.exe)がダウンロードされたら、実行してインストールを行いましょう。
何もわからない場合はデフォルトのまま進めちゃってokです。
finishしたら、大きくRubyInstallerと書かれた画面に遷移しますが、指示通りに進めて大丈夫です。

インストールできたか確認

ターミナルで下記のコマンドを実行して、無事インストールできたか確かめます。

$ ruby -v

自分がインストールしたrubyのバージョンが表示されればokです。

バージョン確認できなかった場合

PATHが通ってない可能性があるので、Windowsの設定を開き、検索ボックスで環境変数を検索、環境変数の編集に飛んでいただき、上部のユーザーの環境変数からpathを選択して、編集。
インストールしたrubyフォルダのbinディレクトリを新規として追加しましょう。
※pathが存在しなかった場合、下部のシステム環境変数からpathを新規として追加してください。

Railsのインストール

railsのインストールは簡単で下記コマンドを実行するだけです。

$ gem i rails #最新バージョンがインストールされる

$ gem i -v (バージョン番号) rails

上のコマンドだと最新のバージョンがインストールされてしまうので、それでは不都合が生じてしまう方は下のコマンドでバージョンを指定してください。

インストール確認

$ rails -v

これはお決まりです

MySQLのインストール

railsではsqlite3がデフォルトデータベースに設定されていますが、それだと僕は環境構築時に自力で解決できない不具合が発生したのでMySQLにしています。
また、現在自分自身データベースの知識が不足しているので、細かいことはよくわかりません。
ここには自分がうまくいった手順を載せています。

インストーラのダウンロード

こちらから下のサイズが大きいものをダウンロードしてください。
oracleアカウントにログインさせようとしてきますが、今回は無視して下部のNo thanks~~をクリックしてダウンロードしましょう。

インストール

インストーラ(~.msi)を実行しましょう。
これも基本的にデフォルトのまま適宜Executeボタンを押しつつ進めちゃってください。

Accounts and Rolesの設定

Accounts and Rolesと書かれた画面が出てきたら上部のボックスに希望のパスワードを入力してください。
これがrootアカウントのパスとなるため、メモを控えといてください。

次にMySQLアカウントを追加します。
Add Userボタンを押して希望のユーザー名、パスワードを入力(他はデフォルトのままで)し、ユーザーを追加します。
ここでのパスワードはrootアカウントのものと異なっていてもokです。

この作業が終了したら、あとは前と同じようにデフォルトのまま進めていけばインストールが完了します。

インストール確認

$ mysql --version

バージョン確認できなかった場合

Rubyの場合と同じくPATHが通ってない可能性があるので、設定からPATHにインストールしたMYSQLフォルダのbinディレクトリを新規として追加しましょう。

Railsアプリの作成、設定

ここまででrailsアプリの作成に必要な最低限のソフトのインストールが終了しました。
ここからは環境に合わせつつ、Railsで作成するアプリの設定を行っていきます。

Railsアプリの作成

下記コマンドを実行します。

$ cd (任意のディレクトリ名) 
#railsアプリを設置したいディレクトリに移動

$ rails new (任意のrailsアプリ名) --database=mysql 
#デフォルトのdbをmysqlに変更してアプリ作成

これでrailsアプリが作成されます。

railsアプリデータベースの作成

database.ymlの編集

作成されたrailsアプリフォルダ内のconfig内に存在するdatabase.ymlファイルを編集します。
上のほうにあるデフォルトのusernamepasswordだけ下記のように編集してください。

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: (MySQLインストール時に作成した名前)
  password: (MySQLインストール時に作成したパスワード)
  host: localhost
データベース作成

下記のコマンドをrailsアプリ上で実行し、データベースを作成してください。

$ rails db:create

開発環境構築完了!!!

ひとまずRailsアプリを開発する環境はこれで整いました。
自分がこれまで学んできたことや、参考書、サイトなどを活かしてrailsアプリの開発を行いましょう。

※herokuにデプロイして公開する記事も後日執筆予定です。
※何か間違っている点、疑問点等ございましたらコメントお願いします。

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

【MySQL版】プログラミング初心者と行うRuby on Rails環境構築講座【Win版】

プログラミング初心者向けのRuby on Rails環境構築をまとめた記事です。
なかなか一つにまとまっている記事が見つからず、時間がかかったので忘備録的な意味も込めてここに記したいと思います。

注意

本記事では最低限の環境構築しか行わないため、手っ取り早くrailsアプリの開発が行いたい初心者さん向けの記事です。

様々な拡張機能や応用などには対応しきれていない部分もあるので、必要な方は個人で調べてください。

動作環境

OS:Win10 (64bit)
Ruby2.4.9(x64)
Rails 5.0.7.2
db:MySQL

以上が僕のRailsを動かすにあたる環境です。
まず最初にこれらのものを順にインストールしていきましょう。

※特にバージョンの指定などはありませんが、不安な場合は僕と同じバージョンをインストールしたほうが確実だと思います。

Rubyのインストール

インストーラのダウンロード

こちらのDEVKITの欄からRuby+Devkitをダウンロードしてください。
(64bitの方はx64、32bitの方はx86)
※バージョンはなんでも構いませんが、何もわからない!という方は推奨verの2.6.5-1をダウンロードするといいでしょう。

インストール

インストーラ(~.exe)がダウンロードされたら、実行してインストールを行いましょう。
何もわからない場合はデフォルトのまま進めちゃってokです。
finishしたら、大きくRubyInstallerと書かれた画面に遷移しますが、指示通りに進めて大丈夫です。

インストールできたか確認

ターミナルで下記のコマンドを実行して、無事インストールできたか確かめます。

$ ruby -v

自分がインストールしたrubyのバージョンが表示されればokです。

バージョン確認できなかった場合

PATHが通ってない可能性があるので、Windowsの設定を開き、検索ボックスで環境変数を検索、環境変数の編集に飛んでいただき、上部のユーザーの環境変数からpathを選択して、編集。
インストールしたrubyフォルダのbinディレクトリを新規として追加しましょう。
※pathが存在しなかった場合、下部のシステム環境変数からpathを新規として追加してください。

Railsのインストール

railsのインストールは簡単で下記コマンドを実行するだけです。

$ gem i rails #最新バージョンがインストールされる

$ gem i -v (バージョン番号) rails

上のコマンドだと最新のバージョンがインストールされてしまうので、それでは不都合が生じてしまう方は下のコマンドでバージョンを指定してください。

インストール確認

$ rails -v

これはお決まりです

MySQLのインストール

railsではsqlite3がデフォルトデータベースに設定されていますが、それだと僕は環境構築時に自力で解決できない原因不明の不具合が発生したのでMySQLにしています。
(友人も同じ現象が起こったため、この問題で悩んでる方、多いと思います)

また、現在自分自身データベースの知識が不足しているので、細かいことはよくわかりません。
ここには自分がうまくいった手順を載せています。

インストーラのダウンロード

こちらから下のサイズが大きいものをダウンロードしてください。
oracleアカウントにログインさせようとしてきますが、今回は無視して下部のNo thanks~~をクリックしてダウンロードしましょう。

インストール

インストーラ(~.msi)を実行しましょう。
これも基本的にデフォルトのまま適宜Executeボタンを押しつつ進めちゃってください。

Accounts and Rolesの設定

Accounts and Rolesと書かれた画面が出てきたら上部のボックスに希望のパスワードを入力してください。
これがrootアカウントのパスとなるため、メモを控えといてください。

次にMySQLアカウントを追加します。
Add Userボタンを押して希望のユーザー名、パスワードを入力(他はデフォルトのままで)し、ユーザーを追加します。
ここでのパスワードはrootアカウントのものと異なっていてもokです。

この作業が終了したら、あとは前と同じようにデフォルトのまま進めていけばインストールが完了します。

インストール確認

$ mysql --version

バージョン確認できなかった場合

Rubyの場合と同じくPATHが通ってない可能性があるので、設定からPATHにインストールしたMYSQLフォルダのbinディレクトリを新規として追加しましょう。

ターミナルがGit bashの場合

自分はgit bashをターミナルとして用いているのですが、MySQLコマンドを実行する場合は先頭に必ずwinptyをつけないと実行できないようです。(原因はわからず、、、)

Railsアプリの作成、設定

ここまででrailsアプリの作成に必要な最低限のソフトのインストールが終了しました。
ここからは環境に合わせつつ、Railsで作成するアプリの設定を行っていきます。

Railsアプリの作成

下記コマンドを実行します。

$ cd (任意のディレクトリ名) 
#railsアプリを設置したいディレクトリに移動

$ rails new (任意のrailsアプリ名) --database=mysql 
#デフォルトのdbをmysqlに変更してアプリ作成

これでrailsアプリが作成されます。

railsアプリデータベースの作成

database.ymlの編集

作成されたrailsアプリフォルダ内のconfig内に存在するdatabase.ymlファイルを編集します。
上のほうにあるデフォルトのusernamepasswordだけ下記のように編集してください。

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: (MySQLインストール時に作成した名前)
  password: (MySQLインストール時に作成したパスワード)
  host: localhost
データベース作成

下記のコマンドをrailsアプリ上で実行し、データベースを作成してください。

$ rails db:create

開発環境構築完了!!!

ひとまずRailsアプリを開発する環境はこれで整いました。
自分がこれまで学んできたことや、参考書、サイトなどを活かしてrailsアプリの開発を行いましょう。

※herokuにデプロイして公開する記事も後日執筆予定です。
※何か間違っている点、疑問点等ございましたらコメントお願いします。

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

Railsを使った新規アプリ立ち上げの流れ

Railsを使った新規アプリ立ち上げの流れを簡単におさらい

<作業工程一覧>

・rails new
・bundle install
・rails db:create
・rails s

作業1 新規アプリの立ち上げ

ターミナル
$ rails _5.2.3_ new test_app -d mysql
           ①           ②    ③
①railsのバージョン(5.2.3) ②アプリ名(test_app) ③オプション(データベースとしてmysqlを指定)

ディレクトリの移動
currentディレクトリ => 新規アプリ(test_app)ディレクトリ

ターミナル
$ cd test_app

作業2 gemのインストール

ターミナル
test_app $ bundle install

作業3 データベースの作成

ターミナル
test_app $ rails db:create

作業4 ローカルサーバの起動

ターミナル
test_app $ rails s

プラウザで localhost:3000 と入力。
もしくは http://localhost:3000 ⬅️こちらをクリック

以下のような画面が表示されればアプリの立ち上げ完了です。
アプリの立ち上げ.jpg

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