【Vue】API読み込み中にグルグル(ローディング/スピナー)を表示する
こんちには。opiyoです。
vueでデータが読み込まれるまでの時間をローディング画像/スピナー画像を表示させて急に画像が表示されてユーザーを困らせないようにしたい!
API通信中にローディング画像を表示させて通信完了したら取得したデータに切り替えたい!
こんな悩みを解決していきたいと思います。
結論から言ってしまうと
- 「vue-simple-spinner」を使う
- v-showを使って表示/非表示を制御する
API連携する際にどうしてもタイムラグが出てしまってました。ローディング画像が無いと、急にシュッとデータが表示されるで何だかなーって思っていたので、グルグルを表示する方法を調べてみました!
vueでローディング/スピナーを表示する「vue-simple-spinner」のインストール
npmの場合
npm install vue-simple-spinner --save
CDNの場合(今回こっち使います)
<script src="https://cdn.jsdelivr.net/npm/vue-simple-spinner@1.2.8/dist/vue-simple-spinner.min.js"></script>
githubはこちらから。
https://github.com/dzwillia/vue-simple-spinner
github見ると、最新は1.2.10
かなーと思って読み込むurlも変えてみたんだけどエラーになったので1.2.8
でやりました。
vueでローディング/スピナーを表示する「vue-simple-spinner」の使い方
1. ライブラリを取り込む
<script src="https://cdn.jsdelivr.net/npm/vue-simple-spinner@1.2.8/dist/vue-simple-spinner.min.js"></script>
2. コンポーネント=componentsを定義する
const Spinner = window.VueSimpleSpinner; var app = new Vue({ components: { Spinner } })
3. テンプレート呼び出し
<spinner></spinner>
サンプル
では早速、画面を表示してみましょう!
グルグル = ローディング画像がちゃんと表示されていますね。
vueでAPI通信中にローディング/スピナーを表示する
次は、より実践的なものを試してみたいと思います!
API連携中はローディング画像を表示。API連携が完了したら取得したデータを表示させる。ってのをやってみます!
1. 表示/非表示を制御するフラグを定義する
var app = new Vue({ el: "#app", data: { message: 'Vueのローディング画像を検証するよ', isLoading: true }, })
2. API通信後にフラグをfalseにする
今回はワンチャンの画像を取得できるAPIを使ってみます!
APIを取得する方法はaxios
を使い、取得後にフラグを変更させます。
mounted :function(){ target = this axios.get('https://dog.ceo/api/breeds/image/random') .then(function(response) { target.image = response.data.message; target.isLoading = false }) .catch(function(response) { console.log(response); }); }
3. フラグを関知する設定を定義する
APIで取得したワンチャンの画像 = image
を表示させます。
また、v-show
を使ってisLoading
のtrue/false
を制御します。
<div id="app"> <p>{{ message }}</p> <spinner v-show="isLoading"></spinner> <img v-show="!isLoading" :src="image" alt=""> </div>
実際に動かして見ると............
リロードすると.......
ローディング画像が表示された後に新しい画像に変わってる事が確認できますね!
今回使ったプログラム
今回使ったプログラムは、こちらのgithubにもアップしておきました。
GitHub - nakanoTaku/vue-simple-spinner: vue-simple-spinnerの検証プログラム
が、こっちにも全文書いておきます!
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <p>{{ message }}</p> <spinner v-show="isLoading"></spinner> <img v-show="!isLoading" :src="image" alt=""> </div> <!-- vue関連読み込み --> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/vue-simple-spinner@1.2.8/dist/vue-simple-spinner.min.js"></script> <script> const Spinner = window.VueSimpleSpinner; var app = new Vue({ el: "#app", data: { message: 'Vueのローディング画像を検証するよ', image: '', isLoading: true }, components: { Spinner }, mounted :function(){ target = this axios.get('https://dog.ceo/api/breeds/image/random') .then(function(response) { target.image = response.data.message; target.isLoading = false }) .catch(function(response) { console.log(response); }); } }) </script> <style> #app { margin: 20px; text-align: center; } img { width: 120px; height: 120px; } </style> </body> </html>
まとめ
vueは便利で面白いですねー。
API使って何か処理するみたいなことは多くの場面で使うだろうから、実務でも使うことが出てきそうです。
今日は、「vue-simple-spinner」を使ったローディング画像の表示方法をまとめてみました。
使い方のおさらいです。
こんな感じです。
が、vueは絶賛勉強中なので間違いあれば「マサカリ」お待ちしております!!
【Ruby on Rails】子の作成時に親のupdated_atを更新したり更新しなかったりする方法
こんちには。opiyoです。
railsでデータを
save
したりupdate
したりするとupdated_at
が更新されるけど、親データのupdated_atを更新したり、更新しないようにするにはどうすればいいの!?
こんな悩みを解決していきたいと思います。
結論から言ってしまうと
- 親データの
updated_at
を更新する: touch - 親データの
updated_at
を更新しない: no_touching
これらを使うと簡単に実現することが出来ます!
親データに紐づく子データを夜間処理で作るようなことをしてるんだけど、朝見ると親データのupdated_atが全部夜間の日付になっていました。 何も触ってないのに表示順が変わっていたので何事かと思う経験がありました...
touch
の存在は知ってたのですが、no_touching
については全く知らなかったので改めて一緒に使い方を調べてみました!
本文
事前準備
先ずは親データと子データが1 : Nになるデータを作ります。
# 親データ create_table "new_users", force: :cascade do |t| t.string "name" t.integer "age" end # 子データ create_table "posts", force: :cascade do |t| t.bigint "new_user_id" t.string "title" t.text "body" t.datetime "created_at", null: false t.datetime "updated_at", null: false end
親データ: new_user.rb
class NewUser < ApplicationRecord has_many :posts, dependent: :destroy end
子データ: post.rb
class Post < ApplicationRecord belongs_to :new_user end
では、このデータを基に実際に動かしていこうと思います。
railsのモデルでtouch
を使って親データのupdated_atも更新する
先ずはtouch
を定義します。子データのbelongs_to
にtouch: true
を設定すると、postデータが更新されると勝手にnew_userデータのupdated_at
が更新されます。
子データ: post.rb
class Post < ApplicationRecord belongs_to :new_user, touch: true end
> user.updated_at.to_s => "2019/12/16 23:23" > user.posts.create!(title: 'touchを検証するよ') (0.2ms) BEGIN Post Create (0.5ms) INSERT INTO "posts" ("title", "created_at", "updated_at", "new_user_id") VALUES ($1, $2, $3, $4) RETURNING "id" [["title", "touchを検証するよ"], ["created_at", "2020-01-14 12:59:54.286549"], ["updated_at", "2020-01-14 12:59:54.286549"], ["new_user_id", 16]] NewUser Update (0.3ms) UPDATE "new_users" SET "updated_at" = $1 WHERE "new_users"."id" = $2 [["updated_at", "2020-01-14 12:59:54.288109"], ["id", 16]] (1.7ms) COMMIT > user.updated_at.to_s => "2020/01/14 21:59"
上のログを見て欲しいのですが、postデータをcreateした後に親のnew_userデータをupdateしてるのが分かります!
子データを作成するときにno_touching
を使って親データのupdated_atを更新させない
次はno_touching
を使うとtouch
が定義されていてもupdated_atが更新されないことを確認してみようと思います。
使い方は親モデル.no_touching do hoge end
です。
> user.updated_at.to_s => "2020/01/14 22:05" > NewUser.no_touching do * user.posts.create!(title: 'no_touchingを検証するよ') * end (0.2ms) BEGIN Post Create (0.4ms) INSERT INTO "posts" ("title", "created_at", "updated_at", "new_user_id") VALUES ($1, $2, $3, $4) RETURNING "id" [["title", "no_touchingを検証するよ"], ["created_at", "2020-01-14 13:07:28.128973"], ["updated_at", "2020-01-14 13:07:28.128973"], ["new_user_id", 16]] (1.6ms) COMMIT > user.updated_at.to_s => "2020/01/14 22:05"
こちらを実行すると先ほど実行されていた、親データのnew_userデータのupdate文は走ってないのが分かると思います!
railsで親のupdated_atを更新したり更新しなかったりする方法まとめ
改めて親データのupdated_atの扱い方法をまとめてみます!
更新する
子モデル側のモデルにbelongs_to new_user, touch true
を付ける
更新しない
子データを更新する際に親モデル.no_touching do hoge end
で囲ってあげる。
以上になります。
【Ruby on Rails】時分秒を操るにはTime#changeメソッド
こんにちは。opiyoです。
今回はRailsを使った時分秒を操り方をの紹介です。
- ある一定の時間内のデータを取得したい!
- 時分秒だけじゃなくて年月日はできるの?
「1ヶ月」 = 「月初 ~ 月末」ってのはよく使うから知っているのですが、「時間」 = 「12時00分00秒 ~ 12時59分59秒」までの1時間内に登録されたデータを取得したい場面があって調べてみました。
changeメソッドで「時間」を操る
changeメソッドの引数にhour
と指定したい時間を渡します。
> Time.current.to_s => "2020/01/09 22:00" > Time.current.change(hour: 1).to_s => "2020/01/09 01:00"
changeメソッドで「分」を操る
changeメソッドの引数にmin
と設定したい分を渡します。
> Time.current.to_s => "2020/01/09 22:01" > Time.current.change(min: 30).to_s => "2020/01/09 22:30"
changeメソッドで「秒」を操る
changeメソッドの引数にsec
と設定したい秒を渡します。
※to_s
すると秒が消える....??
> Time.current => Thu, 09 Jan 2020 22:03:27 JST +09:00 > Time.current.change(sec: 59) => Thu, 09 Jan 2020 22:04:59 JST +09:00
changeメソッドで年月日を操る
Dateにもchangeメソッドは準備されていて、年月日を操ることができます。
> Date.current.to_s => "2020/01/09" > Date.current.change(year: 2019).to_s => "2019/01/09" > Date.current.change(month: 12).to_s => "2020/12/09" > Date.current.change(day: 31).to_s => "2020/01/31"
年月日を操る時は便利メソッドがある!
- 年を操る
> Date.current.to_s => "2020/01/09" > Date.current.beginning_of_year.to_s => "2020/01/01"
- 月を操る
> Date.current.end_of_year.to_s => "2020/12/31" > Date.current.beginning_of_month.to_s => "2020/01/01"
- 日を操る
> Date.current.end_of_month.to_s => "2020/01/31" > Date.current.beginning_of_day.to_s => "2020/01/09 00:00" > Date.current.end_of_day.to_s => "2020/01/09 23:59"
昔の記事で使い方まとめています! opiyotan.hatenablog.com
Railsで時分秒を操るchangeメソッドまとめ
例えば、現在の時刻を基準に「XX時00分00秒 ~ XX時59分59秒」の1時間内のデータを取得したい場合はこんな感じになるかなと思います。
start_time = Time.current.change(min: 00) end_time = Time.current.change(min: 59, sec: 59) AccessLog.where(created_at: start_time..end_time)
以上になります。
【Rails】JSONデータを返却する「gem jbuilder」の便利な使い方
こんにちは。opiyoです。
今回はJSONデータを作る際に便利な「gem jbuilder」についてです。
RailsはAPIに徹する事が世の中的に多くなってきてると思うので、JSONに接する機会は多いと思います。
そんな時に便利なjbuilder
の使い方について、実際のプログラムと共に紹介します。
こんな悩みを解決していければと思います。
gem jbuilderとは
json形式のデータを簡単に作る為のgemです。
json形式のデータを作るのに便利なgemは僕が知る限り2つあります。 - jbuilder - jb
jbuilder
の方がjsonの階層構造と同じようなイメージで作れるので非常に分かりやすい。
が、重たい。
jb
の方は逆で階層構造を自分の頭の中で組み立てて行くイメージになるので分かりづらい。
が、早い。
以前レスポンスをアップする為にjb
にチャレンジしたんだけど、ちょっと深い階層作ったりするのがどうしても出来なくて挫折した経験ありです...
gem jbuilderの基本的な使い方
では、早速色々な使い方をまとめていきたいと思います。
jbuilderのインストール
gem 'jbuilder'
基本の基本
json.hoge
で一番上の階層が作れる
json.total_pages @events.total_pages ↓ { "total_pages": 10 }
階層を下げるには?
do
を使ってブロックを作り、その中に値を書いてあげる
json.events do json.id 123 end ↓ "events": { "id": 123 }
複数件=配列の作り方
do
を使ってブロックを作りつつ、array!
でぐるぐる回すイメージ
json.events do json.array!(@events) do |event| json.id event.id end end ↓ "events": [ { "id": 1185, }, { "id": 1183, } ]
さらに深掘りするには?
これ以降は、上を組み合わせればok。
array!
の中で、do
を使えば更に深くなって行くよ
json.contents do json.array!(@items) do |t| json.id t.id // この部分だね json.title do json.label t.title end end end ↓ "contents": [ { "id": 1, "title": { "label": "テスト" } ]
gem jbuilderの便利なメソッド
extract!で簡単出力
showの時に使うことが多いかな。対象オブジェクトが1件の場合はextract!
を使って出力したいカラムをシンボルで渡してあげれば勝手にjson形式データを作っちゃうよ。
第一引数がオブジェクト、第二引数以降に出力したいカラム名をシンボルで。
json.extract! @item, :id, :title, :description, :created_at, :updated_at ↓ { "id": 1, "title": "テスト", "description": "てすと", "created_at": "2019-12-25T09:22:25.186Z", "updated_at": "2019-12-25T09:22:25.186Z" }
if文も使えちゃう!?
jbuilderの凄いところで、普通にif文とかインスタンスメソッドとか呼べちゃう!
if @event.image.present? json.image_url @event.resized_image_url json.width @event.image.width json.height @event.image.height end
json.finished @event.finished? class Event < ApplicationRecord def finished? return true if event_dates.blank? event_dates.last.date < Date.current end end
// array!はeachと同じように扱えるって思っておけばokだね! json.array!(events) do |event| if group_event == event next end json.id event.id end
ルーティングのprefixが使える
ページのURLを渡したい時はルーティングのprefixが使えちゃう。queryも付与できるからクソ便利だし、hoge_urlにしておけばrequest_urlからドメインも勝手に判断してくれる!
json.url event_url(public_id: @event.eventer.public_id, event_id: @event.id, utm_source: :test) ↓ // 勝手にlocalhost:3000を生成してくれる "url": "http://localhost:3000/events/1185?utm_source=test",
partialが使える
viewと同じようにpartial!が使えるので、共通化できる。 が、記憶が曖昧だけどpartialすると毎回renderされるので、件数が増えれば増えるだけ遅くなる。だから、partialせずに同ファイルに書いてしまった方がレスポンスは早くなる。
json.partial! 'cms_api/events/show', event: event
gem jbuilderのまとめ
様々なjsonデータの作り方について、まとめてみました。
自分が携わっているプロジェクトでは、あまり利用してないですが今どこ行ってもRails側はAPIだけで使う = jsonで返すだけ。って事が多いと思うのでjbuilderは使う場面がいっぱいあるのではないでしょうか? 僕も引き続き積極的に使っていきたいと思います!
【Ruby】色々な繰り返し処理を学ぼう(each, for, while, times, next, break)
こんにちは。opiyoです。
今回は色々なパターンで使うRubyの繰り返し処理についてです。 それぞれ微妙な違いはあれど改めて、どういう場面で何を使うのか。実際のプログラムと共に紹介します。
- for文の基本的な使い方が知りたい
- こんな時やあんな時、for文をどう使うの!?
- for文の途中で抜けたい!
こんな悩みを解決していければと思います。
rubyの each
の使い方
ごめんなさい。先にeach
を書かせてもらいます!
理由は簡単で、仕事の中でfor
を使った記憶が無いからです...
なので、基本的にこれだけ覚えておけば問題ないと思います。それぐらいeach
でほとんど事足ります。
オブジェクト.each do |変数| 繰り返し処理 end
配列の場合
strs = ['a', 'b', 'c'] strs.each do |str| puts str end ↓ a b c
ハッシュの場合
strs = {dog: '犬', cat: '猫'} strs.each do |key, value| puts "#{value}は英語で#{key}" end ↓ 犬は英語でdog 猫は英語でcat
オブジェクトの場合
データベースから取得したオブジェクトを繰り返す場合の処理です。
users = NewUser.order(id: :desc).limit 3 => <id: 16, name: "opiyo">, <id: 15, name: "cat">, <id: 14, name: "dog"> users.each do |user| puts user.name end ↓ opiyo cat dog
rangeの場合
rangeは[最小値..最大値]
のようなデータの事です。
この例だと今日から月末までの日付を出力する処理です。
# `end_of_month`はrailsで使えるメソッドです。 (Date.today..Date.today.end_of_month).each do |day| puts day end ↓ 2019/12/16 2019/12/17 2019/12/18 2019/12/19 2019/12/20 2019/12/21 2019/12/22 2019/12/23 2019/12/24 2019/12/25 2019/12/26 2019/12/27 2019/12/28 2019/12/29 2019/12/30 2019/12/31
rubyの for
の使い方
for 変数 in オブジェクト do 繰り返しの処理 end
変数に格納されたデータを1つ1つオブジェクトに渡しながらdo end
の中に書かれた処理が実行されます。
では、それぞれの場合を想定して実際に動かしてみます。
文字列の配列の場合
strs = ['a', 'b', 'c'] for strs in str do puts str end ↓ a b c
数値の配列の場合
strs = [1, 2, 3] for str in strs do puts str end ↓ 1 2 3
配列の配列の場合
strs = [['a',1], ['b',2], ['c',3]] for str in strs do puts str end ↓ a 1 b 2 c 3
ハッシュの配列の場合
strs = {dog: '犬', cat: '猫'} for str in strs do puts str end ↓ dog 犬 cat 猫
ハッシュの場合はkey
とvalue
に分けて取得することができます!
strs = {dog: '犬', cat: '猫'} # keyだけ取得する for key, value in strs do puts key end ↓ dog cat # valueだけ取得する for key, value in strs do puts value end ↓ 犬 猫
rubyの while
の使い方
while 条件 do 繰り返し処理 end
while
は、ある条件がokになるまで実行されます。
i = 0 while i <= 5 puts i i += 1 end ↓ 0 1 2 3 4
この場合ですとi
が5より大きくなるまで処理が実行されます。
注意なのは条件がokにならないと処理が永遠に続きます。
この場合は、処理の中でi
をマイナスしているので永遠に5より大きくならず無限ループになります。
i = 0 while i <= 5 puts i i -= 1 end ↓ 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 . . .
rubyの times
の使い方
繰り返す回数.times do 繰り返す処理 end
times
は繰り返したい数だけ処理します。
5.times do puts "test" end ↓ test test test test test
今何回めの処理かを判定処理の中で使いたい場合は、do
の後に|変数|
を書いてあげます。
5.times do |i| puts "#{i} 回目のtest" end ↓ 0 回目のtest 1 回目のtest 2 回目のtest 3 回目のtest 4 回目のtest
注意点は0
から始まる点です。
rubyの upto
の使い方
最小値.upto(最大値) do |i| puts 'test' end
times
と似ていますが、upto
の場合は最小値 -> 最大限まで繰り返し処理をします。
1.upto(5) do |i| puts "#{i} 番目のtest" end ↓ 1 番目のtest 2 番目のtest 3 番目のtest 4 番目のtest 5 番目のtest
rubyの downto
の使い方
最大値.downto(最小値) do |i| puts 'test' end
upto
と似ていますが、downto
の場合は最大値 -> 最小値まで繰り返し処理をします。
5.downto(1) do |i| puts "#{i} 番目のtest" end ↓ 5 番目のtest 4 番目のtest 3 番目のtest 2 番目のtest 1 番目のtest
rubyの繰り返しを制御する
繰り返し処理の中で条件に応じた処理が可能です。
rubyの繰り返しから次の処理へ(next)
2回目の繰り返しの場合はskipし次の処理を行います。
strs = [1, 2, 3] strs.each do |str| next if str == 2 puts "#{str} 番目の処理です。" end ↓ 1 番目の処理です。 3 番目の処理です。
rubyの繰り返しを終了する(break)
2回目以降の繰り返しを終了します。
strs = [1, 2, 3, 4, 5] strs.each do |str| break if str == 3 puts "#{str} 番目の処理です。" end ↓ 1 番目の処理です。 2 番目の処理です。
rubyの繰り返し処理のまとめ
様々な繰り返し処理について、まとめてみました。
正直、each
とnext
とbreak
だけ覚えておけば事足りると思いますが使う時が来れば積極的に使っていきましょう!
Dockerを使って「Rails / PostgreSQL」の開発環境を作ろう!
Docker
を使ってRuby on Railsの開発環境を作成する方法の紹介です。
こちら公式の手順になるのですが、Rubyのバージョンが2.5だったので今回2.6でチャレンジしてみます。
基本は公式通りで問題ないですが、2.6でrails new
するとRails6系がインストールされます。Rails6系ではWebpacker
が自動でインストールされる影響でそれを利用するためのyarn
をインストールする必要があります。
【Rails入門】Webpackerではじめるフロントエンド開発!Rails5.1対応 | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト
今回作成する環境
- Ruby: 2.6.5
- Rails: 6.0.0
- PostgreSQL: 12.0
環境構築
Gemfile作成
source 'https://rubygems.org' gem 'rails'
合わせて空のGemfile.lock
も作成しておきます。
Dockerfile作成
Railsアプリを作成するために必要な各種設定を記述するファイルです。
上から順番に処理されていくようなイメージですね。
FROM ruby:2.6 # `apt-get install yarn`とするとえらーになるので、以下ように。 RUN apt-get update -qq && apt-get install -y nodejs postgresql-client 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 mkdir /myapp WORKDIR /myapp COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install COPY . /myapp # Add a script to be executed every time the container starts. COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 # Start the main process. CMD ["rails", "server", "-b", "0.0.0.0"]
- RUN: コマンドの実行
- WORKDIR: 作業ディレクトリ
- COPY: ファイルのコピー
- CMD: コンテナコマンドの実行
RUNとCMSの違いはこちら。
entrypoint.sh
server.pid
が存在するときに削除するシェルファイルです。これも作成しないとエラーになりました。
#!/bin/bash set -e # Remove a potentially pre-existing server.pid for Rails. rm -f /myapp/tmp/pids/server.pid # Then exec the container's main process (what's set as CMD in the Dockerfile). exec "$@"
docker-compose.yml作成
こちらはアプリケーションを構成するサービス(web / DB)、各サービスの取得方法やポート番号など全体の構成を定義するファイルです。
version: '3' services: db: image: postgres volumes: - ./tmp/db:/var/lib/postgresql/data web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp ports: - "3000:3000" depends_on: - db
rails作成
docker-compose run web rails new . --force --no-deps --database=postgresql docker-compose build
postgresql設定
元々色々書かれていますが、一度全て消して以下だけにします。
# database.yml default: &default adapter: postgresql encoding: unicode host: db username: postgres password: pool: 5 development: <<: *default database: myapp_development test: <<: *default database: myapp_test
DBを作成します。
docker-compose run web rake db:create
アプリを起動する
ここまでで設定は完了です。
docker-compose up
localhost:3000
でRailsのウェルカムページが表示されていればokです!
その他のこと
vueをインストールする
docker-compose run web rails webpacker:install docker-compose run web rails webpacker:install:vue docker-compose build docker-compose up
typescriptをインストールする
$ docker-compose run web rails webpacker:install:typescript
webpacker:installするとエラーになる
apt-get install yarn
とすると、エラーになりました。
$ docker-compose run web rails webpacker:install Starting docker-sample_db_1 ... done rails aborted! ArgumentError: Malformed version number string 0.32+git /usr/local/bundle/gems/webpacker-4.0.7/lib/tasks/webpacker/check_yarn.rake:12:in `block (2 levels) in <main>' /usr/local/bundle/gems/railties-6.0.0/lib/rails/commands/rake/rake_command.rb:23:in `block in perform' /usr/local/bundle/gems/railties-6.0.0/lib/rails/commands/rake/rake_command.rb:20:in `perform' /usr/local/bundle/gems/railties-6.0.0/lib/rails/command.rb:48:in `invoke' /usr/local/bundle/gems/railties-6.0.0/lib/rails/commands.rb:18:in `<main>' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' /usr/local/bundle/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require' /usr/local/bundle/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' /usr/local/bundle/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require' /myapp/bin/rails:9:in `<top (required)>' /usr/local/bundle/gems/spring-2.1.0/lib/spring/client/rails.rb:28:in `load' /usr/local/bundle/gems/spring-2.1.0/lib/spring/client/rails.rb:28:in `call' /usr/local/bundle/gems/spring-2.1.0/lib/spring/client/command.rb:7:in `call' /usr/local/bundle/gems/spring-2.1.0/lib/spring/client.rb:30:in `run' /usr/local/bundle/gems/spring-2.1.0/bin/spring:49:in `<top (required)>' /usr/local/bundle/gems/spring-2.1.0/lib/spring/binstub.rb:11:in `load' /usr/local/bundle/gems/spring-2.1.0/lib/spring/binstub.rb:11:in `<top (required)>' /myapp/bin/spring:15:in `<top (required)>' bin/rails:3:in `load' bin/rails:3:in `<main>' Tasks: TOP => webpacker:install => webpacker:check_yarn (See full trace by running task with --trace)
なんか分からないけど、yarnのバージョンが何かがおかしい... なので、yarnのinstall方法を変更します。
# Dockerfile 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
これど再度docker-compose build
してやると上手くいきました。
【Rails】Vue.js入門してみた。(rails new ~ hello?)
Ruby on Rails + Vue.jsで最初の画面「Hello Vue!」が表示されるまでの方法を紹介します。
実行環境
- Ruby: 2.6.3
- Rails: 6.0.0
- yarn: 1.19.1
- vue: 3.12.0
rails newまで
先ずはrails単体で「Hello World」が表示されるまでです。
$ mkdir vue-app $ cd vue-app $ ruby -v $ rbenv versions $ rbevn local 2.6.3 # Gemfile作成 $ bundle init
Gemfileを開くとgem "rails"
がコメントアウトされているので、コメントアウトを解除する
# gem "rails" <- ここのコメントアウトを外す
bundle install
する
$ bundle install --path vendor/bundle
rails new
します。
ここで--webpack=vue
を設定するとvueの設定がinstall済で構築できます。
が、今回は後々設定する形でやっていこうと思います。
# railsの雛形を作ります $ bundle exec rails new . -B -d postgresql # Gemfileが更新されるので再度install $ bundle install --path vendor/bundle # DBの作成します $ bundle exec rake db:create $ bundle exec rake db:migrate # サーバー起動します $ bundle exec rails s
どん!
お馴染みの画面が表示されたらokです。
vueを使ってHello World表示させる
先ずは、vueを使えるように設定します。
設定方法は、githubのwebpacker
に書かれてます。
https://github.com/rails/webpacker#vue
$ bundle exec rails webpacker:install $ bundle exec rails webpacker:install:vue
次に表示させるためのコントローラーと画面を作ります。
$ bundle exec rails g controller home index # routes.rb Rails.application.routes.draw do root 'home#index' end # application.html.erb . . <body> <%= yield %> <%= javascript_pack_tag 'hello_vue' %> <- これを追加します。 </body>
これで準備は完了です!
rails s
して画面を開くと...
「Hello Vue!」が表示されていればokです!
vueファイルをいじってみる
<%= javascript_pack_tag 'hello_vue' %>
で読み込んだhello_vue
はapp/javascript/packs/hello_vue.js
を参照しています。
このファイルの真ん中に使い方が色々と書いてあります。
- 既存のhtml / erbテンプレートの要素をターゲットにできるようにするには、上記のコードをコメントアウト
- このマークアップをHTMLテンプレートに追加します。
なので、先ほど作ったhome/index.html.erb
とhello.vue.js
を変更していきます。
# index.html.erb <div id='hello'> {{message}} <app></app> </div>
# hello.vue.js import Vue from 'vue/dist/vue.esm' import App from '../app.vue' document.addEventListener('DOMContentLoaded', () => { const app = new Vue({ el: '#hello', data: { message: "Can you say hello?" }, components: { App } }) })
ここまで出来たらもっかいrails s
で画面を確認してみます。
画面左上に「Can you say hello?」が表示されていればokです。
これは、vueで定義した変数message
の文字列をhtmlで定義した{{ message }}
で表示させています。
Vue.jsは絶賛勉強中なので、随時使い方は別の記事でまとめていきたいと思います。
Tips
bundle installでエラーになった場合
$ bundle install --path vendor/bundle . . . Resolving dependencies... Bundler could not find compatible versions for gem "sprockets": In snapshot (Gemfile.lock): sprockets (= 4.0.0) In Gemfile: sass-rails (~> 5) was resolved to 5.1.0, which depends on sprockets (>= 2.8, < 4.0) rails (~> 6.0.0) was resolved to 6.0.0, which depends on sprockets-rails (>= 2.0.0) was resolved to 3.2.1, which depends on sprockets (>= 3.0.0) Running `bundle update` will rebuild your snapshot from scratch, using only the gems in your Gemfile, which may resolve the conflict.
エラー文を見ると、 sass-rails
のバージョンが引っかかってるのが分かるのでGemfile
のバージョン指定されているのを外してあげます。
gem 'sass-rails', '~> 5' ↓ gem 'sass-rails'
rails webpacker:installでエラーになった場合
DEPRECATION WARNING: Single arity template handlers are deprecated. Template handlers must now accept two parameters, the view object and the source for the view object. Change: >> Coffee::Rails::TemplateHandler.call(template) To: >> Coffee::Rails::TemplateHandler.call(template, source) (called from <main> at /Users/tnakano/rails/vue-app/Rakefile:6) DEPRECATION WARNING: Single arity template handlers are deprecated. Template handlers must now accept two parameters, the view object and the source for the view object. Change: >> Coffee::Rails::TemplateHandler.call(template) To: >> Coffee::Rails::TemplateHandler.call(template, source) (called from <main> at /Users/tnakano/rails/vue-app/Rakefile:6) RAILS_ENV=development environment is not defined in config/webpacker.yml, falling back to production environment rails aborted! Webpacker configuration file not found /Users/tnakano/rails/vue-app/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /Users/tnakano/rails/vue-app/config/webpacker.yml
Please run rails webpacker:install Error: No such file or directory
この辺りが怪しいですかね。これをそのまま検索してみるとwebpacker
がインストールされてないと出るエラーみたいなので、Gemfile
に追加します。
# Gemfile gem 'webpacker', '~> 4.x'
追加したらbundle install
します。
また、yarn
がインストールされていない場合もエラーになるみたいなのでその場合はbrewを使ってインストールします。
$ brew install yarn
【Rails】enumをさらに便利にしてくれるgem enumerize(日本語化も)
Ruby on RailsでEnum = 列挙型を使う時に色々と便利なGemenumerize
の紹介です。
enumは例えば、ユーザーの性別とか、ステータスとか複数の項目を持つデータを扱う際に使います。
Railsだけでもenumを扱うことは出来るのですが、enumerize
を使うと簡単に日本語表示できたりformを簡単に作れたり便利です。
使い方
Gemfile
にenumerize
を追加してbundle install
します。
# Gemfile gem 'enumerize'
enumerize
を使うカラムをモデルで定義します。
migrationする際に、defaultを定義しておくとrake db:migrate
した際に既存のデータへも値が入るので設定します。
# Migration class AddRoleToNewUser < ActiveRecord::Migration[5.2] def change add_column :new_users, :role, :string, default: 'member', null: false end end ↓ > NewUser.select(:id, :name, :role).limit(5) => [#<NewUser:0x00007fca26d4adf8 id: 1, name: "opiyo", role: "member">, #<NewUser:0x00007fca26d4a650 id: 2, name: nil, role: "member">, #<NewUser:0x00007fca26d49ed0 id: 3, name: nil, role: "member">, #<NewUser:0x00007fca26d49728 id: 4, name: "opiyo", role: "member">, #<NewUser:0x00007fca26d48ff8 id: 5, name: nil, role: "member">]
モデルで実際に定義していきます。
# new_user.rb class NewUser < ApplicationRecord extend Enumerize has_many :posts, dependent: :destroy enumerize :role, in: %i(admin member), default: :member, scope: true end
extend Enumerize
は書くの忘れるので注意です!
ここでもdefaultを指定しておくことで、オブジェクトを作った際にデフォルトで値が設定されます。
また、定義していない値でsave
するとvalidation
を書かなくてもエラーになります。
> user = NewUser.new => #<id: nil, name: nil, role: "member"> > user.role = 'opiyo' => "opiyo" > user.save (0.2ms) BEGIN (4.2ms) ROLLBACK => false > user.errors.full_messages => ["Roleは一覧にありません。"]
設定はこれだけです。日本語表示の対応をする場合はja.yml
への設定を行います。
# ja.yml ja: enumerize: new_user: role: admin: '管理者' member: 'メンバー'
よく使うメソッド
色々な取得方法がありますので、よく使うメソッドをrails c
で確認していきます。
> NewUser.role.options => [["管理者", "admin"], ["メンバー", "member"]] > NewUser.role.values => ["admin", "member"] > user = NewUser.new => <id: nil, name: nil, role: "member"> > user.role => "member" > user.role.member? => true > user.role.admin? => false > user.role.opiyo? NoMethodError: undefined method `opiyo?' for "member":Enumerize::Value > user.role_value => "member" > user.role_text => "メンバー" # scope: trueが必要 > NewUser.with_role(:member) SELECT "new_users".* FROM "new_users" WHERE "new_users"."role" = $1 [["role", "member"]] > NewUser.without_role(:member) SELECT "new_users".* FROM "new_users" WHERE "new_users"."role" NOT IN ('member')
formで使う(simple_form)
enumerize
を定義していると、簡単にセレクトボックスやラジオボタンが作れます。
.hoges__new-form = simple_form_for(@user, url: new_users_path) do |f| = f.input :name, placeholder: 'お名前', hint: 'フルネームでご記入してください。' = f.input :age = f.input :gender, collection: Hoge::GENDER, label: false, include_blank: '-----選択して下さい-----' # セレクトボックス = f.input :role # ラジオボタン = f.input :role, as: :radio_buttons # チェックボックス = f.input :role, as: :check_boxes = f.input :birthday .hoges__new-form-btn = f.submit
simple_form
の使い方はこちらにまとめていますので、どうぞ!
【Rails】開発中に送ったメールを確認する(Gem: letter_opener)
Ruby on Railsで開発中に送ったメールを確認する Gem letter_opener_web
の紹介です。
環境設定
Gemfile
にletter_opener_web
を追加する。
# Gemfile group :development do gem 'letter_opener_web' end
開発環境モードの設定ファイルにメール送信の設定をします。
# development.rb Rails.application.configure do config.action_mailer.default_url_options = { host: localhost, port: 3000 } # `:letter_opener`を指定する config.action_mailer.delivery_method = :letter_opener # ログにエラーを表示するために`true`を設定 config.action_mailer.raise_delivery_errors = true # ここの指定は無くてokみたい # config.action_mailer.smtp_settings = { # address: SMTPのメールサーバ, # port: 587, # domain: 送付するドメイン, # authentication: "plain", # enable_starttls_auto: true, # user_name: メールサーバ認証用ユーザー, # password: メールサーバ認証用パスワード # } end
ブラウザでメールの送信結果を確認できるように設定します。
Rails.application.routes.draw do if Rails.env.development? mount LetterOpenerWeb::Engine, at: '/letter_opener' end end
これで、http://localhost:3000/letter_opener/
で確認することが可能です!
Mailerファイルを作成する
$ bundle exec rails g mailer new_user
Mailerファイルを設定する
# new_user_mailer.rb class NewUserMailer < ApplicationMailer default from: "hoge@example.com" def to_user(user) @user = user mail to: user.email, cc: 'cc@example.com', bcc: 'bcc@example.com', subject: 'ご登録ありがとうございます!' end end
# to_user.html.haml %p = "#{@user.name}様" %br ご登録ありがとうございます。 %p こちらからログインして下さい。 %br - url = new_user_url(@user.id) = link_to url, url, target: '_blank'
何もしていないとhtmlメールになりますが、format.text
を指定することでtextメールで送ることも可能です。
# new_user_mailer.rb class NewUserMailer < ApplicationMailer default from: "hoge@example.com" def to_user(user) @user = user mail to: user.email, cc: 'cc@example.com', bcc: 'bcc@example.com', subject: 'ご登録ありがとうございます!' do |format| format.text { render 'new_user_mailer/to_user', layout: false } # ここの部分 end end end
textメールの場合は改行や空白がそのまま本文となりますので、要注意です!
# to_user.text.erb <%= @user.name %>様 ご登録ありがとうございます。 こちらからログインして下さい。 <%= new_user_url(@user.id) %> <%= render 'signature' %>
# _signature.text.erb ■------------------------------------------------------------- opiyo株式会社 お客様相談お問い合わせ窓口 mail:opiyo@example.com -------------------------------------------------------------■
実行方法と結果の確認
# rails consoleに入る $ bundle exec rails c # メール送信する > NewUserMailer.to_user(NewUser.last).deliver_now => #<Mail::Message:70228559444700, Multipart: false, Headers: <Date: Wed, 16 Oct 2019 21:37:46 +0900>, <From: hoge@example.com>, <To: >, <Cc: cc@example.com>, <Bcc: bcc@example.com>, <Message-ID: <5da70f1ab3d89_12e833fdf64440e5c983a0@TakunoMacBook-puro.local.mail>>, <Subject: ご登録ありがとうございます!>, <Mime-Version: 1.0>, <Content-Type: text/plain>, <Content-Transfer-Encoding: base64>> # メール送信を非同期で > NewUserMailer.to_user(NewUser.last).deliver_later => #<ActionMailer::DeliveryJob:0x00007fbeb9a88db8 @arguments= ["NewUserMailer", "to_user", "deliver_now", #<NewUser:0x00007fbeb9a8b2e8 id: 13, name: "opiyo", age: nil, gender: "", birthday: nil, email: nil, created_at: Tue, 15 Oct 2019 20:13:15 JST +09:00, updated_at: Tue, 15 Oct 2019 20:13:15 JST +09:00, token: nil>], @executions=0, @job_id="24783fb5-9c1e-4005-a247-457a9e16d78d", @priority=nil, @provider_job_id=6292, @queue_name="mailers">
【Rails】不用な値の更新を防ぐ「Strong Parameters」について
Ruby on RailsのStrong Parameters
についての紹介です。
ユーザー登録やお問い合わせなど、ユーザーがフォームに入力したデータのみ登録・更新できるようにするための機能です。
webの場合は開発者ツールなどを使って存在しないformを自由に作ったり出来てしまうので、それを防ぐことは大事です。
基本的な使い方
params.require(:key).permit(filter)
- key: paramsのキー
- filter: 登録・更新を許可するカラム名
<input name="new_user[name]"> <input name="new_user[age]">
key
はinputラベルのname
に指定する名前です。この例の場合だとnew_user
がそれにあたります。
filter
の部分は登録・更新したいカラム名です。この例の場合だとname
やage
がそれにあたります。これらをシンボルを使って記述していきます。
実際の使い方例
実際の使い方ですが、update
やcreate
処理の時に使います。
new_user_params
メソッドがStrong Parameterの処理部分です。
# new_users_controller.rb def create @user = NewUser.new(new_user_params) if @user.save # 成功した時の処理 else # 失敗した時の処理 end end def new_user_params params.require(:new_user).permit(:name, :age, :gender, :birthday) end
このように記述しておく事で万が一別のカラムが飛んで来ても無視されます。
またNewUser.create(params[:new_user])
のようにStrong Parameters記述せずにparamsをそのまま登録しようとするとエラー(ActiveModel::ForbiddenAttributesError)になります。
そのほかの使い方例
関連するデータもまとめて登録する
1 : Nの関係など関連するデータも合わせて登録・更新した時にnested_attributes
という仕組みがあります。こういった場合は以下のように記述する事で関連するデータもまとめて対応する事ができます。
params.require(:new_user).permit(:name, :age, :gender, :birthday, posts_attributes: [:id, :title, :_destroy])
キーが存在しない場合にエラーにならないように
テーブルなどのデータの一覧があって、対象データにチェックを付けてデータの登録・更新するような処理の場合に1つもチェックがない状態で保存するとkey
が無い状態になるのですが、そのような場合に使います。
params.fetch(:new_user, {}).permit(:name, :age, :gender, :birthday)