- 投稿日:2019-07-28T23:11:48+09:00
merge
- 投稿日:2019-07-28T22:19:37+09:00
Rubyで二重コロン[::]とドット[.]の使い分け
背景・目的
二重コロン[::]とドット[.]の使い分けがごっちゃになる時があるので整理しておく。
二重コロン[::]とドット[.]の使い分け
一般的なルールは、、、
定数・クラス・モジュールを呼び出す場合 => 二重コロン[::]
メソッドを呼び出す場合 => ドット[.]但し、、、
定数を呼び出す時にドット[.]を使うと怒られるが、メソッドを使う時に二重コロン[::]を使っても怒られないので私の様な初心者は注意が必要。module Sample class User NAME = 'taro' def self.hello(name = NAME) "Hello, #{name}." end end endSample::User::NAME => "taro" Sample::User.NAME => NoMethodError (undefined method 'NAME' for Sample::User:Class) Sample::User::hello => "Hello, taro." `Sample::User.hello => "Hello, taro."
- 投稿日:2019-07-28T21:19:06+09:00
Ruby on Railsのヘルパーメソッドで<script>タグを書く。
ビューヘルパーって慣れない内は難しいよね
結構コロンがいるのかとか、どこに括弧をつけるとかなかなか分かりにくい。
簡単にJSのテストをする時に、viewファイルに以下のタグを書くこともあると思いますが、できればビューヘルパーを使いたいですよね。sample.html.erb<script> </script>実際のコード
以下のように書くと同じ事になります。
sample.html.erb<%= javascript_tag do %> <% end %>ちなみにクラスはこうやって付けられます、
でも多分(class: "hoge")とかでも大丈夫だしこっちの方がスマート。
記事書いている今試せないのでちょっとあやふやです。sample.html.erb<%= javascript_tag(:class => :hoge) do %> <% end %>最後に
まあテストだけならビューヘルパー使わなくてもいいじゃないかという話かもしれませんが、
気分的に気になる人はこの書き方を使ってみては?
- 投稿日:2019-07-28T20:31:07+09:00
Ruby on Raildで空き家を貸し借り出来るwebアプリを開発
はじめに
Ruby on Railsを使って、空き家を貸し借りできるwebアプリを開発しました。ただし、正式に公開する前提で開発はしておらず、あくまでデモとして開発しました。
開発した目的としては、rails開発の訓練のためと、ポートフォリオを作成したかったためです。
この記事ではそのwebアプリの解説をしております。
注意点
1.このwebアプリはRuby on Railsチュートリアルで公開されているソースコードをベースに開発しました。
2.サーバーサイドの実装の訓練が目的で開発をしたため、フロントエンド関連はほとんど手を入れておりません。
ソースコード
ソースコードはgithubで公開しております。
github:null_house参考にさせていただいた記事
Ruby on Railsチュートリアル
rails 予約機能をつける。(一回目)
Railsでコメント機能をつくってみよう
Railsで「投稿お気に入り追加機能」を実装する
railsで検索フォームを作ろう!!大変お世話になりました。ありがとうございます。
HOME画面
届いたメールのURLをクリックし、アカウント有効化をすると自身のプロフィール画面にジャンプします。
空き家を貸し出す
作成すると、自身のプロフィールページにある「あなたが貸しに出してる空き家」の箇所に作成した空き家のタイトル名が表示されます。
空き家の詳細ページ
以下は作成された空き家の詳細ページになります。
1.空き家のタイトル
2.空き家の説明文
3.空き家の貸出者
4.お気に入り機能
5.空き家へのコメント
6.空き家の内覧予約
7.空き家の適正価格算出
8.空き家の借用に対してされたオファーの内容(後述)様々な機能
自身のプロフィールページにある「あなたがお気に入りに追加した空き家」の欄に、お気に入りに登録した空き家のタイトルが表示されます。
家賃適正価格予測機能
回帰分析を用いて、空き家作成時に入力したサイズなどの値を元に、家賃の適正価格を表示します。
(モデル作成ソース)import numpy as np import pandas as pd from sklearn import linear_model ##データセットはランダムに作成 data = {'layout' : [2, 1, 3, 4, 5], 'land_area' : [40, 20, 30, 55, 65], 'building_area' : [50, 20, 35, 60, 70], 'age_of_a_building' : [40, 50, 30,20,10], 'adoress' : [7, 3, 8, 4, 1], 'price' : [48000, 29000, 33000,55000,67000]} df = pd.DataFrame(data) Y_train = df['price'] X_train = df.drop("price", axis=1) lm_model = linear_model.LinearRegression() lm_model.fit(X_train,Y_train) print("切片 =",lm_model.intercept_) print("回帰係数 =",lm_model.coef_)切片 = 27073.62274689006 回帰係数 = [ 4.82355928 -1097.43589744 1625.64102564 -48.23559279 -2076.92307692]def lm(x1,x2,x3,x4,x5) (27073 + 4.82355928*x1 - 1097.43589744*x2 + 1625.64102564*x3 - 48.23559279*x4 - 2076.92307692*x5).to_i end<% if current_user.id == @house.user_id %> <h3>家賃予測価格</h3> <p>この空き家の1ヶ月の適正価格は<%= lm(x1,x2,x3,x4,x5) %>円です</p> <% end %>プレミアム会員機能
<% if @user.premium? %> <h4>あなたはプレミアム会員です!!</h4> <% end %>オファーを出す
オファーを出すと、出された側の空き家ページにオファーの内容が表示されます。
<h3>オファー一覧</h3> <% if @offer %> user id : <%= @offer.user_id%><%= @offer.use %> <% end %>管理画面
管理者のみがアクセスできる管理画面を作成しました。
def ensure_correct_user if current_user.admin? #何もしない else flash[:notice] = "アクセス権限がありません" redirect_to root_url end endユーザー一覧
コメント一覧
内覧予約一覧
データ視覚化画面
運営からのお知らせ機能
管理画面と同じく、管理者のみがアクセスできるページで、お知らせを作成したりできます
。作成
一覧
詳細
今後の課題
- テストがおざなりになってしまったので、テストを書く訓練を今後したい。
- 大規模な機械学習モデルを使用できるようにしたい(GCPにモデルをデプロイして予測を取得したり等)
最後に
webアプリ開発において、基本的な機能は実装できるようになったとは思います。
今後実践の機会を増やして、レベルアップしていきたいです。※コメントやツッコミあればどんどんください!
- 投稿日:2019-07-28T20:31:07+09:00
線形回帰モデルによる価格予測機能を組み込んだ空き家貸し借りアプリをRuby on Railsで開発
はじめに
Ruby on Railsを使って、空き家を貸し借りできるwebアプリを開発しました。ただし、正式に公開する前提で開発はしておらず、あくまでデモとして開発しました。
開発した目的としては、rails開発の訓練のためと、ポートフォリオを作成したかったためです。
この記事ではそのwebアプリの解説をしております。
線形回帰モデルによる価格予測の実装については中盤辺りに記載してます。
注意点
1.このwebアプリはRuby on Railsチュートリアルで公開されているソースコードをベースに開発しました。
2.サーバーサイドの実装の訓練が目的で開発をしたため、フロントエンド関連はほとんど手を入れておりません。
ソースコード
ソースコードはgithubで公開しております。
github:null_house参考にさせていただいた記事
Ruby on Railsチュートリアル
rails 予約機能をつける。(一回目)
Railsでコメント機能をつくってみよう
Railsで「投稿お気に入り追加機能」を実装する
railsで検索フォームを作ろう!!大変お世話になりました。ありがとうございます。
HOME画面
届いたメールのURLをクリックし、アカウント有効化をすると自身のプロフィール画面にジャンプします。
空き家を貸し出す
作成すると、自身のプロフィールページにある「あなたが貸しに出してる空き家」の箇所に作成した空き家のタイトル名が表示されます。
空き家の詳細ページ
以下は作成された空き家の詳細ページになります。
1.空き家のタイトル
2.空き家の説明文
3.空き家の貸出者
4.お気に入り機能
5.空き家へのコメント
6.空き家の内覧予約
7.空き家の適正価格算出
8.空き家の借用に対してされたオファーの内容(後述)様々な機能
自身のプロフィールページにある「あなたがお気に入りに追加した空き家」の欄に、お気に入りに登録した空き家のタイトルが表示されます。
家賃適正価格予測機能
回帰分析を用いて、空き家作成時に入力したサイズなどの値を元に、家賃の適正価格を表示します。
(モデル作成ソース)import numpy as np import pandas as pd from sklearn import linear_model ##データセットはランダムに作成 data = {'layout' : [2, 1, 3, 4, 5], 'land_area' : [40, 20, 30, 55, 65], 'building_area' : [50, 20, 35, 60, 70], 'age_of_a_building' : [40, 50, 30,20,10], 'adoress' : [7, 3, 8, 4, 1], 'price' : [48000, 29000, 33000,55000,67000]} df = pd.DataFrame(data) Y_train = df['price'] X_train = df.drop("price", axis=1) lm_model = linear_model.LinearRegression() lm_model.fit(X_train,Y_train) print("切片 =",lm_model.intercept_) print("回帰係数 =",lm_model.coef_)切片 = 27073.62274689006 回帰係数 = [ 4.82355928 -1097.43589744 1625.64102564 -48.23559279 -2076.92307692]def lm(x1,x2,x3,x4,x5) (27073 + 4.82355928*x1 - 1097.43589744*x2 + 1625.64102564*x3 - 48.23559279*x4 - 2076.92307692*x5).to_i end<% if current_user.id == @house.user_id %> <h3>家賃予測価格</h3> <p>この空き家の1ヶ月の適正価格は<%= lm(x1,x2,x3,x4,x5) %>円です</p> <% end %>プレミアム会員機能
<% if @user.premium? %> <h4>あなたはプレミアム会員です!!</h4> <% end %>オファーを出す
オファーを出すと、出された側の空き家ページにオファーの内容が表示されます。
<h3>オファー一覧</h3> <% if @offer %> user id : <%= @offer.user_id%><%= @offer.use %> <% end %>管理画面
管理者のみがアクセスできる管理画面を作成しました。
def ensure_correct_user if current_user.admin? #何もしない else flash[:notice] = "アクセス権限がありません" redirect_to root_url end endユーザー一覧
コメント一覧
内覧予約一覧
データ視覚化画面
運営からのお知らせ機能
管理画面と同じく、管理者のみがアクセスできるページで、お知らせを作成したりできます
。作成
一覧
詳細
今後の課題
- テストがおざなりになってしまったので、テストを書く訓練を今後したい。
- 大規模な機械学習モデルを使用できるようにしたい(GCPにモデルをデプロイして予測を取得したり等)
最後に
webアプリ開発において、基本的な機能は実装できるようになったとは思います。
今後実践の機会を増やして、レベルアップしていきたいです。※コメントやツッコミあればどんどんください!
- 投稿日:2019-07-28T20:02:51+09:00
マイグレーションファイルの記述を間違えてしまった
本日の学習のハマってしまったエラー内容の備忘録です。
マイグレーションファイルの記述を間違えてしまった時の対処法
本日の学習中に
bundle exec rake db:seed
を実行したいのにエラーが出てしまい
原因を探していたらマイグレーションファイルの記述ミスでした。
書き直して上書き保存してもエラーになっていましたので
ターミナルから変更するのだろうかと考え、調べていました。今日作っていたのは下記のコード
class CreateItems < ActiveRecord::Migration[5.2] def change create_table :items do |t| t.string :items <= nameに変更 t.integer :price t.integer :user_id t.timestamps end end end上記のコードの
items
をname
に変更した後にbundle exec rake db:migrate:resetマイグレーションファイルをリセットして再度マイグレーションを実行します。
※自分は実行しましたが、必要ないかも?bundle exec rake db:migrateこのやり方で一応は成功しました。
調べていたら
rake db:rollback
などもあるとの事なので今度テスト環境で試してみたいです。
- 投稿日:2019-07-28T20:02:20+09:00
プログラミン未経験者はRailsチュートリアを1周目はじっくりやってはいけない
想定読者
・プログラミン初心者
・実務未経験者
・これからRailsチュートリアをやろうとしている方著者情報と記事の概要
著者情報
・HTML, CSS, JavaScriptを少しかじった程度の初心者
・ProgateでRubyおよびRialsを1周やっている
・Railsで転職活動用のWebアプリを作りたい人記事の概要
Ruby on Railsを学習すると決めたからには、誰もがやるであろうRailsチュートリアです。Twitterで検索すると多くのプログラミン初学者が挑戦しているのを見かけます(私もその一人)。
では、プログラミング初心者の私がRailsチュートリアをやることで、どのレベルにまで到達できたのか、紹介したいと思います。理解度30%
このQiitaは、実はRailsチュートリア走破後すぐに書いているのですが、率直な感想として、Railsチュートリアの30%程しか理解できなかったと感じています。ここでいう「理解」は、どれだけ再現できるかだと思ってください。とくにテストの書き方については理解度はかなり低めです。ちなみに私は、Railsチュートリアを25日間でやりました。時間でいうと、100時間ほどです。割とじっくりやっと方ではないかと思います。
各章ごとの理解度
章 内容 理解度 コメント 1章 環境設定 100% 2章 MVCモデル概要 100% 3章 ルーティング 100% 4章 Ruby文法 100% Progateをやっていれば大丈夫 5章 Viewを書く 100% 6章 モデルを書く 50% バリデーション等の流れをフォロー難 7章 ユーザー登録機能 60% 8章 ログイン機構 50% 9章 ログインしたまま機構 3% 脳内がトークンで埋め尽くされる 10章 ユーザーのREST 50% 細かな機能が多くなってくる 11章 ユーザー有効化 50% メール関係のテストが複雑 12章 パスワード再設定 30% 似たような機構が多く、混同してくる 13章 マイクロポスト機構 20% まったく全体像が見えない 14章 フォロー機構 20% relationshipモデルが難しい ちなみに、最も難しい9章はスキップしてもいいと本書でも明言されています。
身についたとは口が裂けても言えない
Railsチュートリアル1週目を終えて、さくさくWebアプリを作れるようになったかというと、まったくそんなことはありません。一部のブログ等では、「Railsチュートリアルを1周すればWebアプリをさくさく作れる一歩手前のレベルになります」と書いてた気がしますが、私の場合は全然そんなことありませんでした。
1周目は概念の習得に専念
正直、Railsチュートリアルで紹介のあった細かい技術はすでに大方覚えていません(笑) 「プログラミンは暗記ではない!」というありがたい言葉もありますが、流石に「こんなメソッドあったな〜」と後からググり治せるくらいの記憶の残滓は必要なはずですが、残ってません。一方で、MVCモデルや、Railsの大方の挙動、フォルダ構成はかなり理解できました。ただ、概念を習得するのに25日間、100時間の投入が必要だったか?と問われると、まったく必要なかったと思います。
結論:1周目はスピーディーに。現場Rails等を併用して。
結論として、Railsチュートリアルの1周目は、理解度よりもスピードを意識したほうが得策であると考えます。(じっくりやっても結局覚えれません)。結局のところ自分の頭で1から考えるしか大きな成長は望めませんので、Railsチュートリアルはそこそこに、とっとと自作のWebアプリを作り始めるのが得策だと感じました。
あと、もう一点。10章をやっている時に、これまたRails学習の決定版である『現場で使える Ruby on Rails 5速習実践ガイド』、通称『現場Rails』をパラパラとやっていたのですが、日本人著者の利点といいましょうか。併用すると、Railsチュートリアルのもやもやが晴れるところもあり、並行してすすめるのは結構おすすめです!
- 投稿日:2019-07-28T20:02:20+09:00
プログラミング未経験者はRailsチュートリア1周目をじっくりやってはいけない
想定読者
・プログラミン初心者
・実務未経験者
・これからRailsチュートリアをやろうとしている方著者情報と記事の概要
著者情報
・HTML, CSS, JavaScriptを少しかじった程度の初心者
・ProgateでRubyおよびRialsを1周やっている
・Railsで転職活動用のWebアプリを作りたい人記事の概要
Ruby on Railsを学習すると決めたからには、誰もがやるであろうRailsチュートリアです。Twitterで検索すると多くのプログラミン初学者が挑戦しているのを見かけます(私もその一人)。
では、プログラミング初心者の私がRailsチュートリアをやることで、どのレベルにまで到達できたのか、紹介したいと思います。理解度30%
このQiitaは、実はRailsチュートリア走破後すぐに書いているのですが、率直な感想として、Railsチュートリアの30%程しか理解できなかったと感じています。ここでいう「理解」は、どれだけ再現できるかだと思ってください。とくにテストの書き方については理解度はかなり低めです。ちなみに私は、Railsチュートリアを25日間でやりました。時間でいうと、100時間ほどです。割とじっくりやっと方ではないかと思います。
各章ごとの理解度
章 内容 理解度 コメント 1章 環境設定 100% 2章 MVCモデル概要 100% 3章 ルーティング 100% 4章 Ruby文法 100% Progateをやっていれば大丈夫 5章 Viewを書く 100% 6章 モデルを書く 50% バリデーション等の流れをフォロー難 7章 ユーザー登録機能 60% 8章 ログイン機構 50% 9章 ログインしたまま機構 3% 脳内がトークンで埋め尽くされる 10章 ユーザーのREST 50% 細かな機能が多くなってくる 11章 ユーザー有効化 50% メール関係のテストが複雑 12章 パスワード再設定 30% 似たような機構が多く、混同してくる 13章 マイクロポスト機構 20% まったく全体像が見えない 14章 フォロー機構 20% relationshipモデルが難しい ちなみに、最も難しい9章はスキップしてもいいと本書でも明言されています。
身についたとは口が裂けても言えない
Railsチュートリアル1週目を終えて、さくさくWebアプリを作れるようになったかというと、まったくそんなことはありません。一部のブログ等では、「Railsチュートリアルを1周すればWebアプリをさくさく作れる一歩手前のレベルになります」と書いてた気がしますが、私の場合は全然そんなことありませんでした。
1周目は概念の習得に専念
正直、Railsチュートリアルで紹介のあった細かい技術はすでに大方覚えていません(笑) 「プログラミンは暗記ではない!」というありがたい言葉もありますが、流石に「こんなメソッドあったな〜」と後からググり治せるくらいの記憶の残滓は必要なはずですが、残ってません。一方で、MVCモデルや、Railsの大方の挙動、フォルダ構成はかなり理解できました。ただ、概念を習得するのに25日間、100時間の投入が必要だったか?と問われると、まったく必要なかったと思います。
結論:1周目はスピーディーに。現場Rails等を併用して。
結論として、Railsチュートリアルの1周目は、理解度よりもスピードを意識したほうが得策であると考えます。(じっくりやっても結局覚えれません)。結局のところ自分の頭で1から考えるしか大きな成長は望めませんので、Railsチュートリアルはそこそこに、とっとと自作のWebアプリを作り始めるのが得策だと感じました。
あと、もう一点。10章をやっている時に、これまたRails学習の決定版である『現場で使える Ruby on Rails 5速習実践ガイド』、通称『現場Rails』をパラパラとやっていたのですが、日本人著者の利点といいましょうか。併用すると、Railsチュートリアルのもやもやが晴れるところもあり、並行してすすめるのは結構おすすめです!
- 投稿日:2019-07-28T19:54:54+09:00
jqueryでHTTP通信をしないページ遷移
タイトル通り
HTTP通信を行わずに、webページを遷移する方法を身につけたので共有します。
htmlはhamlで記入しているのでよろしくお願いします。結論としてはまだ表示させたくないページには大元のclassにdisplay:noneを当てる
まずは、必要なwebページのhtmlコードを一つのhtmlファイルに全て書き出します。そして、最初に表示されないページの大元のクラスにdisplay:noneが当たるクラスを与えます。下のコードでは.yabaiがそのクラスになります
以下のコードと画像を見てくださいhaml.zyuuhati .keikoku-box %P.top-keikoku = fa_icon 'venus-mars' %span 警告! %p.keikoku-bunsyo 当サイトは18歳以下の利用を固く禁じます。あなたは18歳以上ですか? %a.ryoukai はい //このボタンを押すとページが切り替わります %a.nigeru いいえ .waller.yabai //.yabaiにはdisplay:noneがかかっているので最初は見えません %P.yabababa まじ卍字css.zyuuhati{ background-color: gray; height: 100% padding :15% 15%; } .keikoku-box{ background-color: #fba933; height: 100%; width: 100%; padding: 20% 10% 10% 10%; } .top-keikoku{ text-align: center; font-size: 30px; font-weight: 200; color: red; } .keikoku-bunsyo{ margin-top: 70px; font-size:25px; color: black; } .ryoukai{ display: block; text-align: center; border-radius: 20%; line-height: 40px; width: 200px; height: 40px; background-color: aqua; font-size: 20px; margin: 20px auto; color: white; } .nigeru{ display: block; text-align: center; border-radius: 20%; line-height: 40px; width: 200px; height: 40px; background-color: red; font-size: 20px; margin: 20px auto; color: white; } .yabai{ display: none; } .waller{ background-color: #ef5185; height: 700px; } .yabababa{ color: white; font-size: 50px; }
「はい」
のリンクをクリックした瞬間、一つ目のページが消え、二つ目のページが現れましたね。
このからくりは、「はい」
のクリックを発火点にして、1枚目のページのクラスにyabaiクラス
を与え、
2枚目のページからyabaiクラス
を取り除くという方法で実装しています。
具体的なコードは以下の通りです。jquery$(function(){ $('.ryoukai').on('click', function(e){ e.preventDefault(); $('.zyuuhati').addClass('yabai'); //最初の画面をdisplay:noneにします。 $('.waller').removeClass('yabai'); //次のページを表示させます }); });
この方法で一つのURL上でページ遷移することができます!
- 投稿日:2019-07-28T19:39:09+09:00
プロキシに阻まれたVagrantからRDSに接続する
プロキシに阻まれて何もできない・・・
- ホストマシン(以下「ホスト」)は、かなり堅い認証プロキシ(以下「鉄壁プロキシ」)経由でインターネットに接続されている(Vagrantの通信はことごとく407になる)
- 開発用に、ホスト上のVagrant環境からの通信だけを捌くプロキシサーバ(以下「開発プロキシ」)をEC2に構築する(許可は取ってる)
- EC2にsquidを入れ、Vagrantからの通信を受ける
- 別で動いているWEBアプリケーションのRDSに対して接続できるようにし、データを取得できるようにする
環境
- Windows 10 1803(ホスト)
- Vagrant 2.2.2
- VirtualBox 6.0.0
- CentOS 7.6.1810(ゲスト)
- Ruby 2.6.0
- Rails 5.2.2
- vagrant-vbguest 0.18.0
- vagrant-proxyconf 2.0.4
- dotenv 2.7.4
- mysql 5.7(RDS)
例として設定する項目と値
記事内での設定例については、ここに記す値を利用する
項目 設定値 ホストのグローバルIPアドレス 111.222.333.444 squid.conf内でのルール名 myrule1 開発プロキシのユーザ名 ec2-user 開発プロキシのsquid用ポート 60008 開発プロキシのElastic IP 55.555.5.555 開発プロキシのプライベートIP 172.16.11.11 開発プロキシのpemファイル nice_stick.pem RDSのエンドポイント xxxxxxxx.yyyyyyyy.ap-northeast-1.rds.amazonaws.com RDSのポート 3306 RDSのパブリックアクセシビリティ 有効 プロジェクト名 nice_stick .env DB_USERNAME nice_stick .env DB_PASSWORD melonpan
- RDSは、セキュリティグループで55.555.5.555からの3306番の接続を許可し、mysql側で、
nice_stick@55.555.5.555
からのパスワード利用での接続を許可しておくmelonpanプロジェクトの本番DBに、nice_stickプロジェクトの開発環境からアクセスできるようにしていく
EC2(開発プロキシ側)の設定
- Amazon Linux 2でインスタンス作成、ElasticIPも割り当てておく
- セキュリティグループのインバウンドに、ホストのグローバルIPアドレスを設定する
- したがって、鉄壁プロキシ経由でホストのグローバルIPアドレスに対して22番ポートでの接続ができるようにしておく
今回は、下記の設定を行う
terminal(開発プロキシ側)sudo yum -y squid install sudo vi /etc/squid/squid.conf
squid.conf(抜粋)(省略) acl localnet src fe80::/10 ← の下に acl myrule1 src 111.222.333.444/32 を追加 (中略) http_access allow localhost ← の下に http_access allow myrule1 を追加 (中略) # Squid normally listens to port 3128 ← の下に http_port 60008 を追加上記の編集を行って保存、
terminal(開発プロキシ側)sudo squid -k parse sudo systemctl restart squid.service sudo systemctl enable squid.service
を行う。squid -k parse は、squid.confの構成のチェックをしているので、エラーがあれば修正する。
エラーがある状態でsystemctl restartしても、エラーが発生するので、きちんと直す。省略するが、ダイジェスト認証などの認証機能を導入しておくほうが(かなり)望ましい。
https://skkskynw.hateblo.jp/entry/2016/09/04/165725Vagrant側の設定
ホストへのVagrant/VirtualBoxのインストールは行われているものとする
Vagrantプラグインのインストール
プロジェクトルートで、下記コマンドを実行する
cmd.exevagrant plugin install vagrant-vbguest vagrant plugin install vagrant-proxyconf vagrant plugin install dotenvインストール後、
cmd.exevagrant plugin listを行い、上記3つのプラグインがインストールされていることを確認する
.envとVagrantfileの編集
.envPROXY_URL=http://55.555.5.555:60008Vagrantfile(抜粋)Dotenv.load Vagrant.configure("2") do |config| (中略) if Vagrant.has_plugin?("vagrant-proxyconf") config.proxy.enabled config.proxy.http = ENV['PROXY_URL'] config.proxy.https = ENV['PROXY_URL'] config.proxy.no_proxy = "localhost,127.0.0.1" end (中略) config.vm.synced_folder ".", "/vagrant", type: "virtualbox" end上記設定を行い、vagrant up する
Ruby、Rails、mysqlクライアントのインストール等はすませておく。
Railsプロジェクトも作成しておく(database.ymlを編集するので)SSHログインと開発プロキシの動作確認
vagrantの通信がプロキシサーバから出ているかを確認する
terminal(開発プロキシ側)[ec2-user@172.16.11.11 ] $ sudo tail -f /var/log/squid/access.logcmd.exe(vagrant側,sshログイン後)[vagrant@localhost] curl ifconfig.io
ec2側ターミナルにアクセスログが記録され、vagrant側ターミナルに開発プロキシのElastic IPが返ってくればOK。
これで開発自体はできる。RDSに接続するために
ここからが本題。
上記の設定値のとおり、今回接続するRDSは本番用であり、接続はRDSのセキュリティグループ、mysqlのユーザ管理で制御されている。図は https://www.draw.io/ を利用して作成
この状態で、database.ymlに下記のような設定をしても、接続できずにしばらくしたあと110エラーが返ってくる
database.ymlmelonpan_production_for_nice_stick_development: <<:default host: xxxxxxxx.yyyyyyyy.ap-northeast-1.rds.amazonaws.com database: melonpan_production username: <%= ENV['DB_USERNAME'] %> password: <%= ENV['DB_PASSWORD'] %>鉄壁プロキシを使わないネットワークで、同じ構成の環境を作成して実験したところ、上記の記述でも接続できた。
また、開発プロキシにSSH接続してRDSへ接続しても、正常に接続できた。
したがって、vagrant内のプロジェクトでも、この状態では、RDSへの接続で利用される外部ネットワーク接続はVagrantを通じた「開発プロキシ」ではなく、ホストに通じている「鉄壁プロキシ」だということがわかる。これはmysqlコマンドでも同様だった。
mysqlの接続は、AWS内にすら届いておらず、鉄壁プロキシの段階ではじかれていたということ。
(これ自体を回避できる方法があったらコメントください)てっきり、ifconfigコマンドで開発プロキシのElasticIPが返ってきていたので、開発プロキシ経由で接続してくれると思っていた。
SSHポートフォワーディングの利用による解決
上記の図の通り、開発プロキシはRDSと同じサブネットにいるので、Vagrantから開発プロキシに対してSSHポートフォワードしてあげれば繋がるのではと考えた。
https://qiita.com/nishidataishi/items/40928debaddeb2e33d1d や、
https://cloudpack.media/9675 を参考に、プロジェクトルートに pemfiles ディレクトリを作成。
Vagrantfile.rbのsynced_folder部分を下記に書き換えて、開発プロキシのpemファイルをpemfilesディレクトリ配下にコピー。
(※ sshコマンドがpemファイルの権限でエラーを吐くので、600にする必要がある。ゲスト側でchmodしても変えられない。)この段階で、/pemfiles ディレクトリをgitignoreにしておく(超重要)
.gitignore/pemfiles ← を追加Vagrantfileconfig.vm.synced_folder ".", "/vagrant", type: "virtualbox", :mount_options => ['dmode=775', 'fmode=775'] config.vm.synced_folder "./pemfiles", "/vagrant/pemfiles", type: "virtualbox", :mount_options => ['dmode=600', 'fmode=600']cmd.exe(vagrant側,sshログイン後)[vagrant@localhost] sudo ssh -f -N -L 60008:xxxxxxxx.yyyyyyyy.ap-northeash-1.rds.amazonaws.com:3306 -i /vagrant/pemfiles/nice_stick.pem ec2-user@55.555.5.555
を実行して、バックグラウンドでポートフォワーディングさせるように設定。
database.ymlを下記のように書き換え
database.ymlmelonpan_production_for_nice_stick_development: <<:default host: 127.0.0.1 port: 60008 database: melonpan_production username: <%= ENV['DB_USERNAME'] %> password: <%= ENV['DB_PASSWORD'] %>これでRailsサーバを起動したところ、RDSに接続してデータを取得できた。
都度設定するのは面倒なので、後で.bashrcあたりにでも書き込んでおく。本番サーバでは不要な手続きなので、developmentとproduction/stagingでは、database.yml での記述を変える。
database.yml(本番記述例)melonpan_production_for_nice_stick_production: <<:default host: xxxxxxxx.yyyyyyyy.ap-northeash-1.rds.amazonaws.com database: melonpan_production username: <%= Rails.application.credentials.melonpan_production_database_user %> password: <%= Rails.application.credentials.melonpan_production_database_pass %>開発時のmelonpan_productionへの接続は、melonpan_production_for_nice_stick_developmentを、
本番はmelonpan_production_for_nice_stick_productionを使うようにする
(modelディレクトリ内で、melonpanモジュールを作っているのは、本体と別アプリのテーブルの名前空間を分けて名前衝突を防ぐため)app/model/melonpan/melonpan_db_connection.rb#frozen_string_literal: true module Melonpan class MelonpanDbConnection < ActiveRecord::Base self.abstract_class = true establish_connection: "melonpan_production_for_nice_stick_#{Rails.env}".to_sym end endあとは、実際に接続してデータを取得するクラスで、MelonpanDbConnectionを継承すればOK。
これで、開発環境はポートフォワーディング経由で、本番環境は直接接続というように切り分けられた。P.S.
この問題の解決に実働30時間も費やしたのがくやしいし認証プロキシつらい。
- 投稿日:2019-07-28T19:33:53+09:00
【Rails】LINEログインでemailを取得する
こんにちは!本日はLINEログイン時にemailを取得する方法をお伝えします!
facebookは取得できるのに、LINEはgemのデフォルトで取ってこれていないようでした。
そこで必要な部分をオーバーライドして使います!(【注意】本記事はomniauth-lineのプラグインを利用しています)
【目次】
LINE delvelopers
でemail取得申請をする- omniauth-lineをオーバーライドして
id_token
のペイロードからemailを取得する1.LINE delvelopersでemail取得申請をする
やることは簡単で、LINE側に
LINEログインの時にemail情報使わせてお願い!
と申請するだけです。
(その際に、ユーザーに許可を求めている文言等の確認を送る、そして待つ(1日くらい?))↓こちらに関しては公式ドキュメント・他の方々の記事が参考になります。↓
メールアドレス取得権限を申請する(公式)
RailsでOpenID connectを用いたLINEログイン2.omniauth-lineをオーバーライドして
id_token
からemailを取得するここからが出番です!
【結論】以下のように
omniauth-line
gemのomniauth/strategies/line.rbオーバーライドするだけです。# app/config/initializers/omniauth/strategies/line.rb require 'omniauth-oauth2' module OmniAuth module Strategies class Line < OmniAuth::Strategies::OAuth2 option :scope, 'email profile openid' #追記 info do { name: raw_info['displayName'], image: raw_info['pictureUrl'], description: raw_info['statusMessage'], email: JWT.decode(access_token.params['id_token'], ENV['LINE_CHANNEL_SECRET']).first['email'] #追記 } end end end end
option :scope
→ユーザーが付与する権限
option :scope
で
(ユーザーが付与する権限に実際に確認して見ます(以下の情報は加工してあります)。
# access_token.params['id_token'] <OmniAuth::AuthHash credentials= #<OmniAuth::AuthHash expires=true expires_at=1566893036 refresh_token="sAuxKnUCETKgOYs2ll7J" token="eyJhbGciOiJIUzI1NiJ9.Hj3glrwEWDOPWZNnTLjqsdy2l78TgLlZYVX3AurU6dPhenV4u_G5sZ_aqVWfwmVWcvYlF_Rhf- 6D_BoRqMY66lMAa0sb63mvsma1d_av1JZgl8TrpN9WLi4p7UfWxv3QvM8lEQn0qZrQeU3Vp88Kv097jRKgdC7Z364TgZZD6OU.CEouR6pTTLEHp..."> extra=#<OmniAuth::AuthHash> info=#<OmniAuth::AuthHash::InfoHash description=nil email="eyJ0eXAiOiJKV1QiLCJhbGciOdcdscsdciJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FjY2Vzcy5saW5lLm1lIiwic3ViIjoiVTNlcdcsNGJkNjYyOTU4NjIzMTVkYmRmODVmNGMxMDY1M2Y2IiwiYXVkIjoiMTYxNjIyOTMxNCIsImV4cCI6M..." image="https://profile.line-scdn.net/0hk1oz7EfkNB5cdc... name="example"> provider="line" uid="U3e4bd6629586..." >
OmniAuth::AuthHash
(id_tokenのペイロード)にemail情報が含まれていますね!
しかし、現状だとわからないのでJWTでデコードします。
ENV['LINE_CHANNEL_SECRET']
はLINEのChannel Secret
のことです。JWT.decode(access_token.params['id_token'], ENV['LINE_CHANNEL_SECRET'])すると以下のように
<OmniAuth::AuthHash credentials=#<OmniAuth::AuthHash expires=true expires_at=1566894068 refresh_token="UvrpsvdMgwNYHLC4LO9j" token="eyJhbGciOiJIUzI1NiJ9.Cl3zWMKrL6g59qIbWWk0nhdfhNLFB7NNZiSIoHI8zKq89BW77wIx-jregc-jxfENUYwTjZkNwK0lYlz7c4ZRTOcF2iWJK3zl1aTKroyF9lfNj1aThmBeyVioNvbbfSIjLmdpK2jjBh1E2j59D_twbHWTFWiAwuI7qokOp_z8lbI.G8QUoudL46KbuyqhN7UpvBa1PenH6MDQvNPrD_tGz-8"> extra=#<OmniAuth::AuthHash> info=#<OmniAuth::AuthHash::InfoHash description=nil email=[#<OmniAuth::AuthHash amr=#<Hashie::Array ["linesso"]> aud="1616229314" # emailが認識できるようになる! email="example@gmail.com" exp=1564305669 iat=1564302069 ・ ・ ・email情報が認識できる形になりましたね!
JSON Web Tokens - jwt.ioでもペイロードさえ入力すればデコードしてくれるのでJWTが何をしているかよくわからない方はおすすめです。これでemailの取得は完了です。
request.env['omniauth.auth']
からでもemailからでも取得できるので
formのvalue
に入れて初期値っぽくしてしまいましょう!p request.env['omniauth.auth'][email] > example@gmail.comおまけ
副業案件お待ちしております。得意分野はRuby on Railsです!
職務経歴書
- 投稿日:2019-07-28T19:30:19+09:00
RailsへのBootstrap導入方法
RailsへのBootstrap導入方法 備忘録
1. Gemfile
Gemfileに以下4点を追加する
gem "sass-rails", "~>5.0" gem "bootstrap-sass", "~>3.3.6" gem "jquery-rails" gem "jquery-ui-rails"
![]()
2. bundle update
ターミナルにて bundle update を実行
3. csccファイル変更
ファイル名変更
/app/assets/stylesheets/application.css から
/app/assets/stylesheets/application.scss へ末に以下2点を追加
@import "bootstrap-sprockets"; @import "bootstrap";
![]()
4. jsファイル変更
/app/assets/javascripts/application.js
以下2点を追加(図では13、18行目)
//= require jquery //= require bootstrap-sprockets
![]()
実際に使ってみる
https://getbootstrap.com/
今回はGemfileにてversion3系を指定したので、v3.3.7 を選択使いたいデザインを探して…
htmlにclassを適用する
無事にデザインが反映されました
- 投稿日:2019-07-28T18:50:18+09:00
Sprockets::FileNotFoundを解決する
- 投稿日:2019-07-28T18:50:18+09:00
Sprockets::FileNotFoundを解決する。
- 投稿日:2019-07-28T18:46:36+09:00
DockerのみでつくるRailsプロジェクト
概要
Railsプロジェクトを作成する際にDocker環境があるのにわざわざローカル環境にRubyを入れて…は効率が悪すぎるので、Rubyコンテナを使用してRailsプロジェクトを作成しました。
忘備録に手順をまとめたので同じようにRailsプロジェクトを作成したい方の助けになればいいと思います。環境
- macOS Mojave 10.14
- Docker version 18.09.2, build 6247962
rubyコンテナの取得
DockerHubよりRubyイメージを取得
$ docker pull ruby:2.6.3 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ruby 2.6.3 f1c13927d193 13 days ago 870MBGemfileの生成
Rubyイメージからコンテナを作成し、Gemfileを生成する。
// コンテナの起動 $ docker run --rm -v `pwd`:/myapp -w /myapp -it ruby:2.6.3 bash // オプション --rm: 実行後のコンテナを削除 -v: 共有ディレクトリの設定 -w: ワーキングディレクトリの設定 -it: コンテナをフォアグラウンドで実行 // Gemfileの生成 root@a1eeb5367697:/myapp# bundle init Writing new Gemfile to /myapp/GemfileGemfileの編集
Gemfileを編集し、Railsをインストールするように変更する。
Gemfile- # gem "rails" + gem "rails"Dockerfile、docker-compose.ymlの作成
コンテナを作成するDockerfileとdocker-compose.ymlを作成する。
各ファイルは下記のようにディレクトリを作成し、配置する。ディレクトリ構成
├ docker-compose.yml └ docker ├ mysql │ ├ volumes ← DB永続化用ディレクトリ │ └ password.env └ rails └ Dockerfileファイル内容
DockerfileFROM ruby:2.6.3 ENV LANG C.UTF-8 RUN set -x && \ : "前提パッケージのインストール" && \ apt-get update -qq && \ apt-get install -y \ build-essential \ mysql-client \ nodejs RUN set -x && \ : "パッケージのインストール" && \ gem install bundler WORKDIR /tmp ADD Gemfile Gemfile ADD Gemfile.lock Gemfile.lock RUN bundle install ENV APP_HOME /myapp RUN mkdir -p $APP_HOME WORKDIR $APP_HOME ADD . $APP_HOMEdocker-compose.ymlversion: '3' services: db: image: mysql:5.7.26 ports: - "3306:3306" volumes: - ./docker/mysql/volumes:/var/lib/mysql env_file: ./docker/mysql/password.env web: build: context: . dockerfile: ./docker/rails/Dockerfile command: bundle exec rails s -p 3000 -b '0.0.0.0' ports: - "3000:3000" volumes: - .:/myapp environment: RAILS_ENV: development env_file: ./docker/mysql/password.env depends_on: - dbDBのパスワードを設定
password.envMYSQL_ROOT_PASSWORD=passwordRailsプロジェクトの生成
Dockerfile、docker-compose.ymlで定義したコンテナのビルドを行い、コンテナにログインする。
// コンテナビルド $ docker-compose build // コンテナにログイン $ docker-compose up -d $ docker-compose exec web bash // オプション -d: バックグラウンド実行 // railsプロジェクトの生成 root@477e08f00455:/var/www/CleanManager# rails new . -d mysql -BT // オプション -d: DBをmysqlに設定 -B: bundle installを省略 -T: テストファイルの作成を省略 // パッケージのインストール root@477e08f00455:/var/www/CleanManager# bundle installrailsアプリの起動
コンテナの再起動を行う。
docker-compose.ymlにビルドインサーバを起動するコマンドを記述しているため、別途起動するコマンドを実行する必要はない。
再起動後、ブラウザで http://localhost:3000 にアクセスし起動していることを確認する。root@477e08f00455:/var/www/CleanManager# exit $ docker-compose down $ docker-compose up -dまとめ
Docker初心者だったので、よくわからないことがありましたが、なんとか作成することができました。
DBをMySQLからPostgreSQLに変更したかったのですが、PostgreSQLコンテナが起動直後に落ちてしまったのでMySQLで妥協しました。
今後も原因を探して判明しだい、再度記事にしたいと思います。
間違い等ありましたら、コメントから修正お願いします。
- 投稿日:2019-07-28T18:18:07+09:00
Cannot find module '@rails/webpacker' を解決する
対象者
Rails5 + webpack のプロジェクトを作成したが、以下エラーが出現する方
エラー
$ bin/webpack-dev-server The CLI moved into a separate package: webpack-cli. Please install 'webpack-cli' in addition to webpack itself to use the CLI. -> When using npm: npm install webpack-cli -D -> When using yarn: yarn add webpack-cli -D module.js:557 throw err; ^ Error: Cannot find module '@rails/webpacker' at Function.Module._resolveFilename (module.js:555:15) at Function.Module._load (module.js:482:25) at Module.require (module.js:604:17) at require (internal/module.js:11:18) at Object.<anonymous> (.../appname/node_modules/webpack-dev-server/bin/webpack-dev-server.js:64:1) at Module._compile (module.js:660:30) at Object.Module._extensions..js (module.js:671:10) at Module.load (module.js:573:32) at tryModuleLoad (module.js:513:12) at Function.Module._load (module.js:505:3)原因
@rails/webpackerがインストールされていない。
(私の場合、yarnがインストールいなかった為、
rails new app --webpack=vue
実行後にrails/webpackerがインストール出来ない旨のエラーが出力されていた。)解決
yarnをインストールし、Railsプロジェクトを再作成する。
手順
1. yarnをインストール
# インストール $ brew install yarn # インストール出来たか確認 $ yarn -v 1.17.32. Rails + webpackプロジェクトを新規作成
$ rails new app --webpack=vue $ cd app $ rails g scaffold pages $ rails db:migrate3. ファイルを編集
2.のコマンド実行により作成された以下2つのファイル
index.html.erb, routes.rb
を下記のように置き換える。app/views/pages/index.html.erb<%= javascript_pack_tag "hello_vue" %>config/routes.rbRails.application.routes.draw do root "pages#index" # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end4. Railsサーバーを起動
$ rails server
5. ローカルホストを確認
http://localhost:3000/ にアクセス
以上。
参考
- 投稿日:2019-07-28T17:00:08+09:00
【Rails】 RSpecでNoMethodErrorと言われた人へ
エラーの内容
ターミナルで
bundle exec rspec
を実行すると以下のような文が表示されてしまい、テストの判定が行われませんでした。undefined method `build' for #<RSpec::ExampleGroups::User::Create:~~~~~> undefined method `create' for #<RSpec::ExampleGroups::User::Create:~~~~~>解決法
1. spec以下にフォルダを作成する
"spec/support/factory_bot.rb"を作成します。
2. factory_bot.rbに次の内容を記述する
factory_bot.rbRSpec.configure do |config| config.include FactoryBot::Syntax::Methods end3. rails_helper.rbで2のファイルを読み込む
rails_helper.rbrequire 'support/factory_bot'ここまで終えて、もう一度
bundle exec rspec
を実行したところ、無事にテストコードの判定を行うことができました。参考
Stack Overflow「
undefined method `build' for #<RSpec::ExampleGroups::UserName:>
」以上を参考に解決することができました。ありがとうございます。
さいごに
前例探しに手間取ったので、記事として残します。同じエラーに遭遇した方の参考になれば幸いです。なお、理屈についてはいまの私では説明できないため、未来の私への覚書も兼ねています。
- 投稿日:2019-07-28T16:12:12+09:00
【Rails】エラーメッセージをviewに表示する仕組み。errors.any? を使って
バージョン
Rails 5.0.7.2
はじめに
Railsのモデル(model)でバリデーション(Validation)エラーが発生した場合に、対応するビュー(view)にエラー内容を表示する。
エラー出力のイメージ
Nameタブが空欄のままCreate Groupした時にエラー出力
処理の流れ
1.モデル(model)クラスにバリデーション(Validation)を設定
validatesメソッドについて
validates(検証するフィールド名, :length => 検証パラメータ)
以下のモデル(model)ではvalidatesメソッドの第一引数にgroupTBLのnameカラムを設定。
第二引数以降に検証パラメータを設定している。この場合、1.上記スナップショットのnameフォームが空欄であることを非許容
2.nameフォームは本アプリケーションないで一意になることとなる
group.rbclass Group < ApplicationRecord has_many :members has_many :users, through: :members has_many :messages validates :name, presence: true, uniqueness: true end2.コントローラ(controller)に条件分岐を設定する
saveに成功したらrootに設定したビュー(view)にリダイレクト
savaに失敗したらrenderでedit.html.hamlに再度遷移させるgroups_controller.rb#必要な箇所だけ抜粋 class GroupsController < ApplicationController def create @group = Group.new(group_params) if @group.save redirect_to root_path, notice: 'グループを作成しました' else render :new end end3.ビュー(view)にエラー出力を定義
hamlで書いています。
ビューのエラー文を表示したい箇所に「if 〇〇.errors.any?」を記載する。
モデル(model)でバリデーションエラーが発生した場合、modelのerrorsにエラーメッセージが設定さる。さらに、full_messagesでバリデーションのエラーメッセージを配列で取得できる。
@group.errors.full_messagesでエラーを全て表示。
@group.errors.full_messages.countで件数を表示できる。edit.html.haml#必要な箇所だけ抜粋 .chat-group-form %h1 新規チャットグループ = form_for @group do |f| - if @group.errors.any? .chat-group-form__errors %h2= "#{@group.errors.full_messages.count}件のエラーが発生しました。" %ul - @group.errors.full_messages.each do |message| %li= message .chat-group-form__field .chat-group-form__field--left = f.label :name, class: 'chat-group-form__label' .chat-group-form__field--right = f.text_field :name, class: 'chat__group_name chat-group-form__input', placeholder: 'グループ名を入力してください'以上ざくっと。
- 投稿日:2019-07-28T16:12:12+09:00
【Rails】エラーメッセージをviewに表示する仕組み errors.any?
バージョン
Rails 5.0.7.2
はじめに
Railsのモデル(model)でバリデーション(Validation)エラーが発生した場合に、対応するビュー(view)にエラー内容を表示する。
エラー出力のイメージ
Nameタブが空欄のままCreate Groupした時にエラー出力
処理の流れ
1.モデル(model)クラスにバリデーション(Validation)を設定
validatesメソッドについて
validates(検証するフィールド名, :length => 検証パラメータ)
以下のモデル(model)ではvalidatesメソッドの第一引数にgroupTBLのnameカラムを設定。
第二引数以降に検証パラメータを設定している。この場合、1.上記スナップショットのnameフォームが空欄であることを非許容
2.nameフォームは本アプリケーションないで一意になることとなる
group.rbclass Group < ApplicationRecord has_many :members has_many :users, through: :members has_many :messages validates :name, presence: true, uniqueness: true end2.コントローラ(controller)に条件分岐を設定する
saveに成功したらrootに設定したビュー(view)にリダイレクト
savaに失敗したらrenderでedit.html.hamlに再度遷移させるgroups_controller.rb#必要な箇所だけ抜粋 class GroupsController < ApplicationController def create @group = Group.new(group_params) if @group.save redirect_to root_path, notice: 'グループを作成しました' else render :new end end3.ビュー(view)にエラー出力を定義
hamlで書いています。
ビューのエラー文を表示したい箇所に「if 〇〇.errors.any?」を記載する。
モデル(model)でバリデーションエラーが発生した場合、modelのerrorsにエラーメッセージが設定さる。さらに、full_messagesでバリデーションのエラーメッセージを配列で取得できる。
@group.errors.full_messagesでエラーを全て表示。
@group.errors.full_messages.countで件数を表示できる。edit.html.haml#必要な箇所だけ抜粋 .chat-group-form %h1 新規チャットグループ = form_for @group do |f| - if @group.errors.any? .chat-group-form__errors %h2= "#{@group.errors.full_messages.count}件のエラーが発生しました。" %ul - @group.errors.full_messages.each do |message| %li= message .chat-group-form__field .chat-group-form__field--left = f.label :name, class: 'chat-group-form__label' .chat-group-form__field--right = f.text_field :name, class: 'chat__group_name chat-group-form__input', placeholder: 'グループ名を入力してください'以上ざくっと。
- 投稿日:2019-07-28T16:12:12+09:00
【Rails】エラーメッセージをviewに表示する仕組み。 〜errors.any?〜を使って
バージョン
Rails 5.0.7.2
はじめに
Railsのモデル(model)でバリデーション(Validation)エラーが発生した場合に、対応するビュー(view)にエラー内容を表示する。
エラー出力のイメージ
Nameタブが空欄のままCreate Groupした時にエラー出力
処理の流れ
1.モデル(model)クラスにバリデーション(Validation)を設定
validatesメソッドについて
validates(検証するフィールド名, :length => 検証パラメータ)
以下のモデル(model)ではvalidatesメソッドの第一引数にgroupTBLのnameカラムを設定。
第二引数以降に検証パラメータを設定している。この場合、1.上記スナップショットのnameフォームが空欄であることを非許容
2.nameフォームは本アプリケーションないで一意になることとなる
group.rbclass Group < ApplicationRecord has_many :members has_many :users, through: :members has_many :messages validates :name, presence: true, uniqueness: true end2.コントローラ(controller)に条件分岐を設定する
saveに成功したらrootに設定したビュー(view)にリダイレクト
savaに失敗したらrenderでedit.html.hamlに再度遷移させるgroups_controller.rb#必要な箇所だけ抜粋 class GroupsController < ApplicationController def create @group = Group.new(group_params) if @group.save redirect_to root_path, notice: 'グループを作成しました' else render :new end end3.ビュー(view)にエラー出力を定義
hamlで書いています。
ビューのエラー文を表示したい箇所に「if 〇〇.errors.any?」を記載する。
モデル(model)でバリデーションエラーが発生した場合、modelのerrorsにエラーメッセージが設定さる。さらに、full_messagesでバリデーションのエラーメッセージを配列で取得できる。
@group.errors.full_messagesでエラーを全て表示。
@group.errors.full_messages.countで件数を表示できる。edit.html.haml#必要な箇所だけ抜粋 .chat-group-form %h1 新規チャットグループ = form_for @group do |f| - if @group.errors.any? .chat-group-form__errors %h2= "#{@group.errors.full_messages.count}件のエラーが発生しました。" %ul - @group.errors.full_messages.each do |message| %li= message .chat-group-form__field .chat-group-form__field--left = f.label :name, class: 'chat-group-form__label' .chat-group-form__field--right = f.text_field :name, class: 'chat__group_name chat-group-form__input', placeholder: 'グループ名を入力してください'以上ざくっと。
- 投稿日:2019-07-28T15:57:30+09:00
deviseについて
Deviseのドキュメントを一通り読んだので、今の自分に必要な部分のみ訳していきました。
1.deviseの導入
Gemfile.rbに
Gemfile.rbgem 'devise'この記述をして、
$ bundle install $ rails g devise:installこれだけで、deviseをインストールができます。
2.deviseのセットアップ
rails g devise:install後、以下のような文章が現れます。
Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> 4. You can copy Devise views (for customization) to your app by running: rails g devise:views1.はメール認証機能を実装したときに、メール認証のメールに記載するURLを設定する部分なので、実際にサービスを運用するときには編集します。deviseのチュートリアルなどを勉強している段階ではあまり関係ないです。
2.はrootのurlを何かしら設定しなさいという内容なので、適当にhomeコントローラーを作って、indexアクションに飛ばしておきます。
$ rails g controller home index
config/routes.rb#rootにhome#indexを追加 root to: "home#index"3.flashメッセージを設定しなさいということなのですが、なくてもこの先に進めます。railsでwebアプリを作っていると、application.html.erbの本文は<% yield %>だけなので、layoutディレクトリにflashメッセージを記述するためのパーシャル(_flash.html.erb)を作って、その中にflashメッセージを表示する記述をしておくといいでしょう。
_flash.html.erb<% flash.each do |key, value| %> <%= content_tag(:div, value, class: "flash flash_#{key}") %> <% end %>flashメッセージをapplication.html.erbで描画するために、renderを使って結果を表示します。
application.html.erb<body> <%= render 'layouts/flash' %> <%= yield %> </body>こんなもんでしょうか。
4.はview画面を作り込みたいときに使用します。
$ rails g devise:views
これで下準備ができました。ユーザー登録をするために、Userモデルを作成し、データベースを作りましょう。
3.モデルの作成
$ rails g devise User
1.の言う通りメール認証を追加するならば、ここでConfirmableをアンコメントアウトしておきます。
○○○○○○○○○○_devise_create_users.rbConfirmable t.string :confirmation_token t.datetime :confirmed_at t.datetime :confirmation_sent_at <img width="982" alt="スクリーンショット 2019-07-28 13.23.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/460758/9a233b84-0dff-a80c-384d-01b96e2c6675.png"> t.string :unconfirmed_email # Only if using reconfirmable機能を解説しているだけなので、ここは何も追加しません。
$ bundle exec rake db:migrate続いてユーザーモデルを編集しましょう。
user.rbdevise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :confirmable #デフォルトではvalidateableまでの5つの記述がありますが、メール認証の機能を追加するために、:confirmableを追加しておきましょう。続いて、index.html.erbに簡単なユーザー登録とログアウトボタンを作ります。
index.html.erb<%= link_to "ユーザー登録", new_user_registration_path %> <%= link_to "ログアウト", destroy_user_session_path, method: "delete" %>これで最低限の機能が実装されましたので、実際にユーザー登録機能を使ってみましょう。
$ rails s
devise関連の設定を行ったら、rails sを再度立ち上げること!!!これをしないと、いつまでたっても変更が反映されせん!!!
localhost:3000に接続すると下のような画面が出てきます。
登録後の画面に先ほどの3.で設定した、flashメッセージが出てきます。
この時点ではまだログインされておらず、登録しようとしたemailアドレスに認証メールを送った段階のため、コンソールを一度確認します。
吐き出されたメッセージをみてみると、登録したアドレスに認証アドレスを記載したメールを送りましたよとあるので(実装してないので、実際はメールはきません。)、aタグのリンクをコピぺして接続すると
無事、認証されてログインされました。deviseを導入した時点で、以下のヘルパーメソッドが使えるようになっているので、必要に応じてbefore_actionに付け加えたり、使用しましょう。
before_action :authenticate_user! #オプションでonlyを設定して、ログインしているユーザーにのみ、設定したアクションへのアクセス権限を与える。デフォルトではすべてのアクションにアクセス制限がかかっています。 user_signed_in? #ユーザーがログイン済みかどうか判定するメソッド。 current_user #現在ログインしているユーザーの情報を取得する。 user_session #sessionの情報を取得する。 #userには各自で設定したモデル名が入るので、memberモデルでdeviseを設定したら、member_signed_in?になります。4.ストロングパラメーターの設定
デフォルトではユーザー情報はemailとpasswordしか(他にもありますが、ユーザーが設定する情報ではないので割愛)ないので、ユーザー名などを追加で設定したいと考える方は大勢いるでしょう。
しかし、モデルに渡すパラメーターは下記のようにdevise側で設定されている状態のため、追加したい場合はdeviseのコントローラーファイルは作成されないため、applicationコントローラー中で、configure_permitted_parametersメソッドを設定して、許可するパラメーターを追加します。
#デフォルトでdeviseが設定している、モデルに渡せるパラメーター POST /users/sign_in => devise/session#create #ユーザーのログイン時 => emailのみ POST /users/sign_up => devise/resistrations#create #ユーザー登録時 => email, password, password_confirmationのみ PATCH /users => devise/resistrations#update #ユーザー情報の更新時 => email, password, password_confirmationのみapplication_controller.rb#パラメーターを追加したい場合 class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? #deviseに関連するアクションか判定して、trueならばparameterを追加する protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys:[:name]) end #sign_upのルーティングに、:nameのパラメーターを許可する。 end駆け足で解説しましたが、間違っていたらご指摘ください。
- 投稿日:2019-07-28T15:16:09+09:00
日付をX軸としたamChartsの折れ線グラフで初期表示(ズーム後)を直近の1週間表示に変更する
概要
amChartsのDate Based Dataを使用しグラフを作成します。
こちらのグラフは起動時に全体を表示し、”最終日からある割合”の日付をズームして表示します。(かっこいい)
Demo source
この”最終日からある割合”を”直近の1週間”に変更していきたいとおもいます。(上のDemo sourceのgifでは直近の8日にプロットされた値が表示されてますね)作成する前提
amChartsがCDNで読み込めている
参考文献amcharts 4 Demos を使ってグラフを作成(amChartsの導入方法が記載されています)
使用するグラフの種類:Date Based Data
使用するモデル:Railsにて不連続な間隔(日付など)で投稿された値をamChartsを使って折れ線グラフを作成する。において作成した体重管理アプリをモデルに作成します。コントローラーファイルなどの記述はこちらを参考にしてください。編集するファイル
・ビューファイル
ビューファイル(Demo source)
まずは、Demo sourceがどういう構造になっているか見てみましょう。
demo.erb<!-- Styles --> <style> #chartdiv { width: 100%; height: 500px; } </style> <!-- Resources --> <script src="https://www.amcharts.com/lib/4/core.js"></script> <script src="https://www.amcharts.com/lib/4/charts.js"></script> <script src="https://www.amcharts.com/lib/4/themes/animated.js"></script> <!-- Chart code --> <script> am4core.ready(function() { // Themes begin am4core.useTheme(am4themes_animated); // Themes end // Create chart instance var chart = am4core.create("chartdiv", am4charts.XYChart); // Add data chart.data = [{ "date": "2012-07-27", "value": 13 }, { "date": "2012-07-28", "value": 11 }, { "date": "2012-07-29", "value": 15 }, { //~省略~ "date": "2013-01-30", "value": 81 }]; // Set input format for the dates chart.dateFormatter.inputDateFormat = "yyyy-MM-dd"; // Create axes var dateAxis = chart.xAxes.push(new am4charts.DateAxis()); var valueAxis = chart.yAxes.push(new am4charts.ValueAxis()); // Create series var series = chart.series.push(new am4charts.LineSeries()); series.dataFields.valueY = "value"; series.dataFields.dateX = "date"; series.tooltipText = "{value}" series.strokeWidth = 2; series.minBulletDistance = 15; // Drop-shaped tooltips series.tooltip.background.cornerRadius = 20; series.tooltip.background.strokeOpacity = 0; series.tooltip.pointerOrientation = "vertical"; series.tooltip.label.minWidth = 40; series.tooltip.label.minHeight = 40; series.tooltip.label.textAlign = "middle"; series.tooltip.label.textValign = "middle"; // Make bullets grow on hover var bullet = series.bullets.push(new am4charts.CircleBullet()); bullet.circle.strokeWidth = 2; bullet.circle.radius = 4; bullet.circle.fill = am4core.color("#fff"); var bullethover = bullet.states.create("hover"); bullethover.properties.scale = 1.3; // Make a panning cursor chart.cursor = new am4charts.XYCursor(); chart.cursor.behavior = "panXY"; chart.cursor.xAxis = dateAxis; chart.cursor.snapToSeries = series; // Create vertical scrollbar and place it before the value axis chart.scrollbarY = new am4core.Scrollbar(); chart.scrollbarY.parent = chart.leftAxesContainer; chart.scrollbarY.toBack(); // Create a horizontal scrollbar with previe and place it underneath the date axis chart.scrollbarX = new am4charts.XYChartScrollbar(); chart.scrollbarX.series.push(series); chart.scrollbarX.parent = chart.bottomAxesContainer; chart.events.on("ready", function () { dateAxis.zoom({start:0.79, end:1}); }); }); // end am4core.ready() </script> <!-- HTML --> <div id="chartdiv"></div>なんだか難しそうで、なにを書いているかパッとみたただけではわかりませんね。
ただ、データが記載されているところはわかるのではないでしょうか?demo.erb<script> // Add data chart.data = [{ "date": "2012-07-27", "value": 13 }, { "date": "2012-07-28", "value": 11 }, { "date": "2012-07-29", "value": 15 }, { //~省略~ "date": "2013-01-30", "value": 81 }]; </script>↑ここです。
この部分を体重管理アプリのモデルに合わせていきます。ビューファイル(本アプリ)
まずは、コントローラーから変数をもってきて算出までします。
index.erb<script> //JSON形式で値を渡す const weights = <%== JSON.dump(@weights) %>; const dates = <%== JSON.dump(@dates) %>; //表示期間を計算 var firstDate = new Date(dates[0]) //一番最初 var lastDate = new Date(dates.slice(-1)[0]) //一番最後 var termDate= (lastDate - firstDate)/ 1000 / 60 / 60 / 24 + 1 //表示する期間 </script>細かいところはRailsにて不連続な間隔(日付など)で投稿された値をamChartsを使って折れ線グラフを作成する。を参照してください。(本記事をそのままコピペしても動きません)
さて、Demo sourceのchart.dataの値を下記のように変えてください。index.erb<script> // Add data chart.data = []; for (var j =0; j< weights.length; j++){ for (var i = 0; i < termDate; i++) { var newDate = new Date(firstDate) newDate.setDate(newDate.getDate() + i); //初日からi日分たす if ((new Date(dates[j])) - (newDate)==0){ weight =weights[j] chart.data.push({ date: newDate, weight: weight }); } } } </script>valueはRailsにて不連続な間隔(日付など)で投稿された値をamChartsを使って折れ線グラフを作成する。のときと同様にweightに変更してます。weightの変更箇所はその他にもあるのですべて置換してあげてください。
初期表示(ズーム後)を直近の1週間表示にする
本記事の本題です。
まずはDemo sourceからズームっぽい記述を探してみましょう。後方から9行目付近をみてください。demo.erb<script> chart.events.on("ready", function () { dateAxis.zoom({start:0.79, end:1}); }); </script>{start:0.79, end:1}の数値を試しに{start:0, end:1}かえてみてください。
変えるときは、【小ネタ】amChartsのDemo sourceをVScodeなどのエディタにコピペせず、ブラウザ上でプロパティを変更し表示を確認する方法を使うと便利です。
zoomされず、全体が表示されました。
ということは、startの数値を変更すれば直近の1週間が表示できそうです。全体の日数はtermDateという変数で取得できてるので、
1週間は全体の日数のどれくらいの割合か出してみます。
例:termDateが70日の場合
式: 7/termDate=0.1
0.1という数値をstartに入れては駄目です。なぜならstartは0に近いほど、小さい値(日付)を取得します。
なので0.1を入れると0.1≦x≦1の範囲になり(endが1の場合)、一番古い日付から1週間後から最新の日付を範囲としてしまいます。
では、どうするかというと1から引いてあげれば良いです。{start:1-7/termDate, end:1}としてあげます。
こうすることで0.9≦x≦1となり、直近の1週間の割合がだせます。
最後にビューファイルの全体を記載します。index.erb<!-- Styles --> <style> #chartdiv { width: 100%; height: 500px; } </style> <!-- Resources --> <script src="https://www.amcharts.com/lib/4/core.js"></script> <script src="https://www.amcharts.com/lib/4/charts.js"></script> <script src="https://www.amcharts.com/lib/4/themes/kelly.js"></script> <script src="https://www.amcharts.com/lib/4/themes/animated.js"></script> <!-- Chart code --> <script> am4core.ready(function() { // Themes begin am4core.useTheme(am4themes_kelly); am4core.useTheme(am4themes_animated); // Themes end // Create chart instance var chart = am4core.create("chartdiv", am4charts.XYChart); const weights = <%== JSON.dump(@weights) %>; const dates = <%== JSON.dump(@dates) %>; var firstDate = new Date(dates[0]) var lastDate = new Date(dates.slice(-1)[0]) var termDate= (lastDate - firstDate)/ 1000 / 60 / 60 / 24 + 1 // Add data chart.data = []; for (var j =0; j< weights.length; j++){ for (var i = 0; i < termDate; i++) { var newDate = new Date(firstDate) newDate.setDate(newDate.getDate() + i); //初日からi日分たす if ((new Date(dates[j])) - (newDate)==0){ weight =weights[j] chart.data.push({ date: newDate, weight: weight }); } } } // Set input format for the dates chart.dateFormatter.inputDateFormat = "yyyy-MM-dd"; // Create axes var dateAxis = chart.xAxes.push(new am4charts.DateAxis()); var valueAxis = chart.yAxes.push(new am4charts.ValueAxis()); // Create series var series = chart.series.push(new am4charts.LineSeries()); series.dataFields.valueY = "weight"; series.dataFields.dateX = "date"; series.tooltipText = "{weight}" series.strokeWidth = 2; series.minBulletDistance = 15; // Drop-shaped tooltips series.tooltip.background.cornerRadius = 20; series.tooltip.background.strokeOpacity = 0; series.tooltip.pointerOrientation = "vertical"; series.tooltip.label.minWidth = 40; series.tooltip.label.minHeight = 40; series.tooltip.label.textAlign = "middle"; series.tooltip.label.textValign = "middle"; // Make bullets grow on hover var bullet = series.bullets.push(new am4charts.CircleBullet()); bullet.circle.strokeWidth = 2; bullet.circle.radius = 4; bullet.circle.fill = am4core.color("#fff"); var bullethover = bullet.states.create("hover"); bullethover.properties.scale = 1.3; // Make a panning cursor chart.cursor = new am4charts.XYCursor(); chart.cursor.behavior = "panXY"; chart.cursor.xAxis = dateAxis; chart.cursor.snapToSeries = series; // Create vertical scrollbar and place it before the value axis chart.scrollbarY = new am4core.Scrollbar(); chart.scrollbarY.parent = chart.leftAxesContainer; chart.scrollbarY.toBack(); // Create a horizontal scrollbar with previe and place it underneath the date axis chart.scrollbarX = new am4charts.XYChartScrollbar(); chart.scrollbarX.series.push(series); chart.scrollbarX.parent = chart.bottomAxesContainer; chart.events.on("ready", function () { dateAxis.zoom({start:1-7/termDate, end:1}); }); }); // end am4core.ready() </script> <!-- HTML --> <div id="chartdiv"></div>完成!!
参考文献
Railsにて不連続な間隔(日付など)で投稿された値をamChartsを使って折れ線グラフを作成する。
最後に
この記事を書いた目的
・自分なりに工夫した点をアウトプットして、理解を深める。
・あわよくば有識者にフィードバックをもらいたい。
・私と同じ初学者からも奇譚のない意見をもらいたい。(自分だったらどうこうする的な)筆者について
TECH::EXPERTにて4月27日より52期夜間・休日コースでruby/railsを学習している未経験エンジニアです。
ご不備等ありましたら、ご指摘ください。ちなみに本記事が初投稿になります。
言わずもがなかもしれませんが、趣味はボディメイク・筋トレでございます。
余談ですが、120kg⇨66kgまで減量して大会出場した経験があり
ダイエットについての質問はなんでも答えられるかと思いますひとこと
最後までご覧いただきまして、ありがとうございました。
もし気に入っていただけたら、イイね・ストック・フォローご自由に!
- 投稿日:2019-07-28T15:03:08+09:00
Rails + Cropper.jsで画像トリミング機能を実装する
概要
Cropper.jsを用いてRailsでトリミング機能付き画像アップロード機能を実装してみます。
ソースコードは以下に置いてます。
https://github.com/Tak-Iwamoto/jquery-cropper-rails環境
Rails 5.2.2
Bootstrap 4.3.1
active storage
mini_magick 4.9.4active storage
active_storageを利用するために以下のコマンドを実行してください。
rails active_storage:install
rails db:migrate
Cropper.jsの読み込み
https://github.com/fengyuanchen/cropperjs
上のgithubからcropper.min.jsとcropper.min.cssを取得し、Railsの中に配置しましょう。サードパーティライブラリはvendorディレクトリの中に入れることが推奨されており、vendorの中にassets/javascriptsとassets/stylesheetsディレクトリを作成し、それぞれcropper.min.jsとcropper.min.cssを配置します。
https://github.com/fengyuanchen/jquery-cropper
また、JQueryを用いるために上のgithubからjquery-cropper.min.jsを取得し、同様にRailsの中に配置します。最後にapplication.jsとapplication.scssに以下のように編集します。
application.js
//= require rails-ujs
//= require jquery
//= require jquery_ujs
//= require cropper.min.js
//= require jquery-cropper.min.js
//= require activestorage
//= require turbolinks
//= require_tree .
//= require popper
//= require bootstrap-sprockets
application.scss
*= require_tree .
*= require cropper.min.css
*= require_self
*/
これでCropper.jsが使えるようになりました。modelとcontrollerを作成
デモのためのuserモデル、コントローラーを作成します。
user.rbclass User < ApplicationRecord attr_accessor :x, :y, :width, :height has_one_attached :image endusers_controller.rbclass UsersController < ApplicationController def new @user = User.new end def create @user = User.new(user_params) @user.save session[:crop_x] = user_params[:x] session[:crop_y] = user_params[:y] session[:crop_width] = user_params[:width] session[:crop_height] = user_params[:height] redirect_to user_path @user end def show @user = User.find(params[:id]) end private def user_params params.require(:user).permit(:image, :x, :y, :width, :height) end endCropper.jsでトリミングした結果のパラメータをsessionで保持し、のちに画像を表示するときに用いていますが、このやり方は筋が悪い気がしています... active_storageで加工した画像を保存する方法が分からなかったため、この方法で行っていますが、おそらく他にいい方法があると思います。
画像アップロードフォーム
トリミング画像をアップロードするためのフォームを作成します。
new.html.erb<div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <div class="preview" style='overflow:hidden'> <div id="beforeUpload"> <%= icon("fas fa-4x fw","file-image")%> </div> <img src="" id="croppedImage"> </div> <%= form_with model: @user, url: users_path do |f| %> <%= f.file_field :image%> <%= f.hidden_field :x, id:"dataX"%> <%= f.hidden_field :y, id:"dataY"%> <%= f.hidden_field :width, id:"dataWidth"%> <%= f.hidden_field :height, id:"dataHeight"%> <%= f.submit "button", id:"btnUpload", class: 'btn btn-success'%> <% end %> <div class="modal fade" id="cropModal" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-body"> <div class="img-container"> <img src="" id="imageModal" alt="picture"> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" id="btn-save" data-dismiss="modal">Save</button> </div> </div> </div> </div> </div> </div> </div>
<div class="preview" style='overflow:hidden'>
でトリミング後の画像を表示するフィールドを作成しています。。この時、style='overflow:hidden'を指定しないと上手く表示されない場合があります。
トリミング後の画像は<img src="" id="croppedImage">
で表示します。
form_with
でフォームを作成し、トリミングした結果のパラメータはf.hidden_field
でcontrollerに渡して、以下のshow.html.erbで画像を表示する際に用います。
<div class="modal fade" id="cropModal" role="dialog">
以下ではトリミング操作を行うためのmodalをbootstrapによって表示させています。トリミングした画像を表示するために以下のhtmlを作成します。
show.html.erb
<%= image_tag @user.image.variant(crop: "#{session[:crop_width]}x#{session[:crop_height]}+#{session[:crop_x]}+#{session[:crop_y]}") %>
では、トリミング処理を行うために以下のjavascriptファイルを作成します。crop_image.js$(function () { let $image = $('#imageModal'), $img_field = $('#user_image'), $croppedImage = $('#croppedImage'), $cropModal = $('#cropModal'), $beforeUpload = $('#beforeUpload'), $button = $('#btn-save'), $dataX = $('#dataX'), $dataY = $('#dataY'), $dataWidth = $('#dataWidth'), $dataHeight = $('#dataHeight'); let options = { dragmode: 'crop', aspectRatio: 1/1, restore: false, guides: false, center: false, highlight: true, cropBoxMovable: true, cropBoxResizable: true, modal: true, crop: (e) => { $dataX.val(Math.round(e.detail.x)); $dataY.val(Math.round(e.detail.y)); $dataWidth.val(Math.round(e.detail.width)); $dataHeight.val(Math.round(e.detail.height)); } }; // when file upload $img_field.change((e) => { $image.cropper('destroy').removeAttr('src'); file = e.target.files[0]; reader = new FileReader(); if (file.type.indexOf('image') < 0) { window.alert("画像を選択してください"); return ; } reader.onload = ((e) => { $image.attr('src',""); $image.attr('src', e.target.result); $cropModal.modal('show'); $cropModal.on('shown.bs.modal', () => { $image.cropper(options); }); }); reader.readAsDataURL(file); }) // onclick save button $button.click(() => { imgCropping(); }); // modalを閉じたとき、cropper要素を初期化 $cropModal.on('hidden.bs.modal',function() { $image.cropper('destroy').removeAttr('src'); let $cropperContainer = $('.cropper-container'); $cropperContainer.remove(); }); function imgCropping() { if (!croppable) { alert('トリミングする画像が用意されていません') return false; } $beforeUpload.hide(); let croppedData = $image.cropper('getCroppedCanvas').toDataURL(); $croppedImage.attr('src', croppedData); $cropModal.modal('hide'); } });$img_fieldでidがuser_imageのDOMを指定していますが、html側にはそのようなidはありません。Railsはform_withでfile_fieldを作成すると、自動的に
<img id="モデル名_フィールド名">
のタグが作成されるため、注意が必要です。自分もこれが原因でハマってしまいました...optionsではどのように画像をトリミングするか設定しています。
$img_field.change
以下で画像がアップロードされた時にトリミングが開始されるように記述しています。
modalが表示された際、$image.cropper(options)
で先ほど設定したoptionsでcropperインスタンスを作成し、トリミングを行います。また、最初に$image.cropper('destroy')
でcropperインスタンスを初期化していることに注意してください。この処理を行わないと、前にトリミングした画像が残ったままとなり画像が複数表示されたりといった不具合が起こります。また、cropperインスタンスが作成された時点で、
<div class="cropper-container cropper-bg"></div>
のDOMが作成されます。modalを閉じた時点でこのDOMを削除しておかないと前回トリミングした画像が残ったままになっていることがあります。そのため$cropModal.on('hidden.bs.modal'
以下で削除する操作を行っています。以上です。
- 投稿日:2019-07-28T13:31:43+09:00
N+1問題 メモ
- N+1問題とは
- SQLクエリが「データ量N + 1回」走ってしまい、取得するデータが多くなるにつれて(Nの回数が増えるにつれて)パフォーマンスを低下させてしまう問題。
- 関連するテーブルを取得する際に起きる。
- 例
clients = Client.limit(10) clients.each do |client| puts client.address.postcode end上記では最初にクライアントを10人検索するのにクエリを1回発行し、次にそこから住所を取り出すのにクエリを10回発行するので、合計で 11 回のクエリが発行されている。
- 解決方法
- includeメソッドを利用
- includesを指定すると、Active Recordは指定されたすべての関連付けが最小限のクエリ回数で読み込まれるようにしてくれる。clients = Client.includes(:address).limit(10) clients.each do |client| puts client.address.postcode end最初の例では 11 回もクエリが実行されましたが、今度の例ではわずか 2 回にまで減る。
- 投稿日:2019-07-28T11:45:03+09:00
#ruby #rails の #FactoryBot で association を使わずに無理やり BuildStrategy ( create / build / attributes_for ) などを反転して条件分けする例
Example of forcing condition inversion of BuildStrategy (create / build / attributes_for) forcibly without using association in #FactoryBot of #ruby #rails
FactoryBot.define do factory :company do user do build_stragy = self.instance_variable_get(:@build_strategy).class if build_stragy == FactoryBot::Strategy::Create create :user else build :user end end end endOriginal by Github issue
- 投稿日:2019-07-28T10:59:39+09:00
#Ruby / #Rails の #FactoryBot で association 記法を使わずに create と attributes_for の挙動を使い分ける例
- 投稿日:2019-07-28T10:23:56+09:00
【Rails5】外部キーの設定メモ
はじめに
よく忘れてしまうのでメモとして残しときます。
前提条件
また「ユーザーテーブル」はすでに作成している前提で書いていきます。
外部キーの設定
- フォロワーテーブルを作成。
- 作成したマイグレーションファイルに外部キーの設定を追加
- データベースを更新
方法
# ターミナル rails g model follower user:references follower:referencesuser:references
これでreference型のuserカラムを作成しています。
モデルを作成したら以下のマイグレーションファイルも一緒に作成されます。
db/migrate/20190727232828_create_follows.rbclass CreateFollowers < ActiveRecord::Migration[5.2] def change create_table :followers do |t| t.references :user, foreign_key: true t.references :follower, foreign_key: true t.timestamps end end endreference型について
reference型にすると下記の設定が自動でされます。
①カラム名がuserではなくuser_idとして追加される
②自動でindexが追加される
※reference型を指定しても外部キー制約は設定されていないので注意してください。foreign_key: true
外部キー制約が設定されます。
参照するテーブルは指定したモデルのテーブルです。
例えば「t.references :user, foreign_key: true」では
カラム名を指定する箇所で「:user」というモデルが指定されているので、usersテーブルが参照先として設定されます。疑問点
上記の話だと、followerにもuserテーブルを参照先として設定したい時、:userを指定しないといけなくなる。
そうすると2個目のuser_idが出来上がってしまう。エラー出ると思うけど。解決方法
マイグレーションファイルに参照先のテーブルを指定しましょう。
上記で挙げたマイグレーションファイルを修正します。db/migrate/20190727232828_create_followers.rbclass CreateFollowers < ActiveRecord::Migration[5.2] def change create_table :followers do |t| t.references :user, foreign_key: true # { to_table: :users }を追加 t.references :follower, foreign_key: { to_table: :users } t.timestamps end end end{ to_table: :users }で参照するテーブルの指定ができます。
これでデータベースを更新してみましょう。# ターミナル rails db:migrateこれで外部キー制約の設定が完了です。
まとめ
1.フォロワーテーブルを作成。
# ターミナル rails g model follower user:references follow:references2.作成したマイグレーションファイルに外部キーの設定を追加
db/migrate/20190727232828_create_followers.rbclass CreateFollowers < ActiveRecord::Migration[5.2] def change create_table :followers do |t| t.references :user, foreign_key: true # { to_table: :users }を追加 t.references :follower, foreign_key: { to_table: :users } t.timestamps end end end3.データベースを更新
# ターミナル rails db:migrate
- 投稿日:2019-07-28T07:41:15+09:00
dockerでERROR: for mysql Cannot start service mysql: driver failed programming external connectivity on endpoint test-mysqlが出た時の対処
docker-compose run web rails new . --force --database=mysql --skip-bundleを実行するとエラーが出る
dockerでrailsの環境構築をしている中でいざ、railsのアプリを作成しようと以下のコマンドを実行
docker-compose run web rails new . --force --database=mysql --skip-bundleそうすると以下のようなエラーが出る。
ERROR: for mysql Cannot start service mysql: driver failed programming external connectivity on endpoint test-mysql (b2c5bfe3339ba18ad0892ba8fc5a1f427a89b3915035bc12b0c4c1207e016f75): Error starting userland proxy: Bind for 0.0.0.0:3306 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.ようはそのポートはもう割り振ってしまっていますよって事ですね。
そのためポートを一度削除する必要があります。まずは占領しているポート番号を特定します。
ポート番号を特定したら以下のコマンドを実行
$ sudo lsof -i:3300 *ここではポート番号3300にしています。Password:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 94 _mysql 13u IPv6 0x6973239584594d63 0t0 TCP *:mysql (LISTEN)上の94という番号を今度はkillします。
sudo kill 9447そうしてもう一度
docker-compose run web rails new . --force --database=mysql --skip-bundle
を実行すれば完了です。