- 投稿日:2019-02-15T23:50:06+09:00
Rubyでnilか空文字を判定する
nil、空文字の判定方法
nilの判定方法
check_nil.rbstr = nil if str.nil? puts "strはnilです。" end # strはnilです。空文字の判定方法
check_empty.rbstr = "" if str.empty? puts "strは空文字です。" end # strは空文字です。nilまたは空文字を判定する
nilと空文字を同時に判定する方法
is_nil_or_empty.rbdef is_nil_or_empty?(str) if str.nil? || str.empty? return true else return false end end check_array = Array.new check_array.push("") check_array.push(nil) check_array.each do |str| if is_nil_or_empty?(str) puts "strはnilまたは空文字です。" end end #strはnilまたは空文字です。 #strはnilまたは空文字です。注意点
if式の条件式は str.nil? || str.empty? とすべきです。
理由は、||演算子は左から右に順に条件式を評価し、結果が真になった時点でif式の中に入りますが、
empty?から先に評価した場合、対象の文字列がnilであればNoMethodErrorを返すためです。
empty?は文字列、配列、ハッシュのみに対応しています。nilには対応していないため、NoMethodErrorが返ってきます。
nil?は全てのオブジェクトに対応しているため、if式の条件式はnil?を左に書くべきです。no_method_error.rbdef is_nil_or_empty?(str) if str.empty? || str.nil? return true else return false end end check_array = Array.new check_array.push("") check_array.push(nil) check_array.each do |str| if is_nil_or_empty?(str) puts "strはnilまたは空文字です。" end end #undefined method `empty?' for nil:NilClass (NoMethodError)余談
to_sメソッドを使って文字列型に変換することで、nilと空文字を判定することも出来ます。
use_to_s.rbdef is_nil_or_empty?(str) if str.to_s.empty? return true else return false end end check_array = Array.new check_array.push("") check_array.push(nil) check_array.each do |str| if is_nil_or_empty?(str) puts "strはnilまたは空文字です。" end end #strはnilまたは空文字です。 #strはnilまたは空文字です。ただし、UTF-8 でしか動かない処理に投入する場合は、上記の判定方法は使ってはいけない。
https://qiita.com/scivola/items/1f6704f81aba18df9012
- 投稿日:2019-02-15T23:48:41+09:00
後から名前空間を切ったらPG::UndefinedTable with namespaced Modelが発生した
API作ったが、後から名前空間を別に切り出すことになった
API完成したものの、各モジュールの名前が煩雑になりすぎたので後から名前空間を切り出すことになった。
一通り変えたけどDBでエラー吐いてる
一通り変えて、念のためテストを走らす。
ちゃんとモデル名も変更してるし、DBと合ってるな。。。。
PG::UndefinedTable with namespaced ModelDBがエラー吐いてるやん!
原因
prefixを定義してなかったのが原因でした。
例えば以下の様に名前空間をHogeで切っていて、その中にUserというモデルを定義しており、テーブル名はhoge_usersで定義されていた場合。module Hoge class User < ApplicationRecord end endDBに問い合わせるには
table_name_prefix
というメソッドを定義してやると、ちゃんと頭にhogeを付けてDBに問い合わせてくれるので、テーブルが見つからないと言われなくなります。module Hoge def self.table_name_prefix 'hoge_' end end
- 投稿日:2019-02-15T23:48:13+09:00
RailsでModelをOrderできない時に確認すべきこと
- 投稿日:2019-02-15T22:30:01+09:00
rails sできない時の対処法
※初学者向けです。
Ruby on Railsで Rails serverコマンドをした時にサーバーが立ち上がらなかった時に対処したことをメモ。
エラー内容
rails s
としてローカル(http://192.168.33.10:3000/ )にアクセスすると,ActiveRecord::ConnectionNotEstablished
No connection pool with 'primary' found.といったようなメッセージが出て上手く動いていない。
ActiveRecordとはRuby on Railsにおいてデータベースとのやりとりに使われているフレームワーク?です。
なのでこのエラーはデータベース関連のエラーであると推測されます。Rails db:migrateで確認
ターミナルを見返すとそもそもdb:migrateが上手くいってません
rails db:migrate
とすると
Gem::LoadError: can't activate sqlite3 (~> 1.3.6), already activated sqlite3-1.4.0. Make sure all dependencies are added to Gemfile.
というエラー。内容はGemのロードエラー。具体的にはsqlite3 (~> 1.3.6)がアクティベートできないけどsqlite3 (1.4.0)はアクティベートされてるよ、というもの。
おそらくRailsが最新版のsqlite3(1.4.0)を受け付けてないと推測。
ちなみに(~>1.3.6)とは '1.3.6以上1.4.0未満'という意味。対処法:Gemfileの更新
Rails new したフォルダにあるGemfileの内容を変えましょう。
(初学者の私にとっては「???」状態でしたが。。。)
Gemfile
の中にある
gem 'sqlite3'
という部分を
gem 'sqlite3', '~> 1.3.6'
に変更しましょう。これで
bundle update
bundle install
というコマンドをターミナル上で実行し、
rails s
晴れてRuby on Railsのデフォルト画面が現れるはず。
初学者でいきなり詰まったところだったのでメモを残します。
- 投稿日:2019-02-15T22:19:31+09:00
【Rails】Facebookでユーザー認証する
はじめに
FacebookでOmniAuthでユーザー認証しましょう。かっこいいからです。
似たような記事はたくさんありますが、Facebookの仕様変更などで、記事単体では実装が完了しないものばかりだったので改めて書くことにしました。まずdeviseのみで認証機能を実装
以下のサイトを参考につくります。
【Railsのアプリ開発】初心者でもわかる!deviseでログイン機能を実装する使い方暇があれば上の内容も自分でしっかり解説して書きたいところですが、「暇があれば」などと言うのは大体やらない兆しです。期待しないでください。
ユーザー一覧ページの作成
認証ページだけ作っても寂しいので、ユーザー一覧ページを作っておくと良いでしょう。
$ rails g controller usersこれで作成されるファイルのうち、コントローラーとビューを以下のように変更して、ユーザー一覧ページを作成します。
app/controllers/users_controller.rbclass UsersController < ApplicationController before_action :authenticate_user! def index @users = User.all end endapp/views/users/index.html.erb<% @users.each do |u| %> <div class="user_field"> <%= link_to u.email, destroy_user_session_path, method: :delete %> </div> <% end %>一覧表示されたユーザーのメールアドレスをクリックするとサインアウトするようにしました。
最後に、このusers#indexアクションへのルーティングを設定しておきます。
config/routes.rbRails.application.routes.draw do # 省略 resources :users, only: [:index] root "users#index" endサインイン後にはルートパスにリダイレクトされるので、簡単にサインインできたかどうかの確認ができるように、"users#index"をルートパスに設定しました。
Facebookでのサインインに成功すれば、ユーザー一覧のページに遷移し、そこに自分がFacebookに登録したメールアドレスが表示されるはずです。omniauthを実装
再び以下のサイトを参考に。
【開発メモ】RailsアプリでFacebookログインの認証機能を実装させる方法暇があれば。
Facebookの変更に対応
2019/2/15時点で、これだけではまだ足りません。
Facebook側の仕様変更で、以下が必須になりました。
- アプリケーションにhttpsでアクセスするように設定する
- プライバシーポリシーを載せたURLを指定する
順にやっていきます。
アプリケーションにhttpsでアクセスできるように設定する
httpsでアクセスできるようにするには、アプリケーションサーバーがSSL証明書というものを持っていないといけません。SSL証明書にはグレードがあり、グレードの高いものほどサイトの安全性を保証できるのですが、それらは発行するのに認証局にたくさんお金を払わなければなりません。
しかしグレードの低いもので良ければ、自分で作成することができます。自分で作成といってもよくわからないので、SSL証明書の作成はmkcertを使って楽にやってしまいましょう。また、RailsのアプリケーションサーバーとしてPumaを使えば、SSL証明書に関するなんやかんやをいい感じにやってくれます。
PumaはRails5では標準のアプリケーションサーバーなので、これに関しては特にややこしいことはありませんが、何かこだわりや制約があって他のアプリケーションサーバーを使う場合はブラウザバックです。mkcertでSSL証明書を作成
公式GitHub: FiloSottile/mkcert
READMEを読んで、mkcertをインストールします。
僕のパソコンはmacなので、Homebrewを使います。$ brew install mkcert $ mkcert -install自分のRailsアプリケーションの適当な場所にSSL証明書を置くディレクトリを作り、SSL証明書を作成します。
$ mkdir config/certs && cd config/certs $ mkcert localhostこれで、
config/certs
ディレクトリ内にlocalhost.pem
とlocalhost-key.pem
という名前のSSL証明書ができます。
以下のように配置されていればOKです。.gitignoreでSSL証明書を無視
SSL証明書はgitで管理したくないので、.gitignoreに追記します。
(省略) /config/certs/*pumaの設定ファイルでSSL証明書を指定する
config/puma.rb
の12行目くらいに、httpでのpumaのサーバーを3000番のポートで起動するという設定の一行があります(port ENV.fetch("PORT") { 3000 }
)。
httpsでアクセスできるようにしたい今、これはもはや必要ないのでコメントアウトし、以下のように3000番の座を乗っ取りましょう。config/puma.rb(省略) # Specifies the `port` that Puma will listen on to receive requests; default is 3000. # # port ENV.fetch("PORT") { 3000 } ssl_bind "0.0.0.0", "3000", { cert: "config/certs/localhost.pem", key: "config/certs/localhost-key.pem" }アクセスしてみる
あとはいつもどおりサーバーを立ち上げて
https://localhost:3000
にアクセスするだけです(httpではなくhttpsです!)。$ rails serverプライバシーポリシーを載せたURLを指定する
プライバシーポリシーとは、収集した情報をこれこれこういう目的で使いますよという旨が書かれた文書のことです。とりあえず開発時にはアクセスできるサイトであればなんでもよいです。アプリケーションを公開する段階になったら、忘れずに自分のアプリケーション内にプライバシーポリシーを載せたページを作り、それを指定しましょう。
facebookの開発者用管理ページに以下のようにURLを設定しておきます。
プライバシーポリシーのURLの設定は以上です!簡単!
確認
https://localhost:3000
にアクセスすると、サインインのページに遷移し、そこに「Sign in with Facebook」というリンクが表示されているはずです。これをクリックするとFacebookの認証画面が現れて…。自分のメールアドレスが表示されたでしょうか?できたはずです。きっと…。
[+α] deviseで使われるビューファイルを確認する
deviseで作成される諸々のユーザー認証のページは、そのままでは見ることもできません。
しかし以下の設定とコマンドで、ユーザー認証まわりのビューファイルを確認し、カスタマイズすることができるようになります。
config/initializers/devise.rb
の238行目を以下のように書き換えます。config/initializers/devise.rbconfig.scoped_views = true
config/initializers
ディレクトリの中に入っているファイルを変更したので、もしサーバーを立ち上げていたらサーバーを再起動してください。このディレクトリの中のファイルはサーバー立ち上げ時にだけ読み込まれるからです。続いて、ビューファイルを作成します。
$ rails g devise:views usersこうしてできたビューファイルのうち、
app/views/users/shared/_links.html.erb
を見てみると、下の方に以下のような記述があります。これがSign in with Facebook
などと表示してくれる部分です。app/views/users/shared/_links.html.erb<%- if devise_mapping.omniauthable? %> <%- resource_class.omniauth_providers.each do |provider| %> <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br /> <% end %> <% end %>deviseで作成したモデルにomniauthableというオプションがついていれば、この部分が表示され、サインインボタンが表示されるようになっています。今回はデザインまではいじりませんが、かっこいいユーザー認証ページを作成したければここを変えればいいということを覚えておいてください。
- 投稿日:2019-02-15T22:19:31+09:00
RailsでFacebookログインする
はじめに
FacebookでOmniAuthでユーザー認証しましょう。かっこいいからです。
似たような記事はたくさんありますが、Facebookの仕様変更などで、記事単体では実装が完了しないものばかりだったので改めて書くことにしました。まずdeviseのみで認証機能を実装
以下のサイトを参考につくります。
【Railsのアプリ開発】初心者でもわかる!deviseでログイン機能を実装する使い方暇があれば上の内容も自分でしっかり解説して書きたいところですが、「暇があれば」などと言うのは大体やらない兆しです。期待しないでください。
ユーザー一覧ページの作成
認証ページだけ作っても寂しいので、ユーザー一覧ページを作っておくと良いでしょう。
$ rails g controller usersこれで作成されるファイルのうち、コントローラーとビューを以下のように変更して、ユーザー一覧ページを作成します。
app/controllers/users_controller.rbclass UsersController < ApplicationController before_action :authenticate_user! def index @users = User.all end endapp/views/users/index.html.erb<% @users.each do |u| %> <div class="user_field"> <%= link_to u.email, destroy_user_session_path, method: :delete %> </div> <% end %>一覧表示されたユーザーのメールアドレスをクリックするとサインアウトするようにしました。
最後に、このusers#indexアクションへのルーティングを設定しておきます。
config/routes.rbRails.application.routes.draw do # 省略 resources :users, only: [:index] root "users#index" endサインイン後にはルートパスにリダイレクトされるので、簡単にサインインできたかどうかの確認ができるように、"users#index"をルートパスに設定しました。
Facebookでのサインインに成功すれば、ユーザー一覧のページに遷移し、そこに自分がFacebookに登録したメールアドレスが表示されるはずです。omniauthを実装
再び以下のサイトを参考に。
【開発メモ】RailsアプリでFacebookログインの認証機能を実装させる方法暇があれば。
Facebookの変更に対応
2019/2/15時点で、これだけではまだ足りません。
Facebook側の仕様変更で、以下が必須になりました。
- アプリケーションにhttpsでアクセスするように設定する
- プライバシーポリシーを載せたURLを指定する
順にやっていきます。
アプリケーションにhttpsでアクセスできるように設定する
httpsでアクセスできるようにするには、アプリケーションサーバーがSSL証明書というものを持っていないといけません。SSL証明書にはグレードがあり、グレードの高いものほどサイトの安全性を保証できるのですが、それらは発行するのに認証局にたくさんお金を払わなければなりません。
しかしグレードの低いもので良ければ、自分で作成することができます。自分で作成といってもよくわからないので、SSL証明書の作成はmkcertを使って楽にやってしまいましょう。また、RailsのアプリケーションサーバーとしてPumaを使えば、SSL証明書に関するなんやかんやをいい感じにやってくれます。
PumaはRails5では標準のアプリケーションサーバーなので、これに関しては特にややこしいことはありませんが、何かこだわりや制約があって他のアプリケーションサーバーを使う場合はブラウザバックです。mkcertでSSL証明書を作成
公式GitHub: FiloSottile/mkcert
READMEを読んで、mkcertをインストールします。
僕のパソコンはmacなので、Homebrewを使います。$ brew install mkcert $ mkcert -install自分のRailsアプリケーションの適当な場所にSSL証明書を置くディレクトリを作り、SSL証明書を作成します。
$ mkdir config/certs && cd config/certs $ mkcert localhostこれで、
config/certs
ディレクトリ内にlocalhost.pem
とlocalhost-key.pem
という名前のSSL証明書ができます。
以下のように配置されていればOKです。.gitignoreでSSL証明書を無視
SSL証明書はgitで管理したくないので、.gitignoreに追記します。
(省略) /config/certs/*pumaの設定ファイルでSSL証明書を指定する
config/puma.rb
の12行目くらいに、httpでのpumaのサーバーを3000番のポートで起動するという設定の一行があります(port ENV.fetch("PORT") { 3000 }
)。
httpsでアクセスできるようにしたい今、これはもはや必要ないのでコメントアウトし、以下のように3000番の座を乗っ取りましょう。config/puma.rb(省略) # Specifies the `port` that Puma will listen on to receive requests; default is 3000. # # port ENV.fetch("PORT") { 3000 } ssl_bind "0.0.0.0", "3000", { cert: "config/certs/localhost.pem", key: "config/certs/localhost-key.pem" }アクセスしてみる
あとはいつもどおりサーバーを立ち上げて
https://localhost:3000
にアクセスするだけです(httpではなくhttpsです!)。$ rails serverプライバシーポリシーを載せたURLを指定する
プライバシーポリシーとは、収集した情報をこれこれこういう目的で使いますよという旨が書かれた文書のことです。とりあえず開発時にはアクセスできるサイトであればなんでもよいです。アプリケーションを公開する段階になったら、忘れずに自分のアプリケーション内にプライバシーポリシーを載せたページを作り、それを指定しましょう。
facebookの開発者用管理ページに以下のようにURLを設定しておきます。
プライバシーポリシーのURLの設定は以上です!簡単!
確認
https://localhost:3000
にアクセスすると、サインインのページに遷移し、そこに「Sign in with Facebook」というリンクが表示されているはずです。これをクリックするとFacebookの認証画面が現れて…。自分のメールアドレスが表示されたでしょうか?できたはずです。きっと…。
[+α] deviseで使われるビューファイルを確認する
deviseで作成される諸々のユーザー認証のページは、そのままでは見ることもできません。
しかし以下の設定とコマンドで、ユーザー認証まわりのビューファイルを確認し、カスタマイズすることができるようになります。
config/initializers/devise.rb
の238行目を以下のように書き換えます。config/initializers/devise.rbconfig.scoped_views = true
config/initializers
ディレクトリの中に入っているファイルを変更したので、もしサーバーを立ち上げていたらサーバーを再起動してください。このディレクトリの中のファイルはサーバー立ち上げ時にだけ読み込まれるからです。続いて、ビューファイルを作成します。
$ rails g devise:views usersこうしてできたビューファイルのうち、
app/views/users/shared/_links.html.erb
を見てみると、下の方に以下のような記述があります。これがSign in with Facebook
などと表示してくれる部分です。app/views/users/shared/_links.html.erb<%- if devise_mapping.omniauthable? %> <%- resource_class.omniauth_providers.each do |provider| %> <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br /> <% end %> <% end %>deviseで作成したモデルにomniauthableというオプションがついていれば、この部分が表示され、サインインボタンが表示されるようになっています。今回はデザインまではいじりませんが、かっこいいユーザー認証ページを作成したければここを変えればいいということを覚えておいてください。
- 投稿日:2019-02-15T22:15:09+09:00
rails generate controllerで同時にいくつ作れるのか気になった話
オレ generate スキ
コマンド一つで必要なものがザッと作れるgenerate、ほんと好き。
生産性が高いってこういうことなんですかね?と入門したばかりなのに楽しくて仕方がない。
そこでふと気になったんですよ、「アレっていくつくらい同時に作れるのかなぁ?」って。
そんな小学生のような疑問を大切にしていきたい今日このごろ。環境
- cloud9
- Rails 5.2.2
とりあえずアルファベットを1巡してみよう
ググって1ページ目にそれっぽいものがなかったのでとりあえずアルファベット並べてみました。
$ rails generate controller sample a b c d e f g h i j k l m n o p q r s t u v w x y zこんなに同時に作るプロジェクトあるのかなぁ…。
知的好奇心を満たしたいだけなので疑問をスポイル。
流石に多すぎって怒られるかなぁ?と思いながらEnterぽちー!$ rails generate controller sample a b c d e f g h i j k l m n o p q r s t u v w x y z Running via Spring preloader in process 4430 create app/controllers/sample_controller.rb route get 'sample/a' get 'sample/b' get 'sample/c' get 'sample/d' get 'sample/e' get 'sample/f' get 'sample/g' : (中略) : invoke coffee create app/assets/javascripts/sample.coffee invoke scss create app/assets/stylesheets/sample.scssマ?
通っちゃったよ。
じゃあもう1巡、つまりアルファベット52文字なら?$ rails generate controller sample a b c d e f g h i j k l m n o p q r s t u v w x y z aa bb cc dd ee ff gg hh ii jj kk ll mm nn oo pp qq rr ss tt uu vv ww xx yy zz Running via Spring preloader in process 4570 create app/controllers/sample_controller.rb route get 'sample/a' get 'sample/b' get 'sample/c' get 'sample/d' get 'sample/e' get 'sample/f' get 'sample/g' : (中略) : invoke assets invoke coffee create app/assets/javascripts/sample.coffee invoke scss create app/assets/stylesheets/sample.scssウッソだろお前!
ということで、そこそこたくさんを一回でgenerateできそうです。おまけ:最後の一撃はせつない
消す時はgenerateをdestroyに書き換えて実行。
$ rails destroy controller sample a b c d e f g h i j k l m n o p q r s t u v w x y z aa bb cc dd ee ff gg hh ii jj kk ll mm nn oo pp qq rr ss tt uu vv ww xx yy zz
まぁブランチ切っといて、ブランチごと捨てる方が楽だけどさ
- 投稿日:2019-02-15T21:31:42+09:00
get post アクション
- 投稿日:2019-02-15T20:04:36+09:00
比較演算子
- 投稿日:2019-02-15T20:03:09+09:00
変数展開
- 投稿日:2019-02-15T18:40:36+09:00
Docker Rails pry-byebug で pry 入力できなかった時
*メモ書きです。
docker-compose.ymlweb: ... + tty: true + stdin_open: true上記の tty: true stdin_opne: true を追加することで解決しました。
- 投稿日:2019-02-15T17:16:23+09:00
rails で セレクトタグの生成
Railsでセレクトタグの生成
今回、ECサイトの買い物かご的な物を再現してみようと思い作成していた所、少々分かりづらかった所があったので記事にしてみました。
select_tag
Rails ドキュメント
http://railsdoc.com/references/selectここに説明が載っているものの、僕には理解が難しかった・・・
select_tagの使い方
ドキュメントには、
select_tag(要素名, タグを表す文字列 [, オプション])の様に書かれていました。
色々試してみた所、要素名の所で指定した値がname属性として送信され、
params[:要素名]で値を取得できるようです。
値の作成
Railsドキュメント
http://railsdoc.com/references/options_for_selectセレクトタグの値を作成する場合は、options_for_selectを使います。
<%= select_tag("num", options_for_select((タグの配列 or ハッシュ)) %>とすることで値を設定できます。
今回は1から100までの値を設定したので、
<%= select_tag("num", options_for_select((1..100)) %>この様に記述しました。
selected設定
今回は、買い物かごの作成ということだったので、購入予定の個数設定をしておかなくてはならないためselected指定をする必要がありました。
これは、options_for_selectの:selectedオプションを使用することで可能になります。
そのため、options_for_selectの第2引数に
<%= select_tag("num", options_for_select((1..100) , :selected => item.item_number) ) %>とすることで、購入予定数をselected指定しました。
上記の様に、
:selected => 値とすることで、指定ができます。
感想
ドキュメントを読むのは難しい・・・
言葉の定義など、理解があいまいな部分が多く、
用語を明確に覚える必要があると感じた。
- 投稿日:2019-02-15T16:24:27+09:00
【初学者】Ruby on Rails にて rails s できず Usage: rails new APP_PATH [options]と表示される場合 のメモ
*メモ書きです。
*ディレクトリが違うため下記コードが出力される
渡しの場合は cd で 1階層下に行くことで解决しました。
ディレクトリをもう1度見直すことで解決できるかもしれません。comandline.toolsUsage: rails new APP_PATH [options] Options: [--skip-namespace], [--no-skip-namespace] # Skip namespace (affects only isolated applications) -r, [--ruby=PATH] # Path to the Ruby binary of your choice # Default: /Users/mu/.rbenv/versions/2.5.1/bin/ruby -m, [--template=TEMPLATE] # Path to some application template (can be a filesystem path or URL) -d, [--database=DATABASE] # Preconfigure for selected database (options: mysql/postgresql/sqlite3/oracle/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc) # Default: sqlite3 [--skip-yarn], [--no-skip-yarn] # Don't use Yarn for managing JavaScript dependencies [--skip-gemfile], [--no-skip-gemfile] # Don't create a Gemfile -G, [--skip-git], [--no-skip-git] # Skip .gitignore file [--skip-keeps], [--no-skip-keeps] # Skip source control .keep files -M, [--skip-action-mailer], [--no-skip-action-mailer] # Skip Action Mailer files -O, [--skip-active-record], [--no-skip-active-record] # Skip Active Record files [--skip-active-storage], [--no-skip-active-storage] # Skip Active Storage files -P, [--skip-puma], [--no-skip-puma] # Skip Puma related files -C, [--skip-action-cable], [--no-skip-action-cable] # Skip Action Cable files -S, [--skip-sprockets], [--no-skip-sprockets] # Skip Sprockets files [--skip-spring], [--no-skip-spring] # Don't install Spring application preloader [--skip-listen], [--no-skip-listen] # Don't generate configuration that depends on the listen gem [--skip-coffee], [--no-skip-coffee] # Don't use CoffeeScript -J, [--skip-javascript], [--no-skip-javascript] # Skip JavaScript files [--skip-turbolinks], [--no-skip-turbolinks] # Skip turbolinks gem -T, [--skip-test], [--no-skip-test] # Skip test files [--skip-system-test], [--no-skip-system-test] # Skip system test files [--skip-bootsnap], [--no-skip-bootsnap] # Skip bootsnap gem [--dev], [--no-dev] # Setup the application with Gemfile pointing to your Rails checkout [--edge], [--no-edge] # Setup the application with Gemfile pointing to Rails repository [--rc=RC] # Path to file containing extra configuration options for rails command [--no-rc], [--no-no-rc] # Skip loading of extra configuration options from .railsrc file [--api], [--no-api] # Preconfigure smaller stack for API only apps -B, [--skip-bundle], [--no-skip-bundle] # Don't run bundle install [--webpack=WEBPACK] # Preconfigure for app-like JavaScript with Webpack (options: react/vue/angular/elm/stimulus) Runtime options: -f, [--force] # Overwrite files that already exist -p, [--pretend], [--no-pretend] # Run but do not make any changes -q, [--quiet], [--no-quiet] # Suppress status output -s, [--skip], [--no-skip] # Skip files that already exist Rails options: -h, [--help], [--no-help] # Show this help message and quit -v, [--version], [--no-version] # Show Rails version number and quit Description: The 'rails new' command creates a new Rails application with a default directory structure and configuration at the path you specify. You can specify extra command-line arguments to be used every time 'rails new' runs in the .railsrc configuration file in your home directory. Note that the arguments specified in the .railsrc file don't affect the defaults values shown above in this help message. Example: rails new ~/Code/Ruby/weblog This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
- 投稿日:2019-02-15T14:52:24+09:00
rails rename column
rename_column :table_name, :before_column_name, :after_column_name
- 投稿日:2019-02-15T14:52:24+09:00
rails rename column migration
- 投稿日:2019-02-15T14:18:52+09:00
reCAPTCHAを中央寄せしたい
初期では左寄せされる
Railsで実装したので
= recaptcha_tags
をビューに記述するだけで表示されました。
しかし左寄せで表示されてしまい、不恰好なので中央寄せさせたいです。CSSで中央寄せにする
検証してみるとクラス g-recaptchaを持ったdivタグの下に配置されていることがわかったので、そのクラスにCSSを当てる。
下記のコードで中央寄せすることが可能。
中央寄せとは関係ないがパスワードの入力フォームと近かった為、margin-topで離している。reCAPTCHA.css.g-recaptcha { margin-right:auto; margin-left:auto; text-align: center; width:300px; margin-top:20px; }最終的に
- 投稿日:2019-02-15T13:44:18+09:00
メモ:RailsのActionMailerでテキストメールを自動生成する
この記事は
- 技術メモです
やりたかったこと
- RailsのActionMailerを使ってメールを送信しているサービスがあります
- そこですでにHTMLメールを送信しているのですが、一部メーラでHTMLメールは受信できないという話がありました
- そこで全メールについてTEXTとのマルチパートメールで送出する必要がでてきました
普通にやると
- 既存のHTMLメールのテンプレートに加えて、TEXTメールのビューテンプレートも作成するとマルチパートで送信することが可能です
- しかし、TEXT/HTMLのビューテンプレートを両方メンテナンスしていくのは結構きついです
actionmailer-text gem
- actionmailer-textを使うと、自動的にHTMLメールからタグを除去していい感じにテキストメールを送出してくれます
- こんな感じっぽく動きます
<br/>
は改行に置換- リンクは
リンク文字列(URL)
みたいな感じに置換- そのほかの普通のタグは除去
- このへんを見るとなんか一生懸命正規表現で置換してるっぽい
使い方
- gemを入れます
Gemfilegem 'actionmailer-text'
- application_mailerに所定のモジュールをincludeします
application_mailer.rbclass ApplicationMailer < ActionMailer::Base # 追記 include ActionMailer::Text end
- ちなみにdeviseを使っている場合、deviseから送られるメールはApplicationMailerを継承していないことがあるので、devise設定ファイルで指定します
config/initializers/devise.rbconfig.parent_mailer = 'ApplicationMailer'
- 以上で普通に全てのメールがTEXTとHTMLのマルチパートメールになって送信されます
終わりに
- ガラケーとかのテキストしか受けられないメーラ爆発しろ
- 投稿日:2019-02-15T13:39:25+09:00
[rails] モデルに存在しない値をjsonフォーマットで返却する方法
概要
モデルに存在しない値をjsonフォーマットで返却したい場合どうするのか。
答えは、アクション関数のrender json
する際にto_json
を使いmethods
のオプションにモデルの任意の関数を指定してあげればいいです。言葉では伝えづらいので、、実際にやってみた結果を御覧ください。
改修前
Reportのスキーマがどうなっているかは説明を省きますが、
コントローラーで以下のようなアクションの実装をしていて、reports.jsonにGETリクエストするとモデルの内容をjsonで出力してくれます。reports_controller.rb# GET /reports # GET /reports.json def index @reports = Report.all respond_to do |format| format.html { render :index } format.json { render json: @reports, status: :ok } end endreports.json[ { "id": 4, "text": "hoge", "created_at": "2019-02-13T11:16:23.000+09:00", "updated_at": "2019-02-13T11:16:23.000+09:00", "deleted_at": null } ]改修後
では、実際にどう実装するかをやってみます。
まずは、モデル側に任意の関数を実装してください。以下の関数ではcreated_atの値を日本人がわかりやすい日時の文字列フォーマットに変換しています。report.rbclass Report < ApplicationRecord # 省略 def created_at_formatted self.created_at.strftime("%Y年%-m月%-d日") end end次に、アクションの実装の
render json
してあげている箇所を以下のように変更してあげます。reports_controller.rb# GET /reports # GET /reports.json def index @reports = Report.all respond_to do |format| format.html { render :index } format.json { render json: @reports.to_json(methods: :created_at_formatted), status: :ok } end end- format.json { render json: @reports, status: :ok } + format.json { render json: @reports.to_json(methods: :created_at_formatted), status: :ok }そうしますと以下のようにモデルには存在しない値をjsonで返却することができました。
reports.json[ { "id": 4, "text": "hoge", "created_at": "2019-02-13T11:16:23.000+09:00", "updated_at": "2019-02-13T11:16:23.000+09:00", "deleted_at": null, "created_at_formatted": "2019年2月13日" } ]以上になります。
- 投稿日:2019-02-15T12:37:05+09:00
GAEでRailsのstaging環境を作った
概要
今関わっているプロジェクト(Rails)でGAE上にstaging環境を作ることになったが、
設定値周りでちょっと苦労したので構築にあたっての設定内容を残す。Staging環境
Rails詳しくないのでstaging環境の作り方を調べたところ、大きく
- Rails.envにstagingを追加(enviroments/staging.rb)
- Rails.envはproductionで、設定値を切り替える
の2通りがある模様だが、1個目のRails.env追加の方は色々問題もあって(理由は備考に)、今回は2個目を採用。
2個目の方式の場合、production/stagingといった環境がRails.envとは独立した概念になるため、envという単語がどちらを指してるのが分かりづらい。
ここではproduction/stagingなどで区別するenvをproject_envと呼ぶことにする。
project_envの設定値管理
設定ファイルの管理方法自体は大きく3通りあった。
- 設定ファイル
- 環境変数
- credentials (Rails5.2より導入)
色々検討した結果「1. 設定ファイル」の方式を採用することに(長くなったので検討は備考に)
今回はgemのrailsconfig/configを使用する。
config/以下にsettings.ymlというファイルを用意するが、大元のsettings.yml以外にも
config/settings/development.yml config/settings/production.ymlといった環境ごとのファイルが用意できる他、
config/settings.local.yml config/settings/development.local.yml config/settings/production.local.ymlなどローカル(というかファイルが置いてあるプロジェクト)用の設定ファイルも読み込んでくれる。
ちなみに設定は以下の順序で、下の方が優先になるとのこと。
config/settings.yml config/settings/#{environment}.yml config/environments/#{environment}.yml config/settings.local.yml config/settings/#{environment}.local.yml config/environments/#{environment}.local.yml基本的には、
- 全体やenvごとに固定したい値は、localじゃないファイルに記載してcommit
- その環境(project_env)でのみ使いたい値は、localファイルに記載しつつ.gitignoreに追加してcommitはしない
- 秘密情報はlocalファイルに加える。env共通だったとしてもproject_envごとに管理する
といった方針で管理。
3番目の秘密情報については、運用上あまりenv共通になることはなかったのでproject_envごとで問題はなかった。
デプロイ
GAEを使っているのでCloudBuildでデプロイを行う。
以下のようなcloudbuild.yamlを用意しつつ、CloudBuild側でトリガー設定を行う。
steps: - name: 'gcr.io/cloud-builders/gsutil' args: ['cp', 'gs://${_BUCKET}/config/*', './config/'] - name: 'gcr.io/cloud-builders/gcloud' args: ['app', 'deploy', 'app-${_PROJECT_ENV}.yaml'] substitutions: _PROJECT_ENV: dev1. gsutil
- name: 'gcr.io/cloud-builders/gsutil' args: ['cp', 'gs://${_BUCKET}/config/*', './config/']CloudBuildのトリガー設定を行うと、cloudbuild.yaml上では紐づけたbranchのコードがすでに展開された状態になっているので、その状態に対しての操作を書くことができる。
このため、GCSにsettings.local.ymlを配置しておきgsutilで配布することで、コミットしていないファイルもrails側に配布することができる。
今回は他にも配布したいファイルがあったため、それらまるごとrailsのconfig以下に配布するようにした。
配置したGCSのバケット名は、トリガーの代入変数の_BUCKETで設定しておく。
また、cloudbuildのサービスアカウントがgcsに触れる必要があるので、IAMでストレージのオブジェクト閲覧権限も設定しておく。
2. deploy
- name: 'gcr.io/cloud-builders/gcloud' args: ['app', 'deploy', 'app-${_PROJECT_ENV}.yaml']gsutilでrails環境ができたので、gcloud app deployコマンドを実行。
共通のapp.yaml一個で複数にデプロイしてもよいが、運用上はproject_envごとにapp.yamlを分けて作成した方が便利なことが多そう。
開発はしょぼいインスタンスで、本番はちゃんとしたスペックのもの、とかを切り分ける場合にはapp.yamlでの切り分けが必要になってくる。上記のコマンドの場合、app-stg.yamlなどのファイルを用意しておき、トリガーの代入変数にも_PROJECT_ENVを設定しておく。
あとはトリガー設定がうまく行っていれば、branchをpushして
まとめ
ということで、GAEでRailsのstaging環境を作成したときのメモでした。
基本的には
- settings.local.ymlを用意
- GCSに配置
- CloudBuildでgcsからファイルを持ってくる処理を追加
でうまくいく気がする。
あとは秘密情報に関してはバケット権限を考慮しつつ、どうしても回避が難しければCloud KMSを使っていく感じか。
いつも文章多めなので、図とかもっと増やしたい....
備考1: Rails.env追加の問題点
Railsでenvを追加してみると、自分でロジックを追加するのは簡単だが、Rails自体が他のenvを想定していないことが多い。
一例を上げるとsecret_key_base取得は以下のような実装になっていて、development/testとそれ以外で挙動が分かれていたりする。
def secret_key_base if Rails.env.test? || Rails.env.development? secrets.secret_key_base || Digest::MD5.hexdigest(self.class.name) else validate_secret_key_base( ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base ) end enddatabase.yml等はenvごとに接続設定を管理するので、同じdevelopmentでもローカル用と共有用で項目を分けるため、localというenvを追加した。
上記のsecret_key_baseのようなRails本体で分岐しているところは流石にどうしようもなく、都度env対応をする羽目に。
stagingを作る目的は本番相当の環境での動作確認なので、ロジックが違う事態は避けたい。
ということでRails.envはいじらずに、別途project_envの概念を持ち込むことに。備考2. 設定ファイルの管理方式検討
1. 設定ファイル
設定値をyml等で管理して、コード側でそれを呼び出す簡易的な変数管理
railsconfig/configというgemが有名のようで、
- Settings.hoge.fugaなど階層データを扱え、呼び出しもdotつなぎで楽
- settings.yml他、envごとのymlやsettings.local.ymlというローカルのみ有効な設定ファイルも持てる
など色々利点があった。
今回はconfigを採用し、project_envごとにsettings.local.ymlを用意してGCS等に配置し、コードと一緒に配ることで反映する方式を採用することに。
2. 環境変数
システム環境変数(ENV)を使う方式
gemとしてはdotenvが有名とのことただ、設定を階層構造にしづらく(_でつなぐとかで無理やりやる?)、設定管理が大変になりそうなので断念。
3. credentials
rails5.2から導入された機能。
1や2の方式では、接続用の鍵情報やDBパスワードなどの秘密情報をどう管理するかが懸念だが、これは設定ファイルを暗号化することでコミットできるので、git上などで履歴管理ができる。公式はproductionにしか使えないが、Rails.envごとに分けられるrails-env-credentialsというgemも登場していて、Rails.envごとに設定を分けられる。
ただ今回はproject_envが違う設定ファイルを用意したいので、Rails.envが同じ場合にファイル分けが別途必要になってしまう。
結局暗号化されたファイルをgit上で管理できる利点よりも、暗号鍵や設定ファイルの用意や編集の手間がかかる欠点が大きいと判断し断念。
- 投稿日:2019-02-15T11:19:53+09:00
Rails × Mountain View(マウンテンビュー)で作るCSSスタイルガイド&コンポーネント
はじめまして。
Mountain View導入の経緯
普段 Ruby On Railsでプロダクトを開発しており、gemで完結するCSSのスタイルガイドを探していました。
有名なgemをいくつか素振りしてみたのですが、LivingStyleGuideはスタイルガイドを簡単にカテゴリ分けできず、Hologramはメンテナンスコストが高そうに感じました。
そんな時に、Railsのビューコンポーネントをそのままスタイルガイド化できるMountainViewと言うgemを知りました。
Mountain Viewとは
https://github.com/devnacho/mountain_view
With Mountain View you create reusable components for your Rails frontend, while generating a living style guide.
Mountain Viewを使用すると、スタイルガイドを生成しつつ、Railsフロントエンド用の再利用可能なコンポーネントを作ることができます。
この記事で紹介すること
紹介しておいてなんですが、私はパフォーマンス上の理由からMountain Viewのコンポーネント機能をそれほど使っていません。
(コンポーネントはRailsのパーシャルに任せれば済む話で、どちらかと言うとスタイルガイドとしての機能が欲しい...)この記事では私がMountain Viewを導入し、コンポーネントとして使用することを諦め、スタイルガイドとして使用することに落ち着くまでに試行錯誤した内容をまとめています。
javascriptを使ったモダンなフロントエンド開発からは遠い話になりますのでご容赦ください。
導入 ~ スタイルガイドの作成
Rails 5.2.1環境で公式のREADMEだけを参考に導入することができました。
まずは
Gemfile
にmountain_view
を追加します。# コンポーネント機能を利用する場合はグローバルに読み込みます gem 'mountain_view'
bundle install
を実行し、routes.rb
ファイルに次の行を追加します。mount MountainView::Engine => "/mountain_view" if Rails.env.development?下記のコマンドでMountain Viewの新しいコンポーネントを作成します。
rails generate mountain_view:component buttonすると、次のようなディレクトリとファイルが作成されます。
app/ components/ button/ _button.html.erb button.css button.js button.yml拡張子にscssやslimなど、Railsで使っているプリプロセッサを使うことができます。
rails s
でサーバーを立ち上げてみましょう。
ローカル環境からbuttonコンポーネントのスタイルガイドのページが作成されていることが確認できると思います。
http://localhost:3000/mountain_viewi18n対応
i18n対応で日本語化(default_localeをjaに変更)していた場合、Mountain Viewにja.ymlが存在しないためtitleタグの表示で下記のようなエラー出ているかもしれません。
<title><span class="translation_missing" title="translation missing: ja.mountain_view.layout.styleguide_title">Styleguide Title</span></title>私はこちらの en.ymlファイルの内容をコピペした
config/locales/mountain_view.ja.yml
のようなファイルを作成しました。buttonコンポーネントを作ってみる
ここでは
bootstrap
を使用してコンポーネント作りを試してみます。
Gemfile
に以下を追加してbundle install
します。gem 'bootstrap'buttonコンポーネントのscssでbootstrapを読み込みます。
components/button/button.scss@import "bootstrap";bootstrapのbuttonコンポーネントをMountainViewに反映させた例です。
app/components/button/_button.html.erb<button type="button" class="btn <%= properties[:modifire] %>"> <%= properties[:title] %> </button>app/components/button/button.yml- :modifire: btn-primary - :modifire: btn-secondary - :modifire: btn-success - :modifire: btn-danger - :modifire: btn-warning - :modifire: btn-info - :modifire: btn-light - :modifire: btn-darkキャッシュの問題
Mountain ViewではCSSの更新やコンポーネントの作成を行った後にキャッシュが残ってしまい、下記のコマンドを実行しないとコンポーネントのデザインがうまく反映されないことがありました。
bin/rake tmp:cache:clearbuttonコンポーネントを使ってみる
定義したコンポーネントは
render_component
メソッドを使用することで使うことができます。
第一引数にコンポーネント名、第二引数にハッシュ値を渡して使います。<%= render_component("button", { title: "Btn Primary", modifire: "btn-primary" }) %>コンポーネントにブロックを渡し、
properties[:yield]
で読み込んで使用することもできます。app/components/button/_button.html.erb<button type="button" class="btn <%= properties[:modifire] %>"> <%= properties[:yield] %> </button>使い方.html.erb<%= render_component("button", {modifire: "btn-primary" }) do %> Btn Primary <% end %>プレゼンターを使ってみる
コンポーネントの階層に
{コンポーネント名}_component.rb
ファイルを追加してMountainViewコンポーネント用のプレゼンターを定義することができます。app/ components/ button/ _button.html.erb button.css button.js button.yml + button_component.rbMountainView::Presenterを継承して使います。
プロパティのデフォルト値なども使用できます。app/components/button/button_component.rbclass ButtonComponent < MountainView::Presenter properties :modifire, :title property :element, default: 'btn' def modifire_title title || properties[:modifire].titleize end end定義したメソッドやプロパティをコンポーネントのパーシャルで利用することができます。
app/components/button/_button.html.erb<button type="button" class="<%= element %> <%= modifire %>"> <%= title %> </button>Railsのコンポーネント管理がMountainViewで完結して最高!
...と思ったのですが、このコンポーネント機能には、後述するパフォーマンス上の問題があるようです。MountainViewのボトルネック
MountainViewのrender_component機能をeachすると、パフォーマンスがとても残念なことになってしまいます。
これを避けるために公式READMEではMountainViewのプレゼンターでrenderメソッドをオーバーライドする方法を紹介しています。しかし、個人的にはそれよりも素直にRailsのパーシャルを使用した方がメリットが大きいなのではないかと思います。特にrender_component機能ではパーシャルのコレクション機能が使えないのが痛いので、私はeachする要素でMountain Viewのrender_component機能は使いません。
例えば、Mountain Viewを
app/components/list_item/_list_item.html.erb<%= properties[:list_item].title %>こんな風に定義するよりも、Railsのパーシャルで
app/views/components/_list_item.html.erb<%= list_item.title %>このように定義しておけば、renderをキャッシュしてくれますし、collection機能でn+1対策もできます。
使い方.html.erb<% @lists = List.all %> # @listsが100個あったら100回render <% @lists.each do |list_item| %> <%= render_component("list_item", {list_item: list_item}) %> <% end %> # @listsの結果が100個あっても1回のrenderで済む <%= render partial: 'components/list_item', collection: @lists, as: :list_item %>最高のビューコンポーネントはRailsのパーシャルでした...?
と、言うわけで私はMountain ViewをRailsコンポーネント管理用のスタイルガイドとして割り切って使うことにしました。MountainViewをスタイルガイドとして使用する
MountainViewはデフォルトではスタイルガイドのHTMLタグが表示されません。
デフォルトでprism.js
が使われているので、views/mountain_view/styleguide/show.html.erbをオーバーライドして、render_componentの記述の上部に下記のコードを追記しただけでスタイルガイドっぽくなってくれます。app/views/mountain_view/styleguide/show.html.erb... <div class="mv-component__description__properties" style="margin-bottom: 20px;"> <code class="language-html"><%= CGI::pretty("#{render_component(@component.name, component_stub.properties.clone)}") %></code> </div> ...また、MountainViewのサイドメニューがレスポンシブ表現に邪魔なので、メディアクエリで非表示にしてみました。
app/assets/stylesheets/mountain_view/layout.scss.mv-main { @media screen and (max-width: 768px) { width: 100%; padding: 30px 0; } } .mv-sidebar { @media screen and (max-width: 768px) { display: none; } }イニシャライザでMountain Viewでグローバルに読み込みたいCSSを指定することができます。
config/initializers/mountain_view.rbMountainView.configure do |config| config.included_stylesheets = ["mountain_view/layout"] endCSS読み込みの問題
MountainViewはディレクトリ名のコンポーネントをmountain_view.css.erbでディレクトリ名と同名のcssをまとめて読み込んでいるようです。
例えばbuttonコンポーネントでbootstrapをimportした後、別のコンポーネントを作ろうとしてみたところ、button.scssでしかimportしていないbootstrapが既に読み込まれています。
MountainViewの動作がCSS設計の方針と違った場合、私はマニュフェストファイルやレイアウトファイルをオーバーライドして調整するようにしています。
プレゼンターをスタブとして使ってしまう
Tipsとして、私は既存のコードをコンポーネント化する際、一旦Mountain Viewのプレゼンターをスタブとして一旦置いてみる方法をとっています。
app/components/post/post_component.rbclass PostComponent < MountainView::Presenter # コンポーネント作りに必要なデータを取得 def current_user User.find_by(email: 'necessary-user@exapmle.com') end endこんな感じでプレゼンターのメソッドを使うと既存のビューをコンポーネントでリプレースする工程がスムーズにいって便利です。
最後に
Railsのgemで完結するスタイルガイドを探したところ、Mountain Viewを改造しながら使っていくと言う道に辿り着きました。
もっとオススメのgemや、Mountain Viewの便利な使い方をご存知の方がいらっしゃいましたらぜひコメント欄で教えてください...?
- 投稿日:2019-02-15T10:59:56+09:00
Symbolオブジェクト
- 投稿日:2019-02-15T10:54:48+09:00
オブジェクト指向の強みは変更可能性にこそあると思った。
オブジェクト指向って再利用できるから良いってどこの記事、本にもまとめられています。
そんなの誰でもわかってるけど、それだけではいまいちピンと来ていなかった。たぶんそれは僕がオブジェクト指向ネイティブだから。
オブジェクト指向が普及していなかった時にプログラミングをしていた人からするとオブジェクト指向は画期的だったのだろう。でもそんなことは知ったこっちゃない、そうしろとプログラミング言語に言われるのだから。誰かに「あーしろ」「こーしろ」と言われるわけではない。そうしないと基本的に動かなかったり、意味不明な挙動をするのだ。無意識にできていることは素晴らしい事ではあるが、なぜそれが良いのか、どうしてそうするのかを知っていないとエンジニアとは言えない。
そんなある日クライアントにデモを見せるタイミングがあって、デモ中にこんな風にできない?あんな風だといいよね?みたいな言葉が出る。
そんなときに
「あー、それなら秒でできますよ。... リロードしてください。」
「おー!!」
みたいな体験があるとかっこいい。
オブジェクト指向で書いていると挙動の簡単な変更はすぐにできる。
しかもオプションでいろいろ変更できるようにしているとなおさら。
Javascriptのプラグインなどは基本的にoptionで簡単な挙動は変更できる。
クライアントは基本的に表面の動きを見ているので、表面の変えたいところが目の前で変わるのを見れば魔法か何かだと思ってしまうのも無理がない。エンジニアにとっては当たり前であるが、クライアント(非エンジニア)にとっては魔法に見えることが多くある。その芸を支えるのがオブジェクト指向だと思った。
単に書けるエンジニアではなく、デモで魅せられるエンジニアは強いとおもった。
- 投稿日:2019-02-15T10:27:55+09:00
Wercker × parallel_tests
why
Wercker上でのspecテスト完遂に35分ほど要するが、その時間を短縮して開発効率を改善したい。
※Wercker:Oracle提供のCIツール
what
テストを並列実行する。
how
環境Ruby:2.2.3 Rails:5.0.0.1 RSpec:3.5.2 sqlite:1.3.13local開発環境での実行
テスト並列実行用のgem "parallel_tests" を導入。
gemfile
に parallel_test を追加。Gemfilegroup :development, :test do ... gem 'parallel_tests' ... endgemパッケージをインストール。
$ bundle install
config/database.yml
に追加config/database.ymltest: database: yourproject_test<%= ENV['TEST_ENV_NUMBER'] %>テスト用DB:yourproject_testの複製
config/database.yml
の設定に応じてDBを作成。$ bundle exec rake parallel:create RAILS_ENV=testschemaコピー
$ bundle exec rake parallel:prepare[4]rpsec_test実行
$ bundle exec rake parallel:spec[4]※
[]
は並列実行させるプロセス数Wercker環境での実行
Wercker の docker内で複数DB作成
- 投稿日:2019-02-15T10:27:55+09:00
[WIP] Wercker × parallel_tests
why
Wercker上でのspecテスト完遂に35分ほど要するが、その時間を短縮して開発効率を改善したい。
※Wercker:Oracle提供のCIツール
what
テストを並列実行する。
how
環境Ruby:2.2.3 Rails:5.0.0.1 RSpec:3.5.2 MYSQL2:0.4.5local開発環境での実行
テスト並列実行用のgem "parallel_tests" を導入。
gemfile
に parallel_test を追加。Gemfilegroup :development, :test do gem 'parallel_tests' endgemパッケージをインストール。
$ bundle install
config/database.yml
に追加config/database.ymltest: database: yourproject_test<%= ENV['TEST_ENV_NUMBER'] %>テスト用DB:yourproject_testの複製
config/database.yml
の設定に応じてDBを作成。$ bundle exec rake parallel:create RAILS_ENV=testschemaコピー
$ bundle exec rake parallel:prepare[4]rspec_test実行
$ bundle exec rake parallel:spec[4]※
[]
は並列実行させるプロセス数Wercker環境での実行
WerckerのdockerコンテナにDB作成
wercker.ymlservices: - id: mysql:<version> env: MYSQL_USER: *** # DBのuser名 MYSQL_PASSWORD: *** # DBのpassword MYSQL_DATABASE: *** # DBの名前後の
rails-database-yml
コマンドはservices/env
プロパティで指定した内容のdatabase.yml
(DB名、ユーザー名、パスワードのDB)を作成。build: steps: - rails-database-ymlWerckerの同一dockerコンテナでDB複製
Initializing a fresh instance
When a container is started for the first time, a new database with the specified name will be created and initialized with the provided configuration variables. Furthermore, it will execute files with extensions .sh, .sql and .sql.gz that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. You can easily populate your mysql services by mounting a SQL dump into that directory and provide custom images with contributed data. SQL files will be imported by default to the database specified by the MYSQL_DATABASE variable.コンテナーが初めて開始されると、指定された名前の新しいデータベースが作成され、提供されている構成変数で初期化されます。 さらに、/ docker-entrypoint-initdb.dにある拡張子.sh、.sql、および.sql.gzのファイルを実行します。 ファイルはアルファベット順に実行されます。
というわけで、
/docker-entrypoint-initdb.d
にSQLファイルを置いたりすればいい感じにできます。
が、SQLファイルでは、MYSQL_DATABASE
に指定したDBに対してダンプファイルを流すだけですので、他のDBを作ったりすることはできません。参考
- 投稿日:2019-02-15T02:13:40+09:00
Vue on RailsでActive Storageを使って画像を保存する
はじめに
Rails API モードと Vue.js で作成した 自作ブログ で Active Storage を使う際に、画像の受け渡しでハマったので実装方法を残します。
実装するのは Active Storage を使って、eyecatch (アイキャッチ画像) 付きの Post (記事) を投稿できるようなサンプルです。環境
$ ruby -v ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin16] $ bundle exec rails --version Rails 5.2.2実装方法
API 部分 (Rails)
Ⅰ. サンプルアプリケーション新規作成
Rails API モードで作成します。
$ bundle exec rails new sampleapp --database=mysql --api --force $ cd sampleapp/ $ bundle exec rails db:createⅡ. Active Storage インストール
Active Storage をインストールします。
$ bundle exec rails active_storage:install $ bundle exec rails db:migrateⅢ. Post リソースの作成
今回利用する Post モデルとコントローラを作成します。
$ bundle exec rails g resource post title body:text $ bundle exec rails db:migrateⅣ. 各種ファイルの修正
各 Post に eyecatch を設定できるようにモデルを修正します。
追加する eyecatch= メソッドで、Active Storage に画像を保存します。このメソッドは、Base64 形式で受け取った image データをエンコードし、一時的に /tmp 配下に画像ファイルを作成、作成した画像ファイルをアタッチ、その後画像ファイルを削除します。
app/models/post.rbclass Post < ApplicationRecord has_one_attached :eyecatch attr_accessor :image def eyecatch=(image) if image.present? prefix = image[/(image|application)(\/.*)(?=\;)/] type = prefix.sub(/(image|application)(\/)/, '') data = Base64.decode64(image.sub(/data:#{prefix};base64,/, '')) filename = "#{Time.zone.now.strftime('%Y%m%d%H%M%S%L')}.#{type}" File.open("#{Rails.root}/tmp/#{filename}", 'wb') do |f| f.write(data) end eyecatch.detach if eyecatch.attached? eyecatch.attach(io: File.open("#{Rails.root}/tmp/#{filename}"), filename: filename) FileUtils.rm("#{Rails.root}/tmp/#{filename}") end end endモデルで追加した eyecatch= メソッドに POST で受け取る画像のパラメータを渡すように修正します。
app/controllers/posts_controller.rbclass PostsController < ApplicationController def create post = Post.new(post_params) if post.save post.eyecatch = post_params[:image] render json: post, status: :created else render json: post.errors, status: :unprocessable_entity end end private def post_params params.require(:post).permit(:title, :body, :image) end endⅤ. 動作確認
アプリケーションを起動し、curl コマンドでアイキャッチ付き Post が作成できるか確認します。
$ bundle exec rails s $ curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"post": {"title": "Sample title.", "body": "Sample body.", "image": "data:application/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAYAAACALL/6AAAACXBIWXMAADXU\nAAA11AFeZeUIAAAAgUlEQVQYlZWQMQ6DMAxFnyMGJFZCc4be/yisRYyVmDN0\niTuQULCCoH9z/PLtb/hTsi8SaA1yO85ZWHxgAqb8HuVoJAX+iKPtB17L++D+\nyN6drpOa0mj7AYBg1pmz99NmSKDiVzzmKTM/uOTYMjgQNetYuKoEqj7oCHp2\nteqn2/CVvuDZJy0n3DrVAAAAAElFTkSuQmCC\n"}}' http://localhost:3000/postscurl コマンドで作成後、Rails Console でアイキャッチが正常に追加できているか確認します。
$ bundle exec rails c irb(main):001:0> Post.find_by(title: "Sample title.").eyecatch.attached? => true # 画像のパスは以下のように取得できます。 # irb(main):002:0> app.url_for(Post.find_by(title: "Sample title.").eyecatch) # => "画像のパス"フロント部分 (Vue.js)
Ⅰ. Webpacker をインストール
webpacker gem を追加する。
Gemfilegem 'webpacker', '~> 3.5'Webpacker をインストールします。
$ bundle $ bundle exec rails webpacker:installⅡ. Vue.js をインストール
Webpacker で Vue.js をインストールします。
$ bundle exec rails webpacker:install:vueⅢ. Home ページを作成
Vue.js を返すための Home ページを作成します。
$ bundle exec rails g controller Pages HomeRoot パスに Home ページを設定します。
config/routes.rbRails.application.routes.draw do root 'pages#home' end標準の JSON ではなく、ERB を返すために ActionController::Base に修正します。
app/controllers/pages_controller.rbclass PagesController < ActionController::Base def home end endHome ページに利用する View を作成します。
$ mkdir -p app/views/pages/ $ touch app/views/pages/home.html.erbⅣ. Vue.js を利用
Vue.js を利用するための設定を行います。
app/views/pages/home.html.erb<%= javascript_pack_tag 'main' %>利用する各種ファイルを作成します。
$ touch app/javascript/packs/main.js $ touch app/javascript/packs/App.vueapp/javascript/packs/main.jsimport Vue from 'vue' import App from './App.vue' document.addEventListener('DOMContentLoaded', () => { const el = document.body.appendChild(document.createElement('main')) new Vue({ el, render: h => h(App) }) })app/javascript/packs/App.vue<template> <div id="app"> <p>投稿フォーム</p> </div> </template>Ⅴ. 投稿フォームを作成
API コールに利用する axios をインストールします。
$ yarn add axios
画像投稿するフォームを用意します。
画像は POST する前に Base64 にデコードしています。app/javascript/packs/App.vue<template> <div id="app"> <p>投稿フォーム</p> <form v-on:submit.prevent="postItem()"> <p> <label>Title</label> <input name="post.title" type="text" v-model="post.title"><br /> </p> <p> <label>Body</label> <input name="post.body" type="text" v-model="post.body"><br /> </p> <p> <label>画像</label> <input name="uploadedImage" type="file" ref="file" v-on:change="onFileChange()"><br /> </p> <input type="submit" value="Submit"> </form> </div> </template> <script> import axios from 'axios' export default { data() { return { post: {}, uploadedImage: '' } }, methods: { onFileChange() { let file = event.target.files[0] || event.dataTransfer.files let reader = new FileReader() reader.onload = () => { this.uploadedImage = event.target.result this.post.image = this.uploadedImage } reader.readAsDataURL(file) }, postItem() { return new Promise((resolve, _) => { axios({ url: '/posts', data: { post: this.post }, method: 'POST' }).then(res => { this.post = {} this.uploadedImage = '' this.$refs.file.value = '' resolve(res) }).catch(e => { console.log(e) }) }) } } } </script>Ⅵ. 動作確認
アプリケーションを起動し、投稿フォームから画像を投稿します。
http://localhost:3000/$ bundle exec rails sRails Console でアイキャッチが正常に追加できているか確認します。
$ bundle exec rails c irb(main):001:0> Post.last.eyecatch.attached? => true参考記事
https://qiita.com/ozin/items/5ec81a4b126b8ebf7a96
最後に
読んでいただいてありがとうございます。
間違っている点などがありましたら、ご指摘いただけると喜びます!