EKS Ingress 俺的ハマりポイント
ローカル環境でminikubeを用いてKubernetesを構成して、パブリッククラウド使いたいなぁとおもってAmazon EKSを利用しました。 ekstool便利だし、慣れ親しみのあるAWSですし。
次のようにIngressを作り、kubectl apply -f ingress.yaml
などしてアクセスしてみると上手くいきました。
apiVersion: extensions/v1beta1 kind: Ingress metadata: namespace: sample2 name: rails-ing annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internet-facing spec: rules: - host: 're----ruzu.com' http: paths: - path: / backend: serviceName: rails servicePort: 3000
しかし8b27e02b-sample2-railsing-837f-1682119185.ap-northeast-1.elb.amazonaws.com/hoge
にアクセスすると404が返ってきます。🤔ハテ…。
ルート以外のpathはすべて404となってしまうようです。
いろいろ試行錯誤した結果 pathを/*
としたらうまくいきました。
apiVersion: extensions/v1beta1 kind: Ingress metadata: namespace: sample2 name: rails-ing annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internet-facing spec: rules: - host: 're----ruzu.com' http: paths: - path: '/*' backend: serviceName: rails servicePort: 3000
メンターさんに相談してみたところ、ALBの挙動だと思うから調べてみなはれとのこと。
ほーん、、、たしかに/以外は404になっていますね。。。 なるほどね。
ActionMailerを使ってる時にERBテンプレートでエラーしたときの原因特定方法
ActionMailerにて、erbテンプレートを利用することはよくあると思いますが、開発中にエラーが起きても下記の様に原因がよくわからないことがあります。
> Mailer.sth(@order) => #<ActionMailer::Base::NullMail:0x007f93bf3c8638>
ERBテンプレートだけを検証することで、原因を探ることが出来ます。
> ERB.new(File.new('app/views/mailer/sth.text.erb').read).result ArgumentError: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true from ............................/lib/action_dispatch/http/url.rb:45:in `full_url_for'
なんか、URLの生成でしくじってるみたいですね☆
rubyでGoogle Sheets APIとGoogle Drive APIを使ってみた。
みんな大好きExcelファイルをシステムで自動生成してメールで送付してほしいという案件にあたりました。 そこで、みんな大好きGoogle様のAPIを使ってExcelファイルを生成しました。(※ なぜRubyXLという便利なgemを利用しなかったのかはこの記事の最後をご参照ください。) Google APIは以前も使いましたが、バージョンがあがっているみたいなので調べ直しました。
条件
- テンプレートファイルがあるので、そのファイルを元に値を変更したい
- VLOOKUPなどの式が入っているので、ファイルを開いた時に式が再計算されている状態にしたい
準備
Googleのアカウントを作成する
- みんな持ってると思うので省略します
Google Drive APIを有効にする
- Google Developers Console で Google Drive API を有効にするアプリケーションの登録にアクセスして、Google Drive APIを有効にしてください。
Google Sheets APIを有効にする
- Google Sheets APIが無効な状態でAPIを操作しよとすると、こんな感じのエラーがでるので、予め有効にしておくといいと思います。
Google::Apis::ClientError: forbidden: Google Sheets API has not been used in project before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/sheets.googleapis.com/overview?project=xxxxxx then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry. from .../vendor/bundle/ruby/2.2.0/gems/google-api-client-0.9.9/lib/google/apis/core/http_command.rb:211:in `check_status'
- API Managerの概要でsheetと検索すると、Google Sheets APIが出てきます。あとはウィザードに従いAPIを有効にしてください。 gyazo.com
client_secretを得る
- Quickstartに書いてありますが、APIアクセスするためにはclient_secretが必要です。
- 今回はOAuth client IDを使うので、quickstartに書いてあるとおりの手順で、client_secretを作成してください。
コード
さて、お待ちかねのコードの時間です。 テンプレートファイルをコピーして、セルの値を更新して、メールに添付するという実装を行います。 ついでですが、不要になったファイルは消します。
gemをインストールします。
- Gemfile
gem 'google-api-client' gem 'google_drive'
認証用のメソッドを作成する
- quickstartを参考にしたコードです。
- quickstartではcredentialsをファイルにstoreしていますが、Redisに変更しています。
- quickstartでは必要最低限のSCOPEのみとなっていたため、Drive APIとSheets APIの両方を使えるSCOPEに変更しています。
- client_secretは
client_secret.json
という名前で、同じディレクトリにおいてください。 - 実行したらURLが表示されるので、ブラウザで認可したあとに表示される文字列をCLIに貼り付けてください。
require 'google/apis/sheets_v4' require 'googleauth' require 'googleauth/stores/redis_token_store' OOB_URI = 'urn:ietf:wg:oauth:2.0:oob' CLIENT_SECRETS_PATH = 'client_secret.json' SCOPE = [Google::Apis::SheetsV4::AUTH_SPREADSHEETS, Google::Apis::DriveV3::AUTH_DRIVE] def authorize client_id = Google::Auth::ClientId.from_file(CLIENT_SECRETS_PATH) token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new) authorizer = Google::Auth::UserAuthorizer.new( client_id, SCOPE, token_store) user_id = 'default' credentials = authorizer.get_credentials(user_id) if credentials.nil? url = authorizer.get_authorization_url( base_url: OOB_URI) puts "Open the following URL in the browser and enter the " + "resulting code after authorization" puts url code = gets credentials = authorizer.get_and_store_credentials_from_code( user_id: user_id, code: code, base_url: OOB_URI) end credentials end
テンプレートファイルをコピーする
- ファイルをコピーするにはDrive APIを利用します。
# Initialize the API drive_service = Google::Apis::DriveV3::DriveService.new drive_service.client_options.application_name = 'nyaahara sama' drive_service.authorization = authorize # example: https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit drive_service.copy_file('1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms')
かんたんですね!!
セルの値を変更する
- セルの値を変更するにはSheets APIを利用します。
# Initialize the API sheet_service = Google::Apis::SheetsV4::SheetsService.new sheet_service.client_options.application_name = 'nyaahara sama' sheet_service.authorization = authorize value_range = Google::Apis::SheetsV4::ValueRange.new value_range.range = 'A1:D1' value_range.major_dimension = 'ROWS' value_range.values = [['にゃ','あ','は','ら']] # example: https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit sheet_service.update_spreadsheet_value( '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms', value_range.range, value_range, value_input_option: 'USER_ENTERED', )
これで、A1〜D1にそれぞれ「にゃ」「あ」「は」「ら」と入力されているはずです。 縦に行きたかったら、下記のようにしてみてください。
value_range.range = 'A1:A4' value_range.values = [['にゃ'],['あ'],['は'],['ら']]
value_range.major_dimension = 'ROWS'
を変更してもいいのかもしれません。調べられていないです。
ダウンロードしてメールに添付する
- 今回はGoogle APIの使い方の紹介なので、メールに添付する部分は割愛しています。
- ファイルのダウンロードはDrive APIのほうを使います。
# example: https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit drive_service.export_file('1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', download_dest: StringIO.new)
- 簡単ですね!!
download_dest
をFile.open('file_name', 'w')
などにしてみても、動くと思いますよ!!- ちなみに第二引数はMIME typeですが、見つけるのにちょっと手間取りました。
- ここにあります。リンク集にも出しておきますね。
ファイルを削除する
- ファイルの削除はDrive APIを使います。なんとなく予測できましたよね?
drive_service.delete_file('1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms')
- 説明は不要ですね?
まとめ
- Google Spread Sheetのファイルをコピーして、セルの値を編集したあとダウンロードして削除するまでを実装しました。
- フィアル、シート、セルなどの新規追加や、ファイル移動など他の事もたくさんできるみたいなので、また書きたいと思います。
- 神ソースを発見したことで、早く実装できました。ありがとうございます。
参考リンク
- RubyのGoogle API ClientでGoogle Driveを扱う - Spreadsheetの操作あり
- MIME type一覧(Downloading Google Documents)
- 神ソース
- ありがとうございます!!
- rubyからGoogleDriveのスプレッドシートに書き込む(自分のブログ)
なぜ、GoogleSpreadSheetを利用したのか
RubyXLを利用して作成したExcelファイルをWindowsで開くとVLOOKUPなどの式に値が反映されていなかったのですよ。。。トホホ。
/xxx.txtなどのアクセスを受けた時、MissingTemplateエラーが出力される
何が起きたのか
/xxx.txtなどのアクセスを受けた時、MissingTemplateエラーが出力される
概要
404.txtをrenderしようとするが、404.html.erbなどHTMLファイルしか用意していないことが原因である。 なるほどね。 まあ、当たり前ですよね
解決策
- Railsで対応しているフォーマットの404と500を全部作る
- MissingTemplateが発生したら404.htmlに無理やり変更する(もしくは500)
Railsで運営されてるっぽいサイトはどうやって対応しているのか?
github様
いつもお世話になっています。
https://github.com/rails/rails/issues/25593.txt
ホワイトアウト!
これ、何も対処してないね。
https://github.com/rails/rails.txt
などは404ページが表示される。
slugがrails.txt
のリソースを探しにいってNOT FOUNDということだと思う。
まあ、何も対応してないね。
Oh My Glasses様
Spreeを利用されているメガネのECサイトさん。
同じフレームワークを使っているので、こういうとき、よく参考にしています。
https://www.ohmyglasses.jp/brands.txt
しぼん。
結論
- ま、きにしなくていいんじゃねーか?
- 他にもいくつかみたけど、適切にtxtを返すようなサイトは見つからなかった。
.txt
などをpermalinkに含めて検索してNOT FOUNDを返すケースと、サーバーエラーになるケースの2つに分かれる模様。- 「1行routes.rbに書けば解決!」みたいなのが無ければやらなくて良さそう。めんどくさいし。
Rubyの正規表現を複数行に分けて名前付きキャプチャをする
目的
- 整頓されていないテキストデータをrubyで取り扱いたい
- コンテンツデータを作る人は、プログラマーではないことが多いので、スペースや改行、フォーマットなどを気にしない
解決策
- 正規表現でキャプチャする
- 名前キャプチャを出来ると便利(可読性UP)
- 長くなるので複数行で正規表現を定義したい(可読性UP)
早速
# コロンの後にスペースが有ったり無かったりしますよね # 各項目について改行があったりなかったりしますよね raw_text = " お名前:にゃあはらさん メールアドレス: akb48@nyaahara.comお電話番号:教えられないよ!" # \s? を使ってスペースがあってもなくてもマッチング # \n?を使って改行があってもなくてもマッチング # (?<name>pattern) で指定した変数名(name)にキャプチャした結果を投入します。 / お名前:\s?(?<name>.+)\n? メールアドレス:\s?(?<email>.+)\n? お電話番号:\s?(?<phone_number>.+)\n? /xi =~ raw_text # xiオプションを指定すると、改行やスペースを無視してくれます
実行結果サンプル
[1] pry(main)> raw_text = " [1] pry(main)* お名前:にゃあはらさん [1] pry(main)* メールアドレス: akb48@nyaahara.comお電話番号:教えられないよ!" => "\nお名前:にゃあはらさん\nメールアドレス: akb48@nyaahara.comお電話番号:教えられないよ!" [2] pry(main)> / [2] pry(main)* お名前:\s?(?<name>.+)\n? [2] pry(main)* メールアドレス:\s?(?<email>.+)\n? [2] pry(main)* お電話番号:\s?(?<phone_number>.+)\n? [2] pry(main)* /xi =~ raw_text => 1 [3] pry(main)> name => "にゃあはらさん" [4] pry(main)> email => "akb48@nyaahara.com" [5] pry(main)> phone_number => "教えられないよ!"
参考リンク
railsでgoogleのclient idを拾う
Google Analyticsではgoogleのclient idを一意にしてユーザの特定を行っているようです。 こんなやつです。
cookieに_gaというキーで登録されており、サーバーに送信していることについ最近きがつきました。 たとえば、ホットペッパーさんのサイトなんかのクッキーをみると、ありますね。こういうのです。
さて、cookieに登録してあるということは簡単に参照できます。
module GoogleAnalyticsSupport extend ActiveSupport::Concern def client_id cookies[:_ga] end end end
このモジュールをコントローラーでincludeすれば大丈夫ですね。★
あとは、
Analyticsの画面で、自社のアプリケーションのユーザの情報を表示できるようにしたいですね。。。 まあ、それは追々。
RankedModelをSTIで使う時にハマった
Rails 4で作るドラッグアンドドロップで表示順を変更できるサンプルアプリ(スクリーンキャスト付き)などで有名なRankedModel。 RankedModelを知ってから、順序を指定するようなモデルではRankedModelを利用しています。
本日はRankedModelをSTIを利用したとき、順番が意図した通りにならずハマったので共有します。
何が起きたのか?
RankedModelでは作成した順番に並ぶようにデータが作成されていきますが、STIを利用したときに上手く行きませんでした。 下の例では、car1、car2、truck1、truck2と並んで欲しいところです。 どうやらモデルごとに値を決めているようです。
class Vehicle < ActiveRecord::Base ranks :row_order end class Car < Vehicle end class Truck < Vehicle end Car.create!(name: :car1) Car.create!(name: :car2) Truck.create!(name: :truck1) Truck.create!(name: :truck2) Vehicle.rank(:row_order).pluck(:name) #=> ["car1", "truck1", "car2", "truck2"] ( ゚∋゚)
解決策
ranksメソッドの第二引数にオプションとしてclass_nameを渡せば解決します。
よく見たらGithubに書いてありました。
class Vehicle < ActiveRecord::Base ranks :row_order, class_name: 'Vehicle' end class Car < Vehicle end class Truck < Vehicle end Car.create!(name: :car1) Car.create!(name: :car2) Truck.create!(name: :truck1) Truck.create!(name: :truck2) Vehicle.rank(:row_order).pluck(:name) #=> ["car1", "car2", "truck1", "truck2"]
解決策に至るまでに考えたこと
- データを投入したあとにupdate_columnで値を更新する
Car.create!(name: :car1) Car.create!(name: :car2) Truck.create!(name: :truck1) Truck.create!(name: :truck2) Vehicle.rank(:row_order).each.with_index { |v, i| v.update_column(:row_order, i + 1) } # => rankした時点でcar1、truck1、car2、truck2の順番に並ぶため、無意味。この時点ではモデルごとに値を決めていることに気づいていなかった