- 投稿日:2020-03-30T23:08:41+09:00
Typeformのかっこいい入力フォームをWebhookを使って自作アプリに実装した話
概要
非エンジニアビジネス職(カスタマーサクセス職)の@yuta_maruyamaが、動的でイケてるかっこよい入力フォームを自力で作ろうと思ったけれど難易度が高すぎたので米国産SaaSのTypeformをWebhookで組み込んでフォームを実装した話です。
ちなみにカスタマーサクセスの話は一切なく、大好きなクラフトビールのテイスティングノートアプリを作ろうとしている中での話。環境
- Ruby 2.6.2
- Rails 6.0
- heroku
作ろうとしているもの
- ビールのテイスティングノートアプリ
- 飲んだビールに関する評価やコメントをnoteとして残す
- Rails練習用なので見てくれは勘弁
- 「ノートを残す煩わしさ」がないことをサービスのユニークな価値にしたかったのでそこにはこだわりたい
Typeformとは
- フォームやサーベイに特化した米国のサービス
- 無料で使える
- 有料版だとHidden Fields機能など色々使える
- 日本語対応も(一応)している
やったこと
Typeform側
フォームの作成
マグマパスタばりのすっ飛ばし方だが、まずはTypeformにアカウント作成し、フォーム作成をする。Googleフォームを作るのとほぼ変わらない。
Webhookの設定
WebhookなのでPOSTリクエストが前提となる。なので勝手にアクションを指定しなくとも勝手にPOSTになる。今回は
POST /notes
で設定。保存。
hidden_filedの設定(オプショナル)
Hidden Fieldsは有料オプションなので有料化するつもりなければ飛ばして良い。Hidden Fieldsを用いない場合フォーム内で必要な値を入力してもらうのが良さそう(ユーザーにとってはひと手間だが)
今回の場合は、どこのBrewery(醸造所)のなんていうBeerのnoteを書いているかの値を渡して、
- Typeformに遷移した際にどのビールに関してのnoteかをはっきり示す
- わざわざTypeform側でユーザーがなんのビールについてのnoteか入力させないようにするを実現したい。なので
beer_id
brewery_id
beer_name
brewery_name
のフィールドを用意しておくサービス側
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 endView
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チャンネルでご指導いただいている。そのチャンネルでこんなことを述べたが
非エンジニアの自分でも、外部サービスをきちんと使えれば学習時間を大幅に節約してそれなりのアプリケーションを作れる実感がわいた。ZapierなどのノンコーディングでSaaSを連携できるSaaSのためのSaaSもどんどん進化を遂げており、非エンジニアでもプロトタイプレベルならガンガン自分で作ってみて欲しい見た目
最後に、こんな感じの見た目になった。
Typeformに遷移。ちゃんとビール名とブルワリー名が出ている。
元々Javascriptで自分でどうにかしようとおもってたがこれは無理
そして、Yorroco Beerが好きな人はぜひ連絡ください!!
- 投稿日:2020-03-30T23:08:41+09:00
Typeformのかっこいい入力フォームを自作アプリに実装した話
概要
非エンジニアビジネス職(カスタマーサクセス職)の@yuta_maruyamaが、動的でイケてるかっこよい入力フォームを自力で作ろうと思ったけれど難易度が高すぎたので米国産SaaSのTypeformを組み込んでWebhookで連携しようとした話です。
ちなみにカスタマーサクセスの話は一切なく、大好きなクラフトビールのテイスティングノートアプリを作ろうとしている中での話。環境
- Ruby 2.6.2
- Rails 6.0
- heroku
作ろうとしているもの
- ビールのテイスティングノートアプリ
- 飲んだビールに関する評価やコメントをnoteとして残す
- Rails練習用なので見てくれは勘弁
- 「ノートを残す煩わしさ」がないことをサービスのユニークな価値にしたかったのでそこにはこだわりたい
Typeformとは
- フォームやサーベイに特化した米国のサービス
- 無料で使える
- 有料版だとHidden Fields機能など色々使える
- 日本語対応も(一応)している
やったこと
Typeform側
フォームの作成
マグマパスタばりのすっ飛ばし方だが、まずはTypeformにアカウント作成し、フォーム作成をする。Googleフォームを作るのとほぼ変わらない。
Webhookの設定
WebhookなのでPOSTリクエストが前提となる。なので勝手にアクションを指定しなくとも勝手にPOSTになる。今回は
POST /notes
で設定。保存。
hidden_filedの設定(オプショナル)
Hidden Fieldsは有料オプションなので有料化するつもりなければ飛ばして良い。Hidden Fieldsを用いない場合フォーム内で必要な値を入力してもらうのが良さそう(ユーザーにとってはひと手間だが)
今回の場合は、どこのBrewery(醸造所)のなんていうBeerのnoteを書いているかの値を渡して、
- Typeformに遷移した際にどのビールに関してのnoteかをはっきり示す
- わざわざTypeform側でユーザーがなんのビールについてのnoteか入力させないようにする
を実現したい。なので
beer_id
brewery_id
beer_name
brewery_name
のフィールドを用意しておくサービス側
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 endView
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チャンネルでご指導いただいている。そのチャンネルでこんなことを述べたが
非エンジニアの自分でも、外部サービスをきちんと使えれば学習時間を大幅に節約してそれなりのアプリケーションを作れる実感がわいた。ZapierなどのノンコーディングでSaaSを連携できるSaaSのためのSaaSもどんどん進化を遂げており、非エンジニアでもプロトタイプレベルならガンガン自分で作ってみて欲しい見た目
最後に、こんな感じの見た目になった。
Typeformに遷移。ちゃんとビール名とブルワリー名が出ている。
元々Javascriptで自分でどうにかしようとおもってたがこれは無理
そして、Yorroco Beerが好きな人はぜひ連絡ください!!
- 投稿日:2020-03-30T22:42:16+09:00
Docker環境でRailsアプリにvue.jsを導入する
目的
railsアプリにvue.jsを導入するために、練習もかねてサンプルのアプリにvueを導入してみたいと思う。
サンプルアプリのディレクトリ作成
任意のワークスペースでディレクトリを作成します。
ターミナルmkdir sample_app cd sample_appDockerの設定ファイルを作成
DockerfileFROM 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 . /appdocker-compose.ymlversion: '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:Gemfilesource '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: dbhostの部分をdbに変更する。
vue.jsの導入
Gemfilegem 'webpacker', github: 'rails/webpacker'その後、
$ docker-compose exec web bashでwebコンテナに入る。
コンテナ内でコマンドを以下のコマンドを実行
$ rails webpacker:install $ rails webpacker:install:vue $ bin/webpackRailsのviewファイルに以下を記述する
<%=javascript_pack_tag 'hello_vue'%>こんな画面が出てきたら成功です。
以上
- 投稿日:2020-03-30T22:09:30+09:00
Dockerのコマンドについて詳しくなろう
build
buildコマンドはimageを構築するのみ。コンテナ作成はしない。
$ docker-compose buildup
upコマンドでは、キャッシュがある場合はそれを使って一発でイメージの構築から、コンテナの構築・起動までします。
$ docker-compose upstart
startコマンドは既存のコンテナを起動します。
$ cocker-compose startrun
runコマンドはimageの構築から、コンテナの構築・起動までする。引数でサービスを指定する必要あり。
$ docker-compose run webexec
コンテナの中に移動できる
$ docker-compose exec web bashbash ashの違いは、ashの方が軽量なコマンドらしい。
新たなrailsプロジェクトを立ち上げるコマンド
ターミナルdocker-compose run web rails new . --force --database=mysqlrails newの . は現在いるディレクトリにそのままプロジェクトを作成するというもの)だそうです。
以上
- 投稿日:2020-03-30T21:48:30+09:00
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が可能になりました。
- 投稿日:2020-03-30T20:23:35+09:00
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 と省略して記述することも可能です。
- 投稿日:2020-03-30T19:33:46+09:00
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.lockBUNDLED WITH 2.0.2gem install bundler -v2.0.2上記を実装することでエラーを解決することができます。
- 投稿日:2020-03-30T18:44:31+09:00
DBから取得したデータの中身を取得する方法 Ruby on Rails
MySQLからデータを取得してきた
whereメソッドを使って、特定条件下で検索に該当するクエリを発行させると、条件に当てはまったレコード全てを引っ張ってくる。
log_in.rbyesterday_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.rbp log_in_list.uidと書いて、hogehogeが取れているかを確認してみました。すると、ログはおろか、localhostでこの処理部分を走らせてみると、画面に真っ赤な文字でundefined uidと表示されてしまう。何でやねん。
ハッシュみたいなものからオブジェクトを取り出すような書き方はできん
ハッシュみたいなやつと書いているのは、ActiveRecordから取ってきているデータのことをなんて呼んでいいかわからないからですが、こう考えてみると、log_in_listを最初にpした時、これはデータの型がハッシュみたいなやつであって、オブジェクトになっていない。これが本当にハッシュで、ハッシュの値を取り出すには、
example.rblog_in_list["uid"]とかにせねばならない。今回のデータはActiveRecordから引っ張ってきているものなので、これでのアクセスもできない・・・ハズ。
また、whereは条件にあった全てのレコードを引っ張ってくるので、条件にあった全てのuidを抜き取る作業を必要とする。それじゃどうするか・・・一旦、このハッシュっぽい奴のデータをオブジェクトにしてやればいい。
hogehoge.rblog_in_list.each do |data| log_in_users = data.uid p log_in_users endeachを使って、log_in_listの中身をdata変数へと入れ込むと、オブジェクト化してくれるので、オブジェクトへのアクセスする書き方が可能になる。これでhogehogeだけを引っ張ってこれる。
補足
後で知ったことですが、ハッシュ用のループ処理で使えるeachもある。この記事によると、やはりハッシュにはハッシュオブジェクトがちゃんと存在してそのオブジェクトへのアクセスの仕方も違うようだ・・・
考察
重要なのは2つあるかなと思いました。
書いているコードに内包されているデータの型を意識的に脳内で可視化すること。脳内で可視化って意味不明かもしれませんが、言わんとしていることは分かると思うんですよ。「今持ってきているデータは〇〇型で、まだ日オブジェクトだな」みたいな意識を持つイメージでしょうか。
また、それをオブジェクト化した時のアクセス方法を知っていること、もしくはそこから検索をかけて調べる足掛かりにする、ということでしょうか。
- 投稿日:2020-03-30T18:01:49+09:00
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 endSerializer
class UserSerializer < ActiveModel::Serializer attributes :id, :name has_many :books endNOTE
途中 eager_load / includes が効かないような気がして gem も試したのだが、効かないというのは気のせいだった。
ams_lazy_relationships は Star数は少ないが includes のちょっとした問題点を解決してくれそうなgem?
httpリクエスト単位でのキャッシュや、もっと長いキャッシュを実現してくれそうな気もする。Original by Github issue
- 投稿日:2020-03-30T17:36:00+09:00
GitHubから、gemの脆弱性の通知がきたので、バージョンアップをする
はじめに
rubyzipというgemで、割と危険度が高い脆弱性があるという主旨の通知メールがGitHubから届いたため、いちいち面倒ではあるが、バージョンアップを行っておく。
手順
Gemfileの中身にrubyzipがないか探すが、どうも、rubyzipというgemは使っていないようだったため、Gemfile.lockの中身を検索する。すると、2ヶ所で検索される。どうも、他のgemの中から、依存関係として利用されている事のようだ。
Gemfile.lockrubyzip (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 rubyzip2.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 rubyzipGemfile.lockの中身を見ると、確かに、rubyzipのバージョンが上がっています。
Gemfile.lockrubyzip (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
- 投稿日:2020-03-30T17:33:36+09:00
Ruby on Rails とかで docker 環境なのに #VSCode で ruby-rubocop 拡張を有効にするにはどうすれば良いのか? ( #Rails #Ruby )
- 投稿日:2020-03-30T17:24:48+09:00
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
- 投稿日:2020-03-30T16:21:41+09:00
#Rails #rspec で SQLクエリ発行を標準出力する
- 投稿日:2020-03-30T14:18:16+09:00
初めてのBitbucket
rails チュートリアルを進めるにあたって、bitbucketを一番初めに使用するときにわからないことがあって苦しんだためメモ
・cloud9(aws)環境で実施
・アカウント作成は省略公開鍵の作成
consolecat ~/.ssh/id_rsa.pub
上記のコマンド入力で公開鍵を所持しているか確認できます。所持していない場合には
No such file or directory
と表示されます。
鍵を所持していない場合はconsolecd ~/.ssh #sshフォルダに移動 ssh-keygen -t rsa -C saber@example.com # 自分のメールアドレス入力Entキー押すと色々と出てくるが特にいじる必要ないのでそのままEntキー何回か押して鍵を作成。鍵を作成した後に先ほどの
consolecat ~/.ssh/id_rsa.pub
を実行して鍵を表示させます。
公開鍵の追加
bitbucketにログイン後、
ユーザーアイコン
↓
Bitbucket setting
↓
セキュリティー
↓
SSH鍵
↓
鍵追加
↓
さきほど表示した鍵をコピペ
↓
作成
これで完了です。bitbucketへリポジトリ作成
+アイコンを押し、空のリポジトリを作成します。リポジトリ名はなんでも大丈夫せす(わかりやすくするなら自身のアプリケーション名が良いかと)。
bitbucketにリポジトリを作成するとバケツに何かを入れましょうというページに移動しgit remote add origin git@bitbucket.org:ユーザー名/先ほど作成したリポジトリ名.git
とgit push -u origin master
いうコマンドが表示されます。このコードそのまま入力してもいいのですが、まだ自身の環境にリポジトリを作成していない場合はconsolegit init (自身の環境の新しいリポジトリの初期化)ちなみにawsのcloud9の場合はgit導入済みのためこのコマンドが最初から使用できます。
consolegit add -A git commit -m "メッセージ"上記のコマンド実行し、自身のgitにリポジトリを作成したあとは先ほどの
git remote add origin git@bitbucket.org:ユーザー名/作成したリポジトリ名.git
とgit push -u origin master
いうコマンドを実行します。consolegit remote add origin git@bitbucket.org:ユーザー名/先ほど作成したリポジトリ名.git git push -u origin master
これでBitbucketに内容が反映されます。
あとがき
自分なりにわかりやすいよう書いてみましたがわかりにくかったらすみません。
参考になれば幸いです。
- 投稿日:2020-03-30T13:03:55+09:00
#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
- 投稿日:2020-03-30T12:48:13+09:00
Railsのコールバッククラス(callback class)について調べたこと
狙い
本文は、前人の知見(@joker1007の記事、@k5trismegistusの記事)踏まえて、コールバッククラスのメリットとデメリットを述べて、さらに実践において、どのような状況で、それを使ったほうが良いのかについて論じてみる。
利弊
メリット
- モデルから、コールバックの処理(Railsガイドでは、「Active Recordオブジェクトが作成/保存/更新/削除/検証/データベースからの読み込み、などのイベント発生時に常に実行されるコード」と定義)といった責務を切り離れる。
- 異なるモデルでのコールバック処理の中から、汎用性の高い部分を抽出さして、カプセル化することで、メンテナンスしやすくなり、テストもしやすくなる。
デメリット
- いくつのモデルに使われた共通のコールバッククラスでの処理を変更したい時に、特定のモデルに対してその変更がいい、特定のモデルに対してその変更が悪いのようなケースが生じる可能性がある。
- 各モデルにコードバックを書くことと比べて、他のモデルにも影響が出るため、変更の際の確認・検証のコストが高くなる。
- 「他のモデルにも影響が出る」を見落としてしまった状況とつなぎやすくなり、ビジネスロジックの非意図的な変更やサービスの障害が起きる恐れがある。
適用条件
- コールバックの処理のコードの量が異常に多くて、かつ処理の複雑度が高くて、コードをメンテナンスしにくい場合
- メンテナンスをしやすくなることを目的として、コールバックの処理を切り離れる
- 切り離れたコールバックの処理をカプセル化する時に、他の人がそれを非意図的に使わないように、「明確な名前と境界」を付けることは重要である。
- 複数のモデルの中にある特に注力したい大事なコールバックの処理があり、それをドメイン知識として表現したい場合
- 上記の1と同じく、「明確な名前と境界」を付けることは重要である。(これはドメイン知識として成立する前提条件であるので、特に大事)
- 将来的に仕様の変更によって、その処理を修正する必要な時に、既存の「ドメイン知識」を修正したら十分なので、あるいは新たなドメイン知識が生まれることで、それらを再整理しないとけいないのかを考えることは重要である。
- 投稿日:2020-03-30T12:23:15+09:00
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_sandboxUser モデルを作成する
User モデルを作成します。
$ bin/rails g model User name
スクリプトを作成する
スクリプトを作成します。スクリプトは以下の処理を実行します。
- Andy という
name
を持つ User を1つ登録する。- キャッシュを有効にする。
- 登録したUserを
User.first
で検索して、name
を出力する。User.upsert_all
を実行して、 Andy から Bob にname
を更新する。User.first
を使ってname
を出力する。scripts/cache_clear.rbUser.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.nameRails 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
参考情報
- 投稿日:2020-03-30T12:12:34+09:00
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 .プロジェクト名には、単数でも複数でもこだわる必要はありません。
- 投稿日:2020-03-30T11:49:27+09:00
【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 jaconfig/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/最後までお読みいただきありがとうございました。
- 投稿日:2020-03-30T11:34:51+09:00
has_secure_passwordについて
はじめに
パスワードを実装してみたのでメモ
userモデルにパスワードを実装していきます1.has_secure_password
userモデルに
user.rbclass User < ApplicationRecord has_secure_password endと追加することで
(1).セキュアにハッシュ化したパスワードを、データベース内のpassword_digest
という属性に保存できるようになる。(条件あり)
(2).2つのペアの仮想的な属性 (password
とpassword_confirmation
) が使えるようになる。また、存在性と値が一致するかどうかのバリデーションも追加される。
(3).authenticate
メソッドが使えるようになる (引数の文字列がパスワードと一致するとUserオブジェクトを、間違っているとfalseを返すメソッド) 。
この3つの機能が使えるようになります。順番に解説していきます。(1)
ここでいうセキュアとは安全という意味です。設定したパスワードを暗号化(ハッシュ化)させて、
password_dijest
というカラムに保存できるようにします。すなわち、Userモデルにpassword_dijest
カラムを追加する必要があります(先ほどの条件とはこのこと)。consolerails generate migration add_password_digest_to_users password_digest:string rails db:migrateまた、パスワードを暗号化するためのgemとして、
bcrypt
(最新ので大丈夫です)というgemをgemfail
に追加してbundle install
する必要があります。(2)
password
とpassword_confirmation
のセットというのはパスワードとパスワード(確認用)ということです。ちなみに、has_secure_password
をUserモデルに追加したことで自動的にこの二つのバリデーションが追加されるようになっていますが、これは更新時には適用されないのでuser.rbvalidates :password, presence: trueと追加しておきましょう。パスワードの長さを制限したいときは
user.rbvalidates :password, presence: true, length: {minimum:5}とすれば5文字以上のパスワードに制限することができます。
(3)
authenticateメソッドではその説明の通り、引数の文字列がパスワードと一致しているか確認してくれます。
consoleUser.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
を自分なりにかみくだいてみました。参考になれば幸いです。
- 投稿日:2020-03-30T11:32:48+09:00
#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 endclass UserSerializer < ActiveModel::Serializer attributes :id, :name endAdapter を指定する
adapter: :json
を指定すると JSON を Serializer の名前でネストして囲ってくれるみたいだ ( この場合は"users": []
)"all_users": []
などという好きなキー名にするには Serializer 自体を AllUserSerializer とかいう名前にする必要がありそう?- なんか挙動が暗黙的すぎて、いままで触っていたコードではよく分かっていなかった
render json: User.all, each_serializer: UserSerializer, adapter: :jsonactive_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: :jsonactive_model_serializers/rendering.md at v0.10.6 · rails-api/active_model_serializers
Original by Github issue
- 投稿日:2020-03-30T11:08:56+09:00
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.rbrailsの前に bundle execを付け足したらよかったんですね。
今までよくわからずに放置して使ってたbundle exec。
今回のエラーを経て改めて検索し直したら、
bundle execをつけずに実行すると、グローバルにインストールされているgemが動くのに対し、
bundle execをつけて実行するとプロジェクト内にあるgemが動くんだそうで。なるほど、dockerのことはまだよくわかって無いですが、なんとな〜く理解できてきた気がするぞ。
- 投稿日:2020-03-30T10:07:57+09:00
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.rbclass User < ApplicationRecord validates :name, presence: true has_many :topics end
shoulda-matchers
を使うとこのようなRSpecを書くことができます!user_spec.rbrequire '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の書き方で書いて、テストケースに抜けや漏れが出てしまうなんてことを防げます。上記の例では
presence
とhas_many
を取り上げましたが、他にも使えそうな書き方がたくさんあるので追記していきたいと思います。
- 投稿日:2020-03-30T10:02:27+09:00
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やってれば理解できる内容なのかなと思います。しかし、とにかくテストの書き方が難しい。これちゃんと自分で考えてできるようになるんですかね。
とりあえず今日はここまで。
- 投稿日:2020-03-30T02:39:36+09:00
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(グループ名)次に、
Dockerfile
とGemfile
に書き込んでいく。
(vimを使っても良いが今回は省略)DockerfileFROM 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_ROOTGemfilesource 'https://rubygems.org' gem 'rails', '5.2.2'
Gemfile.lock
は空で良いので特にいじりません。docker-compose.ymlversion: '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.ymldefault: &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 コンテナ内に一般ユーザーを作成する
- 投稿日:2020-03-30T01:25:17+09:00
【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ファイルを編集します。
上のほうにあるデフォルトのusername
とpassword
だけ下記のように編集してください。default: &default adapter: mysql2 encoding: utf8 pool: 5 username: (MySQLインストール時に作成した名前) password: (MySQLインストール時に作成したパスワード) host: localhostデータベース作成
下記のコマンドをrailsアプリ上で実行し、データベースを作成してください。
$ rails db:create開発環境構築完了!!!
ひとまずRailsアプリを開発する環境はこれで整いました。
自分がこれまで学んできたことや、参考書、サイトなどを活かしてrailsアプリの開発を行いましょう。※herokuにデプロイして公開する記事も後日執筆予定です。
※何か間違っている点、疑問点等ございましたらコメントお願いします。
- 投稿日:2020-03-30T01:25:17+09:00
【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ファイルを編集します。
上のほうにあるデフォルトのusername
とpassword
だけ下記のように編集してください。default: &default adapter: mysql2 encoding: utf8 pool: 5 username: (MySQLインストール時に作成した名前) password: (MySQLインストール時に作成したパスワード) host: localhostデータベース作成
下記のコマンドをrailsアプリ上で実行し、データベースを作成してください。
$ rails db:create開発環境構築完了!!!
ひとまずRailsアプリを開発する環境はこれで整いました。
自分がこれまで学んできたことや、参考書、サイトなどを活かしてrailsアプリの開発を行いましょう。※herokuにデプロイして公開する記事も後日執筆予定です。
※何か間違っている点、疑問点等ございましたらコメントお願いします。
- 投稿日:2020-03-30T00:58:00+09:00
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 ⬅️こちらをクリック