- 投稿日:2019-07-28T23:11:48+09:00
merge
- 投稿日:2019-07-28T23:06:53+09:00
スタートアップで働いて得られた開発tips
スタートアップに入り1年以上が経ちました。日々目まぐるしく環境が変化していく中でやってしまった失敗。
どんな失敗に遭遇し、どう対応したか
を簡単にまとめてみました!ぜひ、参考になれば幸いです!
(もし、需要がありそうな項目があれば深掘りして再投稿してみます)【フロント・サーバーサイド】
ページのレスポンス速度向上
当初とにかく指摘されたのはサイトのレスポンス速度でした。
そこで、レスポンス速度向上に取り組み、
結果的にPCのトップページの評価が40点台
→MAX96点
にまで向上させることができました。
ちなみにモバイルは70点付近です(笑)
測定ツールはPageSpeed Insights(ページの読み込み時間の測定・改善策の提案をしてくれるサイト)です。行った対策は以下です。
- N+1対策
- キャッシュの導入(一旦memocacheで対応)
- 画像の最適化
- JavaScriptとCSSにasync / defer
- クエリの修正(テーブルやカラムの追加)
- ページを開いた際に大量のデータを計算するなどの処理はレスポンスを遅くします!!
【インフラ系】
ElasticBeanstalkのインスタンスタイプはElasticBeanstalkから変更する
ElasticBeanstalkで環境を作成している場合、EC2からインスタンスタイプの変更しないようにしましょう。
依存関係などを崩してしまうため、うまく行きません。(僕はこれでサーバーを半日落しました(泣))
僕はこの時、環境の再構築をすることでサーバーの復活を果たすことができました。Elastic Beanstalk > ダッシュボード > アクション > 環境の再構築
エラーページは設定しておく
こちらはサーバーを落としてしまった際、またはメンテナンスの際に
503画面
が表示されてしまうとユーザーの不信感につながりかねません。404や500はrails側で設定できますが503はサーバーが落ちてしまっているのでインフラの方で設定して置かなければなりません。CloudFrontのCustom Error Responseを利用して、S3上にあるSorryページを表示する
スロークエリの設定
クエリの重さは、目に見えているページだけでなくサーバーにも大きな負担をかけてしまいます。
その結果、バックグラウンドでも影響が出てしまうことがあります。(メールが大量に届くor届かなくなる、またはjobなど)常にチェックできるように設定しておきましょう!Amazon RDS for MySQLでスロークエリーログを出力させる手順
ヘルスが変化した際の通知
様々な要因がありますが、ヘルスが
Severe
になって気づいたら数時間サーバーが止まってしまっていた。なんてことにならないようにヘルス変化は常に通知しておきましょう。Elastic Beanstalkで環境を構築している際はElastic Beanstalk > 設定 > 通知 > 通知したい先のアドレス設定 > 適用
で設定できます!
【その他】
ドキュメント管理で効率的に時間を活用する
僕の独自の共有に時間がかかるランキングは
1位 開発フローの把握
2位 システムの環境構築
3位 ユーザーからのお問い合わせ対応特に上位2つは出入りの激しい(笑)スタートアップの開発リソースを減らしてしまう深刻な問題だと思います。
一番対応の簡単な方法としてドキュメント管理に力を入れています。
もし、こんな質問がきたらこのマニュアルを渡す
のようなパターンができていればいいドキュメント管理ができているなと思うようになりました。
(ドキュメントはGithubのwikiにまとめています)Githubのタグを使い、新加入のエンジニアのキャッチアップ迅速に
ドキュメント管理
関連でもう一つ。
途中から参加したエンジニアさんはシステムの把握
に時間がかかると思います。
システムの把握に時間をかけすぎてしまうのはもったいないのですが、かけなさすぎると思いがけないバグを生んでしまいます。これがデータ保存系・更新系だと対応が大変です。。そこで僕がよく使うのはGithubの
アサイン
とタグ付け
です。
心がけていることは①自分が担当するissue・pullrequestには必ずself assignする ②ある程度シリーズ化したorしそうなissue・pullrequestにはタグづけをするこの2つを徹底すると以下のことがおきます。
→タグ一つ検索するだけで誰がどのタスクを担当し。どんなコードを書いたかがわかる
→上記がわかるとトラブルやバグ仕様の把握をしたいときに誰とコミュニケーションをとればいいかがすぐわかる
この流れが出来上がると、間に常勤のエンジニアが入ってコミュニケーションの橋渡しをせずに済み、
コミュニケーションコストが大幅に下がります!
【イメージ】
rails本家のコードを使わせていただきました。本当はこんな開発者おりません。
おまけ
副業案件お待ちしております。得意分野はRuby on Railsです!
職務経歴書
- 投稿日: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: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: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-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:23:19+09:00
HomebrewでrbenvをmacOS Sierra 10.12にインストールする指定したバージョンのRubyをつかう
前提
Homebrewがインストールされていること
rbenvをインストールする
<コンピューター名>:~ <ユーザー名>$ brew install rbenv ==> Installing dependencies for rbenv: openssl, pkg-config and ruby-build ==> Installing rbenv dependency: openssl ==> Downloading https://homebrew.bintray.com/bottles/openssl-1.0.2s.sierra.bottl ==> Downloading from https://akamai.bintray.com/e5/e556bbb8902700cd3cb896e0635cc ######################################################################## 100.0% ==> Pouring openssl-1.0.2s.sierra.bottle.tar.gz ==> Caveats A CA file has been bootstrapped using certificates from the SystemRoots keychain. To add additional certificates (e.g. the certificates added in the System keychain), place .pem files in /usr/local/etc/openssl/certs and run /usr/local/opt/openssl/bin/c_rehash openssl is keg-only, which means it was not symlinked into /usr/local, because Apple has deprecated use of OpenSSL in favor of its own TLS and crypto libraries. If you need to have openssl first in your PATH run: echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.bash_profile For compilers to find openssl you may need to set: export LDFLAGS="-L/usr/local/opt/openssl/lib" export CPPFLAGS="-I/usr/local/opt/openssl/include" For pkg-config to find openssl you may need to set: export PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig" ==> Summary ? /usr/local/Cellar/openssl/1.0.2s: 1,795 files, 12.4MB ==> Installing rbenv dependency: pkg-config ==> Downloading https://homebrew.bintray.com/bottles/pkg-config-0.29.2.sierra.bo ==> Downloading from https://akamai.bintray.com/8e/8eb723bfc03cd468d779d54d015d4 ######################################################################## 100.0% ==> Pouring pkg-config-0.29.2.sierra.bottle.tar.gz Error: The `brew link` step did not complete successfully The formula built, but is not symlinked into /usr/local Could not symlink bin/pkg-config Target /usr/local/bin/pkg-config is a symlink belonging to pkg-config. You can unlink it: brew unlink pkg-config To force the link and overwrite all conflicting files: brew link --overwrite pkg-config To list all files that would be deleted: brew link --overwrite --dry-run pkg-config Possible conflicting files are: /usr/local/bin/pkg-config -> /usr/local/Cellar/pkg-config/0.28/bin/pkg-config /usr/local/share/aclocal/pkg.m4 -> /usr/local/Cellar/pkg-config/0.28/share/aclocal/pkg.m4 /usr/local/share/doc/pkg-config/pkg-config-guide.html /usr/local/share/doc/pkg-config/pkg-config-guide.html /usr/local/share/man/man1/pkg-config.1 -> /usr/local/Cellar/pkg-config/0.28/share/man/man1/pkg-config.1 ==> Summary ? /usr/local/Cellar/pkg-config/0.29.2: 11 files, 627.1KB ==> Installing rbenv dependency: ruby-build ==> Downloading https://github.com/rbenv/ruby-build/archive/v20190615.tar.gz ==> Downloading from https://codeload.github.com/rbenv/ruby-build/tar.gz/v201906 ######################################################################## 100.0% ==> ./install.sh ? /usr/local/Cellar/ruby-build/20190615: 448 files, 225.5KB, built in 5 seconds ==> Installing rbenv ==> Downloading https://homebrew.bintray.com/bottles/rbenv-1.1.2.sierra.bottle.t ######################################################################## 100.0% ==> Pouring rbenv-1.1.2.sierra.bottle.tar.gz ? /usr/local/Cellar/rbenv/1.1.2: 36 files, 65.1KB ==> Caveats ==> openssl A CA file has been bootstrapped using certificates from the SystemRoots keychain. To add additional certificates (e.g. the certificates added in the System keychain), place .pem files in /usr/local/etc/openssl/certs and run /usr/local/opt/openssl/bin/c_rehash openssl is keg-only, which means it was not symlinked into /usr/local, because Apple has deprecated use of OpenSSL in favor of its own TLS and crypto libraries. If you need to have openssl first in your PATH run: echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.bash_profile For compilers to find openssl you may need to set: export LDFLAGS="-L/usr/local/opt/openssl/lib" export CPPFLAGS="-I/usr/local/opt/openssl/include" For pkg-config to find openssl you may need to set: export PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig"rbenvのバージョンを確認する
<コンピューター名>:~ <ユーザー名>$ rbenv -v rbenv 1.1.2インストールできるRubyのバージョンを確認する
<コンピューター名>:~ <ユーザー名>$ rbenv install -l Available versions: (省略) 2.6.0-dev 2.6.0-preview1 2.6.0-preview2 2.6.0-preview3 2.6.0-rc1 2.6.0-rc2 2.6.0 2.6.1 2.6.2 2.6.3 (省略)バージョン2.6.3をインストールする
rbenv install 2.6.3インストールされているバージョンを確認する
<コンピューター名>:~ <ユーザー名>$ rbenv versions * system (set by /Users/<ユーザー名>/.rbenv/version) 2.6.3rbenvで使用するRubyのバージョンを2.6.3にする
<コンピューター名>:~ <ユーザー名>$ rbenv global 2.6.3rbenvで使用するRubyのバージョンを確認する
<コンピューター名>:~ <ユーザー名>$ rbenv versions system * 2.6.3 (set by /Users/<ユーザー名>/.rbenv/version)rubyコマンドからバージョンを確認する
<コンピューター名>:~ <ユーザー名>$ ruby -v ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16]MacにデフォルトでインストールされているRubyのバージョンになってしまっている
実行されているRubyの場所を確認する
<コンピューター名>:~ <ユーザー名>$ which ruby /usr/bin/rubyMacにデフォルトでインストールされているRubyの場所になってしまっている
.bash_profileを開く
<コンピューター名>:~ <ユーザー名>$ open .bash_profile以下を追記する
eval "$(rbenv init -)"以下でbash_profileを実行する
<コンピューター名>:~ <ユーザー名>$ source ./bash_profile実行されているRubyの場所を確認する
<コンピューター名>:~ <ユーザー名>$ which ruby /Users/<ユーザー名>/.rbenv/shims/rubyhomebrewでインストールしたRubyの場所が表示される
rubyコマンドからバージョンを確認する
<コンピューター名>:~ <ユーザー名>$ ruby -v ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin16]homebrewでインストールしたRubyのバージョンが表示される
疑問
結局パスの設定をする必要はないのか?
参考
https://weblabo.oscasierra.net/ruby-install-rbenv-homebrew-macos/
https://easyramble.com/rbenv-ruby-version-trouble.html
https://www.grami-sensei.com/ruby/0/1/4
https://weblabo.oscasierra.net/ruby-install-rbenv-homebrew-macos/
- 投稿日: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-28T14:37:49+09:00
【Ruby】eachとmapの違い
Rubyで再帰的な処理をしたいときによく使われるeachとmapですが、初心者の方はつまづきやすいので、これらの使い分け方について簡単にまとめます。
each
eachは繰り返し処理をしたい時に使用します。
下の例では配列arrayの各要素の数字を2倍した結果を出力しています。array = [1, 2, 3] array.each do |item| p item * 2 end 2 4 6 => [1, 2, 3]mapとの違いを理解するうえで、戻り値がもとの配列[1, 2, 3]のままである点がポイントとなりますので覚えておいてください。
map
mapは繰り返し処理をした結果を配列として保持するときに使います。
下の例では配列arrayの各要素の数字を2倍した結果を配列resultに詰めています。array = [1, 2, 3] result = array.map do |item| item * 2 end =>[2, 4, 6]eachと違ってブロックの戻り値の結果が配列として返ってきていることがわかります。
もし同じ処理をeachで実装したい場合は下のようになりますが、mapで書くよりも記述量が増えてしまいますね。array = [1, 2, 3] result = [] array.each do |item| result << item * 2 end => [1, 2, 3]まとめ
eachとmapの使い分けは、処理結果を使うか使わないかによって変わってきます。
処理結果を使いたい場合はeachではなくmapを積極的に使っていけると良いですね!# 良い例 array.map do |item| item * 2 end # 悪い例 result = [] array.each do |item| result << item * 2 end
- eachは繰り返し処理に使う
- mapは繰り返し処理の結果を配列にしたいときに使う
- 投稿日: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-28T12:34:10+09:00
Railsにて不連続な間隔(日付など)で投稿された値をamChartsを使って折れ線グラフを作成する。
概要
TECH::EXPERTのカリキュラムでオリジナルのミニアプリを作成する機会があり、
同期で学習中の方がamChartsを使っていてかっこいいなぁ〜と思い、自分なりに調べてみました。
いくつか工夫したところがあったので共有します。
体重管理アプリのようなものを想定してます。
体重を計る日とそうでない日がマチマチにある場合のグラフを作成します。
例:
7月1日 70kg
7月2日 71kg
7月4日 73kg
7月7日 68kg
7月8日 69kg
7月9日 67kg
=>7月3日と7月6日の記録がない作成する前提
amChartsがCDNで読み込めている
参考文献amcharts 4 Demos を使ってグラフを作成(amChartsの導入方法が記載されています)
使用するグラフの種類:Line Chart with Scroll and Zoom
diaryモデルにweightカラムがある
diaries_controler.rbにindexアクションが用意されてある編集するファイル
・コントローラーファイル
・ビューファイルコントローラーファイル
diaries_controller.rbclass DiariesController < ApplicationController def index @diaries=Diary.all.order('created_at ASC') @weights=@diaries.map(&:weight) @dates=@diaries.map{|diary| diary.created_at.strftime('%Y/%m/%d') } end end今回は、weigthカラムの値ビューファイルに渡します。
配列で渡したいので上記のようにmapメソッドを使いました。
eachでは下記のように記載します。diaries_controller.rb##eachの場合 @weights=[] @diaries.each do |diary| @weigth << diary.weight end"&:"の記法は処理が1つの場合しか使えないので、@datesはデフォルトの記法です。
ビューファイル
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); //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 // Add data chart.data = generateChartData(); // Create axes var dateAxis = chart.xAxes.push(new am4charts.DateAxis()); dateAxis.renderer.minGridDistance = 50; 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.strokeWidth = 2; series.minBulletDistance = 10; series.tooltipText = "{valueY}"; series.tooltip.pointerOrientation = "vertical"; series.tooltip.background.cornerRadius = 20; series.tooltip.background.fillOpacity = 0.5; series.tooltip.label.padding(12,12,12,12) // Add scrollbar chart.scrollbarX = new am4charts.XYChartScrollbar(); chart.scrollbarX.series.push(series); // Add cursor chart.cursor = new am4charts.XYCursor(); chart.cursor.xAxis = dateAxis; chart.cursor.snapToSeries = series; //不連続な間隔(日付)で投稿された値を表示する function generateChartData() { var chartData = []; 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] chartData.push({ date: newDate, weight: weight }); } } } return chartData; } }); // end am4core.ready() </script> <div id="chartdiv"></div>基本はDemo sourceをコピペしてください。
styleがビューファイルにありますが、本記事の趣旨とズレるのでそのままビューファイルに記載してます。
また、Demo sourceの"visits"は"weight"としてます。(単数形です..Demo sourceはなぜ複数形にしてるんだろう...?)
下記コピペ部分とは違うところの説明です。1.コントローラーの変数をJavascriptで使えるようにする
index.erb<script> //JSON形式で値を渡す const weights = <%== JSON.dump(@weights) %>; const dates = <%== JSON.dump(@dates) %>; </script>JSONでコントローラーの値をわたします。
こちらはrailsのcontrollerからjavascriptに対して変数を渡すを参考にさせていただきました。2.表示する期間を算出する
index.erb<script> //表示期間を計算 var firstDate = new Date(dates[0]) //一番最初 var lastDate = new Date(dates.slice(-1)[0]) //一番最後 var termDate= (lastDate - firstDate)/ 1000 / 60 / 60 / 24 + 1 //表示する期間 </script>コントローラー側で配列にしたとき、
diaries_controller.rb@diaries=Diary.all.order('created_at ASC')としてるので、昇順(日付が古い順)になってます。なので、容易に一番最初を最後を取得できますね。
termDateは期間を計算しました。日付の場合そのまま引き算をできないので、/ 1000 / 60 / 60 / 24としてます。
+1は、たとえば 3日から5日までの期間を出すために"5-3=2"では1日たりないので+1としてます。3.不連続な間隔(日付)で投稿された値を表示する
Demo sourceだと下記のように表現されているところです。Demo.erb<script> function generateChartData() { var chartData = []; var firstDate = new Date(); firstDate.setDate(firstDate.getDate() - 1000); var visits = 1200; for (var i = 0; i < 500; i++) { // we create date objects here. In your data, you can have date strings // and then set format of your dates using chart.dataDateFormat property, // however when possible, use date objects, as this will speed up chart rendering. var newDate = new Date(firstDate); newDate.setDate(newDate.getDate() + i); visits += Math.round((Math.random()<0.5?1:-1)*Math.random()*10); chartData.push({ date: newDate, visits: visits }); } return chartData; } </script>簡易的に説明するならば、初期値1200であとは、ランダムで数値をあれやこれやとかえて、
i=1から500まで表現してます。
これはこれで学習するところがあっておもしろかったです。
本記事ではコントローラーから取得した値を下記のようにしてます。index.erb<script> //不連続な間隔(日付)で投稿された値を表示する function generateChartData() { var chartData = []; 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] chartData.push({ date: newDate, weight: weight }); } } } return chartData; } </script>[1]変数をinteger型の変数を2つ用意してます(i,j)
[2]jはweights.lengthの数まで繰り返します。つまり体重のレコードの数までですね。
[3]iをjにネストしてます。こちらはtermDateの数だけ繰り返します。つまり、”2.表示する期間を算出する”で計算してあげた期間分繰り返します。
[4]表示するのは、あくまで、体重のレコードが存在する日付のみなので、jの日付(体重記録がある日付)とiの日付(newDate)の差が0のときのみ、日付と体重をハッシュの形にし、chartDataに入れてあげます。完成!!
gifでは"Jul 11"と"Jul 12"に記録がありません。
参考文献
amcharts 4 Demos を使ってグラフを作成
railsのcontrollerからjavascriptに対して変数を渡す最後に
この記事を書いた目的
・自分なりに工夫した点をアウトプットして、理解を深める。
・あわよくば有識者にフィードバックをもらいたい。
・私と同じ初学者からも奇譚のない意見をもらいたい。(自分だったらどうこうする的な)筆者について
TECH::EXPERTにて4月27日より52期夜間・休日コースでruby/railsを学習している未経験エンジニアです。
ご不備等ありましたら、ご指摘ください。ちなみに本記事が初投稿になります。
言わずもがなかもしれませんが、趣味はボディメイク・筋トレでございます。
余談ですが、120kg⇨66kgまで減量して大会出場した経験があり
ダイエットについての質問はなんでも答えられるかと思いますひとこと
最後までご覧いただきまして、ありがとうございました。
もし気に入っていただけたら、イイね・ストック・フォローご自由に!
- 投稿日: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-28T09:44:10+09:00
Rubyの正規表現でバイナリファイルからPNG形式の画像を抽出
バイナリファイルからPNGを抜き出してみたくなった、ただそれだけ。Rubyでサクッとやる。
コードと実行例
extract-png.rbfilename = ARGV[0] prefix = File.basename(filename, ".*") PNG_REGEXP = / \x89PNG\r\n\x1A\n \x00\x00\x00\x0D IHDR .{13} .{4} .*? \x00\x00\x00\x00 IEND \xAE\x42\x60\x82 /mnx File.binread(filename).enum_for(:scan, PNG_REGEXP).with_index(1) do |data, i| File.binwrite("#{prefix}-%04d.png" % i, data) endconsole$ ruby extract-png.rb imageres.dll $ ls *.png imageres-0001.png imageres-0002.png ... imageres-0337.png imageres-0338.png説明
PNGの仕様
PNGのマジックナンバー(ファイル種別を示す先頭の固定バイト列)は
\x89PNG\r\n\x1A\n
の8バイト。その後はチャンクと呼ばれる
<データ長><チャンク名><データ本体><CRC-32>
の並びが何個も続く。
- 最初のチャンクは
IHDR
でデータは常に13バイトなので、チャンク名までの8バイトが固定値となる。マジックナンバーと合わせるとPNGの先頭16バイトが固定値。- 最後のチャンクは
IEND
でデータは無いので、データ長とCRC(巡回冗長検査)も含む12バイトが固定値となる1。これがPNGの末尾。PNGを厳密に探すには最低でも、マジックナンバーから始まってチャンクが連続することを確認しなければいけない。今回はそこまでするのが面倒なので、バイナリデータからPNGの先頭と末尾を探し出せばOKとした。
正規表現の構築
PNGが複数ある場合もあるので、PNGの先頭~末尾はなるべく短くなるよう抽出しなければならない。言い換えると、PNGの途中に先頭や末尾と同じ文字列が登場してはいけない。しっかり対策するには否定先読みや非包含オペレーターのような機能が必要だが、先頭や末尾の条件を長くしておけば誤検知はほぼ防げる2。そのため今回は最短マッチ
.*?
だけで済ませた。正規表現にはいくつかオプションを指定している。
- m:
.
を改行コードにもマッチさせる。今回はテキストでなくバイナリなので、改行コードを特別扱いさせてはいけない。- n: 正規表現の文字コードをバイナリ(ASCII-8BIT)に指定する。
- x: 正規表現中の空白を無視する。単に可読性を高めるためで、利用は必須ではない。
ファイル入出力と文字列スキャン
本当はファイルが巨大な場合を考慮して少しずつ入力+スキャンできればよかった(StringScannerのIO版みたいな感じ?)が、方法がわからなかったので
IO.binread
で丸ごと読み込むことにした。※IOクラスに慣れなくてFileクラスを使った。正規表現による抽出は
String#scan
でいいものの、何となく以下のことを考慮してObject#enum_for
を組み合わせた。
scan(PNG_REGEXP) { ... }
だと、連番を振る変数を別に用意しなければいけない。scan(PNG_REGEXP).each.with_index(1) { ... }
だと、抽出した全PNGデータが一旦配列で保持されてしまいメモリを消費する。参考
- Portable Network Graphics (PNG) Specification (Second Edition)
- 5 Datastream structure
- 11 Chunk specifications
- Ruby リファレンスマニュアル > 正規表現
- ruby - StringScanner scanning IO instead of a string - Stack Overflow
- 投稿日:2019-07-28T05:47:38+09:00
Ruby*Seleniumでマウス操作actionにpauseさせる
Seleniumでマウス操作したいけど、マウスの動きが速すぎるのか、期待通りに画面操作ができず。。。
なので、とりあえずマウス操作にpauseを加えようと思ったところ若干はまったのでメモです。動かないコード
下記のドキュメントを参考に。
https://www.rubydoc.info/gems/selenium-webdriver/Selenium%2FWebDriver%2FW3CActionBuilder:pauseキーボード操作時はkey_inputをpauseに渡せばいいよって書いてあったので、
マウス操作ならpointer_inputでも渡せばいいかと思い下記を実行。sample.rbaction_builder = driver.action pointer = action_builder.pointer_input elm = driver.find_element(:id, 'element_id') driver.action.click_and_hold(elm) \ .move_by(50,2).pause(pointer, 0.5) \ .move_by(50,2).pause(pointer, 0.5) \ .move_by(50,2).pause(pointer, 0.5) \ .performpointer_input ないよっていわれる。そしてkey_inputもないらしい。ドキュメントに嘘つきやん。
これで動いた
sample.rbaction_builder = driver.action pointer = action_builder.pointer_inputs[0] elm = driver.find_element(:id, 'element_id') driver.action.click_and_hold(elm) \ .move_by(50,2).pause(pointer, 0.5) \ .move_by(50,2).pause(pointer, 0.5) \ .move_by(50,2).pause(pointer, 0.5) \ .performなんでArrayで実装されてるのか謎。とりあえず[0]指定してみたけど期待通りに動いたからまあいっか。
関係ないけど
最初nodejsで実装しようとしてたんですが、そもそもActionsがないと怒られる…。
{ UnknownCommandError: Unrecognized command: actions at buildRequest (C:\nodejs_scripts\node_modules\selenium-webdriver\lib\http.js:375:9) at Executor.execute (C:\nodejs_scripts\node_modules\selenium-webdriver\lib\http.js:455:19) at Driver.execute (C:\nodejs_scripts\node_modules\selenium-webdriver\lib\webdriver.js:696:38) at process._tickCallback (internal/process/next_tick.js:68:7) name: 'UnknownCommandError', remoteStacktrace: '' }http.jsにはActions定義されてるっぽいし謎すぎるから諦めてrubyで実装しました。これの原因わかる方いたら教えてください。。。
そもそもselenium使うならpython使えってことなのかな・・・・
- 投稿日:2019-07-28T01:49:59+09:00
Rubyのシンタックス勉強用(正規表現 編)(更新中)
Rubyのシンタックスを息を吸うように書くために、少しでも理解が怪しいシンタックスを繰り返したくために書きます。
今回は正規表現です。これこそ、繰り返し書いて、息を吸うようにかけるようになりたい。
また、本記事で扱う正規表現は、初心者向けなため100%完璧に正しい表現でなく、そこそこの精度の表現で妥協しています。そこは、ご承知おきください。そこそこでもないぞ、と言う場合は、ご指摘ください。
正規表現は、まずパターンを見つけて言語化することが大事で、それができればあとは、そのプログラムを記述するだけです。
問題の確認は、以下のサービスを使っています。
Rubular: Rubyで動作する正規表現を試せるオンラインエディタ
ここで学ぶ正規表現のメタ文字
メタ文字 意味 例 \d 1個の半角数字 0123456789 \d\d\d\d 4個の半角数字 1111 {n,m} 直前の文字やパターンがn回以上、m回以下連続する - \d{3,5} 3個~5個連続する半角数字 123 や 12345 [AB] AかBのいずれか1文字 - - []
の中で使うと文字の範囲を表す- [a-z] aかbかcか...かzのいずれか1文字 - [-az],[az-] aかzかハイフンのいずれか1文字 - [0-9] 0か1か2か3か...か9のいずれか1文字 - . 改行以外の任意の1文字 あ ? 直前の文字やパターンが1回、もしくは0回現れる - .? 改行以外の任意の文字が1回、もしくは0回現れる - * 直前の文字やパターンが0回以上連続する - .* 直前の文字の0回以上の繰り返し - + 直前の文字が1回以上の繰り返し - \ メタ文字のエスケープ - \w 半角英数字とアンダースコア1文字 - 問題1(電話番号)
日本の固定電話,携帯電話に基本マッチする正規表現を書いてください。
電話:03-1234-5678 電話:06-9999-9999 電話:090-1234-5678 電話:0799-12-3450 電話:04982-2-2002 郵便番号:150-0012パターン1
を見ると、
半角数字が2個~5個 + ハイフン(
-
) + 半角数字が1個~4個 + ハイフン(-
) + 半角数字が4個で、基本マッチすることがわかりました。
正解1(電話番号)
\d{2,5}-\d{1,4}-\d{4}問題2(電話番号)
番号自体は、問題1と同じですが、ハイフンでなく
(
や)
の場合もありますよね。それにマッチする正規表現を書いてください。電話:03-1234-5678 電話:06-9999-9999 電話:090-1234-5678 電話:0799-12-3450 電話:04982-2-2002 電話:03-1234-5678 電話:06(9999)9999 電話:090-1234-5678 電話:0799(12)3450 電話:04982-2-2002 郵便番号:150-0012パターン2
半角数字が2個~5個 + ハイフン(
-
) か(
+ 半角数字が1個~4個 + ハイフン(-
)か)
+ 半角数字が4個で、基本マッチすることがわかります。
正解2(電話番号)
\d{2,5}[-(]\d{1,4}[-)]\d{4}問題3(表記ゆれを許容して社名を抽出する)
表記ゆれの多いワード「引越し」をサービス名にした引越し侍には、以下のような表記ゆれがある可能性があります。
引っ越し侍 引越侍 引越し侍 引っ越し 侍 引越侍 引越し 侍 引越し・侍パターン3
引っ越
と引越
は、ちいさい「つ」(っ
)があっても、無くても許容できるようにするために.?
を使用する越
と侍
の間は何があってもいいように*?
を使用するで、基本マッチすることがわかります。
メタ文字 意味 例 .? 任意の1文字か0文字 - .* 直前の文字の0回以上の繰り返し - 正解3(表記ゆれを許容して社名を抽出する)
引.?越.*侍ただこれだと、例えば「引っ越さない侍」とかでも許容してしまうので、どこまで厳密に抽出するかはその時の状況次第になります。
問題4(HTMLから文字列を抽出)
よく見る都道府県のHTML。ここから、valueの中身と、タグの中身のテキスト(
pref_xxx
,北海道
)がある行ごと抽出する正規表現を書いてください。<select name="pref_name"> <option value="pref_hokkaido">北海道</option> <option value="pref_aomori">青森県</option> <option value="pref_iwate">岩手県</option> </select>パターン4
pref_aomori
やpref_hokkaido
からパターンを導き出すと、value= + " + aからzのアルファベットかアンスコが1文字以上 + "
- アルファベットかアンスコが1文字以上 =
[a-z_]
- 直前のが1文字以上 =
+
つまり
[a-z_]+
- 任意の1文字以上 =
[a-z_]
- 直前のが1文字以上 =
+
タグの中身のテキストは、何かしらテキストが1文字以上あるので
.+
で、基本マッチすることがわかります。
正解4(HTMLから文字列を抽出)
行全体をマッチさせるとしたら
<option value="[a-z_]+">.+<\/option>
option
の閉じタグにあるバックスラッシュは、/
のエスケープを目的にしています。
Rubyは/
を正規表現オブジェクトとして認識してしまうので。問題5(HTMLをCSVに変換 - キャプチャ)
問題4にあるvalueの中身と、タグの中身のテキスト(
pref_xxx
,北海道
)をキャプチャする正規表現を書いてください。Rubyにおけるキャプチャとは何ができるやつなのか
- かっこ
()
内の文字列を参照出来るようにすることができる$1
,$2
...に保存し、文字列を変数として参照できる(置換にも使える)<select name="pref_name"> <option value="pref_hokkaido">北海道</option> <option value="pref_aomori">青森県</option> <option value="pref_iwate">岩手県</option> </select>パターン5
基本はパターン4と同じです。
キャプチャに関してはキャプチャしたい文字列を
()
で閉じ込めます。正解5(HTMLをCSVに変換 - キャプチャ)
<option value="([a-z_]+)">(.+)<\/option>キャプチャされてることがわかります。
Rubularは置換できないので、代わりにエディタのAtomにやらせましょう(Atomじゃなくてもできると思います)
- Atomを正規表現モード(
.*
ボタン押す)にして- 検索窓に
<option value="([a-z_]+)">(.+)<\/option>
入りつけて- 置換後の形式(
$1,$2
)を下の検索窓に借りつけてreplace All
ボタンを押す
$1
と$2
はそれぞれキャプチャされた1番目の文字列と2番目の文字列を表しています問題6(HTMLをCSVに変換 - キャプチャ その2)
基本はパターン5と同じですが。
value
に値がなくて、デフォでselected
がついてる場合もよくありますよね?その場合でもキャプチャできる正規表現を書いてください。<select name="pref_name"> <option value="" selected>都道府県</option> <option value="pref_hokkaido">北海道</option> <option value="pref_aomori">青森県</option> <option value="pref_iwate">岩手県</option> </select>パターン6
value= + " + aからzのアルファベットかアンスコが1文字以上または、何も無い + "
- アルファベットかアンスコが1文字以上 =
[a-z_]
- 直前のが0回以上 =
*
つまり
[a-z_]*
selected
に関しては、ある場合と、無い場合を考慮し、かつキャプチャされたく無いので?:
をつける。つまり
(:? selected)?
最後の
?
は、selected
が無い場合も考慮して書いています。タグの中身のテキストは、何かしらテキストが1文字以上あるので
.+
で、基本マッチすることがわかります。
正解6(HTMLをCSVに変換 - キャプチャ その2)
<option value="([a-z_]*)"(?: selected)?>(.+)<\/option>これで、キャプチャされてることもわかるかと思います。
また、エディタのAtomで置換できることもわかります。正解6に関してはリファクタも可能で、
a-z_
この部分ですが、\w
で代替え可能です。なぜなら、\w
は、半角英数字とアンダースコア1文字を表すからです。<option value="([\w]*)"(?: selected)?>(.+)<\/option>参考