20211010のRubyに関する記事は16件です。

メソッドによるコード省略!

コントローラーに同じ記述があった際、まとめる為の記述を解説します! 下記の例を参考にして、before_actionを使用して、メソッドとしてまとめます! ①.before_actionメソッドを使用して、同じコードをまとめる! 例として、下記の記述では, @eat = Eat.find(params[:id])が、繰り返し使用されています! class eatsController < ApplicationController def index @eats = Eat.all end def edit @eat = Eat.find(params[:id]) end def show @eat = Eat.find(params[:id]) end private def eat_params params.require(:eat).permit(:name, :image, :text) end end この記述をまとめるために、before_actionを使用して、メソッドとしてまとめます! before_actionを使用する際の書き方は、以下の通りです! class コントローラ名 < ApplicationController before_action :処理させたいメソッド名 before_actionを使用すると、コントローラで定義されたアクションが実行される前に、共通の処理を行うことができます! 更に、resourcesと同様にonlyやexceptなどのオプションを使用することによって、どのアクションの実行前に、処理を実行させるかなど制限が可能です! ②.onlyオプションとexceptオプション! onlyは、そのアクションだけを適用させると言う意味です! exceptは、そのアクションだけを取り除くと言う意味です! 使う際は、条件にあった方を使用します! 今回はeditとshowだけを取り除かないで処理させたいので、onlyを使用します! 下記のように記述します! class eatsController < ApplicationController before_action :set_eat, only: [:edit, :show] def index @eats = Eat.all end def edit end def show end private def eat_params params.require(:eat).permit(:name, :image, :text) end def set_eat @eat = Eat.find(params[:id]) end end before_action :set_eat, only: [:edit, :show]と記述することで、 editアクションとshowアクションが実行される前に、set_eatに定義されている処理が実行されるようになります! つまり、editアクションとshowアクションが実行される前に、@eat = Eat.find(params[:id])が実行されるということです! このように、before_actionを用いることで、重複した記述を1つのメソッドにまとめることができます! ③.まとめ ちなみに、set_eatの命名の部分はなんでもOKです! 基本的に他の人が見てわかるような物であれば、全然ありです! 例として、double_eatやtwo_eatなどでも大丈夫です! 個人的に最初はこの部分の名前は、なぜこうなっているのだろう? と言うことが多々ありましたが、なんでもいいと言うのが1番困るんですよね汗 決まりとかある方がわかりやすいと思いますので^^; これは完全に慣れだと思いますが、こう言う箇所も覚えて行こうと思います! 何か説明で間違っていたらご指導お願い致します(_ _)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails6】cocoonによる動的フォーム作成時に注意すべき点。「"accepts_nested_attributes_for"」、「"can't be blank"」

cocoonを用いて、動的に変化するフォームを作成した際にハマったことを記します。 cocoonの導入は以下の記事を参考にしました。 ・【Rails】cocoonを用いて親子孫関係のテーブルに複数のデータを同時保存する方法 - Qiita ・【Rails6】cocoonを使った動的フォーム入力画面の作り方 - Qiita 問題概要  以下のような3つのモデルを作成し、関連づけたと仮定します。 関係 モデル名 親 Parent 子 Child 孫 Grandchild 上記記事を参考にしながらフォームを作成し、できたフォームよりデータを送信したら、以下のようなバリデーションに引っかかりました。 Child Grandchild child can't be blank Child Parent can't be blank 原因 各モデルのvalidationの記述に問題がありました。 parent.rb has_many :children, dependent: :destroy accepts_nested_attributes_for :children child.rb belongs_to :parent has_many :grandchildren, dependent: :destroy accepts_nested_attributes_for :grandchildren validates :parent_id, presence: true grandchild.rb belongs_to :child validates :child_id, presence: true accepts_nested_attributes_forによって、親作成時にその子供のデータも同時に作成できるようになります。 このとき、childのparent_idやgrandchildのchild_idは各データの保存と同時に、そのデータのidが格納されます。 従って、データを保存し終わるまでは各フォームから、 _children_fields.html.erb <%= hidden_field_tag :parent_id, @parent.id %> _grandchildren_fields.html.erb <%= hidden_field_tag :child_id, @child.id %> のようにインスタンス変数から直接値を代入するよう試みても、各データは保存される前でありidを持たないため、バリデーションのpresenceに引っかかってしまいます。 解決策 方法は非常にシンプルで、validates :child_id, presence: trueとvalidates :parent_id, presence: trueを削除します。 おわりに accepts_nested_attributes_forのような1行で大きな効果を有するコードは、その動作を理解できていないと、予想外のエラーの原因になります。便利なものほどその本質の理解を心がけようと思いました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【個人用】Rails Tutorial -1

はじめに 本投稿は、投稿者本人の知識定着を目的として学んだことをアウトプットしているものです Rails インストールからHerokuへのデプロイまで 開発環境→AWS Cloud9 1.Railsのインストール手順 ①インストール時間を短縮するため、Rubyドキュメントの設定を追加 $ echo "gem: --no-document" >> ~/.gemrc ②バージョンを指定してRailsをインストール $ gem install rails -v 6.0.3 ③インストール及びバージョンの確認 $ rails -v Rails 6.0.3 ④JavaScriptソフトウェアの依存関係を管理するYarnをインストール 今回はCloudIDEなので下記コードを入力し実行でOK $ source <(curl -sL https://cdn.learnenough.com/yarn_install) 2.アプリケーションの作成〜実行 ①下記のようにrailsのバージョンを合わせてアプリを作成 $ rails _6.0.3_ new hello_app ②アプリに必要なgemのインストール Gemfileにコードを書き込むが中身は別途学ぶ Gemのバージョンを制限する方法 ex:) gem 'rails', '~> 6.0.3' ~>:マイナーアップデート済みのgemをインストール 6.0.4はインストールするけど、6.1.0はインストールしない ex:) gem 'rails', '>= 6.0.3'  >=常に最新版がインストールされる Gemfileへの記述を終えたら下記実行 $ bundle install ③ローカルWebサーバーへの接続を許可 Railsには開発マシンでのみブラウズできるローカルWebサーバーを起動するためのコマンドラインプログラム(スクリプト)が付属しているので、rails serverというコマンドを実行するだけでRailsアプリケーションを簡単に起動できる が、システムによっては(クラウドIDEであっても)、ローカルWebサーバーへの接続を許可する必要が生じることがあるので下記を記述 config/environments/development.rb Rails.application.configure do . . . # Cloud9 への接続を許可する config.hosts.clear end ④実行 下記を実行し、Railsページが表示されればクリア $ rails server Gitの管理 ※クラウドIDEではGitインストール済み ①systemセットアップ(コンピュータ1台につき1回だけ行う) $ git config --global user.name "自分の名前" $ git config --global user.email your.email@example.com クラウドIDEでデフォルトのエディタを設定する $ sudo ln -sf `which nano` /usr/bin ②初回リポジトリセットアップ 1. $ cd ~/environment/hello_app # Just in case you weren't already there $ git init Reinitialized existing Git repository in /home/ubuntu/environment/hello_app/.git/ Rails 6以降ではrails newコマンドを実行すると自動的にGitリポジトリも生成されるため、技術的にはgit initを必ずしも実行する必要はないと言えるが他の一般的なGitリポジトリはそうではないので、常にgit initを実行する癖をつけておく 2. 次は下記を実行して、プロジェクトの全ファイルをリポジトリに追加 $ git add -A このコマンドを実行すると、現在のディレクトリにあるファイルがすべてステージング(Staging)という一種の待機用リポジトリに置かれ、コミット(反映)を待つ。安全のため、いきなりコミットしないようになっている。ステージングの状態を知るには git status コマンドを使う。 3. ステージングエリアで控えている変更を本格的にリポジトリにコメント付き(-m)で反映(コミット)する $ git commit -m "Initialize repository" <重要> Gitにおけるコミット操作は、あくまでローカルマシン上にしか記録されないことに注意 ③Gitのメリット 重要なapp/controllers/ディレクトリを削除してしまった場合 $ ls app/controllers/ application_controller.rb concerns/ $ rm -rf app/controllers/ $ ls app/controllers/ ls: app/controllers/: No such file or directory ここでは、Unixコマンドのlsでapp/controllers/ディレクトリの中身を表示した後、rmコマンドをうっかり実行してしまい、このディレクトリを削除してしまった。 rfフラグは、「recursive」(サブディレクトリやその中のファイルもすべて削除する)と「force」(削除して良いかどうかをユーザーに確認しない)を指定するオプション 現在の状態を確認。 $ git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: app/controllers/application_controller.rb deleted: app/controllers/concerns/.keep no changes added to commit (use "git add" and/or "git commit -a") ファイルがいくつか削除されたが、この変更が行われたのは現在の「作業ツリー」内のみのため、まだコミット(保存)されない。つまり、以前のコミットをcheckoutコマンド(と、現在までの変更を強制的に上書きして元に戻すための-fフラグ)でチェックアウトすれば、簡単に削除前の状態に戻すことができる。 $ git checkout -f $ git status On branch master nothing to commit, working tree clean $ ls app/controllers/ application_controller.rb concerns/ ④Git Hub 1.GitHubをリモートoriginに追加してそのリポジトリにpushする $ git remote add origin https://github.com/<あなたのGitHubアカウント名>/hello_app.git $ git push -u origin master 最初のコマンドは、GitHubをリポジトリのoriginとしてGitの設定ファイルに追加するためのもの。次のコマンドでは、ローカルのリポジトリをリモートのoriginにプッシュ(push)。すると、hello_appのリポジトリのページがGitHub上に作成され、ファイルの参照、全コミット履歴などさまざまな機能を利用できる 2.Branch ブランチはリポジトリのコピーで、ブランチ上では元のファイルを触らずに新しいコードを書くなど、自由に変更や実験を試すことができる。親リポジトリはmaster(main)ブランチと呼ばれ、トピックブランチ(短期間だけ使う一時的なブランチ)はcheckoutと-bフラグを使って作成。  3.Edit ex:)トピックブランチを作ったら、READMEを編集してカスタムコンテンツを追加 4.Commit 変更が終わったら、git status でブランチの状態を確認 次に下記を実行 $ git commit -a -m "Improve the README file" <注意> -aフラグは慎重に扱う。最後のコミット後に新しいファイルを追加した場合は、まずgit addを実行してバージョン管理下に置く 5.Merge ファイルの変更が終わったので、masterブランチにこの変更をマージ(merge) $ git checkout master Switched to branch 'master' $ git merge modify-README Updating b981e57..015008c Fast-forward README.md | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) 6.Push READMEファイルの更新が終わったので、GitHubに変更をプッシュして結果を見確認。既に一度プッシュを行ったので、大抵のシステムではgit pushを実行するときにorigin masterを省略できる。 $ git push Herokuへデプロイする Herokuとは Railsを含むRuby Webアプリ用のホスティングプラットフォーム (デプロイ方法は割愛します) 終わりに アプリケーションの作成、管理、デプロイまで学んだ。 次回以降、技術面について学習し力をつけたい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SNS認証におけるNot found. Authentication passthru.エラーについて

概要  SNS認証(Omniauth使用)時に(今回はGoogle認証を使用した場合となります)おいて、Google認証ページに遷移しようとすると、「Not found. Authentication passthru.」のエラーが出た場合の対処法について記載します。  SMS認証の導入自体は、下記の記事にお世話になりました。ありがとうございます。 ・deviseとOmniAuthをRailsアプリケーションに導入しテストする 対処法  該当部分は、app/views/devise/shared/_links.html.erbにある、認証画面への遷移用リンクとなります。(user_google_oauth2_omniauth_authorize_pathでエラーが生じます) app/views/devise/shared/_links.html.erb(該当部分のみ抜粋) <%- if devise_mapping.omniauthable? %> <%- resource_class.omniauth_providers.each do |provider| %>   #今回問題となったリンク(自動生成→自身で少し訂正) <%= link_to 'Signin with Google', user_google_oauth2_omniauth_authorize_path, method: :post %><br /> <% end %> <% end %>  まず、以下の記事の内容をお試し下さい。 ・SNS認証ログインでNot found. Authentication passthru.が表示されたときの対処方法 ・Rails5でrails で google認証ができない「Not found. Authentication passthru.」  こちらの記事の内容で治れば、それでよかったのですが、私の場合はこれを試してもエラーがなくなりませんでした。  結論から申し上げると、config/initializers直下に、「omniauth.rb」を作成していただき、以下の内容を記載するとエラーを突破することができました。 omniauth.rb Rails.application.config.middleware.use OmniAuth::Builder do OmniAuth.config.allowed_request_methods = [:post, :get] end  こちらに関しては、現在私が利用させてもらっているスクールのメンター様に教えていただいた方法になります。  正直完全には理解できておりませんが、OmniAuthでの認証時にPOSTメソッドを許可する記述だそうです。これがない状態だと、うまくPOSTメソッドが機能しない状態だったそうです。  これで私の場合は認証機能がうまく動きました。どなたかの参考となれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby] AtCoder過去問 B - Exponential

はじめに AtCoder過去問B問題をRubyで解いてみました。 よろしくお願いします。 問題はこちらから確認してください↓ B - Exponential まずは入力をうけとります。 また、1が入っている配列を作っておきます。 x = gets.to_i ary = [1] このあとwhile文を使うのですが、そのとき1×1はどれだけ繰り返しても1で無限ループへ突入するため、配列には初めから1を入れておきます。 1は初めから入っているので2~xまでのeach文を作成します。iという数字はこの後の処理の中でも固定しておきたいのでコピーとして変数jを用意してiを代入しておきます。 x = gets.to_i ary = [1] (2..x).each do |i| j = i 続いてwhile文を作成します。i × jの答えがxより大きくなったときは処理を終了させます。 i × jの答えがx以下の間はi × jを行いjに代入し、そのjを先ほど作成した配列に入れていきます。 x = gets.to_i ary = [1] (2..x).each do |i| j = i while i * j <= x j = i * j ary << j end end 最後に出来上がった配列の中で一番大きい数字を出力すれば完成です。 x = gets.to_i ary = [1] (2..x).each do |i| j = i while i * j <= x j = i * j ary << j end end puts ans.max
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6+mysql5.7+Docker+AWSで作成したポートフォリオの概要

はじめに この記事では私が作成したwebアプリのポートフォリオの解説をします。 作成したポートフォリオは下記になります。↓ 作成したポートフォリオ 自己紹介 年齢:27歳 職業:地元企業のエンジニアリング部に所属 住居:地方 趣味:映画、音楽、英語(TOEIC:770)、バレーボール 映画はSFが好きで特にスターウォーズが好きです(アイコンはマンダロリアン)。英語の勉強も兼ねて英語で鑑賞するようにしています。 大学時代は軽音部に所属しており音楽は今でもよく聴きます。 中高、社会人とバレーボールを続けており、春高やVリーグは今でもチェックしています(制作背景につながります)。 制作背景 私は中学生〜高校生、社会人とバレーボールを続けています。 社会人になってバレーボールチーム「forza-kanazawa」を立ち上げましたが、なかなか人が集まらず困難していました。そこで少しでも多くの人にチームの事を知ってもらおうとこのアプリを制作しました。 機能一覧 チームメンバーからのヒアリングにより以下の要望があり、機能として実現させました。 ログイン機能 管理者のみログイン機能を使用します。ログインすることで後述の投稿機能を利用できます。 投稿機能(actiontext,Ajax通信, 画像アップロード先 S3,modal形式) 記事は、「タイトル」「サムネ」「内容」「カテゴリ」が追加できます。 Ajaxを実装することでページ遷移なしでの投稿、編集することができます。 カレンダー機能(GoogleCalenderAPI) カレンダーはFullCalenderを導入し、GoogleCalenderAPIを使い同期させています。GoogleCalenderAPIから日本の祝日、練習日を取得します。 メール機能(ActionMailer) 問い合わせメールを管理者に送れるように、Action Mailerを導入しました。Loadingを実装することでユーザが待ち時間をわかるようにしています。 使用技術一覧 フロントエンド HTML/CSS JavaScript/jQuery Bootstarp 4.50 バックエンド Ruby (3.0.0) Ruby on Rails (6.1.3) MySQL (5.7) RSpec インフラ その他 AWS (EC2/Elastic IP/S3/RDS/VPC/IAM/ALB/ACM/Route53/Cloudfront) Nginx/puma Capistrano Git/GitHub VScode Docker/docker-compose ER図 インフラ構成図 工夫した点 UI/UX サイトに訪れるユーザがコンテンツを閲覧する時に迷わないように極力シンプルな構成を心がけました。 投稿のしやすさを意識しmodal表示で投稿できるようにしました。 GoogleCalenderAPIを使用することで日程管理をしやすくしました。 メールの送信時間がわかるようにJavascriptでloadingアニメーションを実装しました。 環境・技術 コードは「Git」で管理し、こまめに「GitHub」にプッシュしてバージョン管理を行いました。ブランチを切って作業しMasterブランチにマージするなど、チーム開発も意識しました。 実際の開発を想定し、Rspecでテストコードを記載いたしました。 実際の開発を想定し、ローカル環境での開発を「docker」と「docker-compose」の仮想環境に切り替えました。 苦労した点 FullCalender,GoogleCalenderAPIの利用 カレンダーを導入するためにFullCalender(ライブラリ)を導入しましたが、最新版ではjQueryが使用できずPure JavaScriptで実装しました。ライブラリの公式documentを読みながら進めることに非常に時間がかかりました。また、外部APIとしてGoogleCalenderAPIを使用しましたが初めてAPIを扱ったため、ここでも時間がかかりました。 dockerの利用 dockerを導入する上で、前提としてLinuxに関する基礎知識は必要不可欠です。したがって、まずLinuxへの基礎的理解を深める段階で時間がかかりました。 SQLに関する理解 RailsではActiveRecordがmodelに適用されるおかげで、簡単なクエリは直感的に書くことができますが、初学者にとってはこれがブラックボックス化してしまいます。実際に中間テーブルを用い、少し複雑なクエリを書くときに私は詰まってしまいました。SQLの基礎本を読み理解しながら進めることに時間がかかりました。 所感 最後にアプリ制作を通し感じたことを書こうと思います。 まず、基礎的理解を深めることの大切さです。私の場合は、まず書籍で理解を深めたあとに取り掛かるほうがスムーズに進めることができました。また、公式ドキュメントを読むことも大切だと思いました。どんな場合でも公式ドキュメントが一番正確な一次情報となるからです。公式ドキュメントは基本英語ですので今のうちに慣れておく必要があると思いました。 今後も継続して勉強を続けたいと思います! ご覧いただきありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Sinatra】アプリにファビコン(favicon)を設定しよう

はじめに 以前、Railsでfaviconを設定しました。→(こちら) 今回はSinatraでfaviconを設定しようと思い探したものの、エラー関連の記事が多く 時間が掛かったので備忘録として記録します。 環境 mac.os バージョン10.15.6 Ruby 2.7.2 psql (PostgreSQL) 12.6 手順 ①faviconにしたい画像を探して、保存する このときに、ファイル名をfavicon.icoにしておきます。 ②アプリ内に格納する 今回はapp/assets/images内にfaviconを格納しました。 ※格納はドラッグ&ドロップでできます。 ③コードを記述する app/views/layout.erb ※ビュー(ERB)のheadタグ内に以下の一文を書きます。 <html> <head> <!--(省略) --> <!--(場所はfaviconの格納場所に合わせて指定する) --> <link rel="shortcut icon" href="assets/img/favicon.ico"> </head> <body> <!--(省略) --> </body> </html> ④faviconが適用される サーバーを起動させると、faviconが適用されていることが確認できます。 参考 1.Sinatra でメモアプリ 最後に 記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。 読んでいただき、ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

link_toでパラメーターを送信する

has_many belongs_toで関連付けを行っているモデルで、ちゃんと情報が取れるかの確認をしていたら結構時間がかかってしまったのでメモ 関連付け belongs_toとhas_manyを使います。 基本的にhas_manyは親,belongs_toが子です。 例えばUserモデルとTweetモデルがあったとして、 Userは1つ以上のTweetがあることが想定されるので、User has many Tweet Tweetは1人のユーザーしか持たないので Tweet belongs to User みたいな感じになります。 わかりにくかったら公式を読んでください。 実装 今回使うのはPostとPostProductの2つのモデル UserとPostだけであれば新規のPostデータに外部キーである(user_id)を含めるのは簡単なのですが、 今回はPostのデータを取得することから始めないといけなかったので苦戦しました。 postが持っている情報は確認できるのですが、それをpostproductで使おうとしたら情報が取れないのでエラーになりまくりでした。 formでhidden_fieldを使うことも考えましたがそもそも取れてないので却下 いろいろ調べてたところ、link_toでパラメーターが送れることがわかった。 <%= link_to "リンク名", example_path, カラム: カラムに対する値, class: "css" %> この書き方で送れるとのこと。 僕はこんな感じで使いました。 <%= link_to "投稿に商品追加", post_post_products_path(@post) post_id: @post.id, class: "dropdown-item" %> 送るだけじゃ使えないので、レシーバーにも処理を書きます。 post_product_controller.rb def index @post = params[:post_id] end これでidを渡すことができました! ですが、これだと @postに入っているのはidだけなので意味がありません。 post_product_controller.rb def index post = params[:post_id] @post = Post.find_by(id: post) end find_byを使うことでidに対応する情報を持ってくることができます。 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】map関数で行うリファクタリング

状況 UserテーブルとPostテーブルが1対1のアソシエーションの場合。 アクティブなUserの投稿した記事のidを配列形式で取得する post_ids = User.where(status:"active").post.pluck(:id) こんな感じで1行で取得したいが、User.where(status:"active")は配列なのでpostを一意に識別できずエラーになる 冗長なコード users = User.where(status:"active") post_ids = [] users.each do |user| post_ids.push(user.post) end あまりスタイリッシュじゃない、、。 map関数でリファクタリング post_ids = User.where(status:"active").map { |u| u.post.id } ワンラインで記載できていい感じ。 コメントを元に追記 下記でも取得できる。 User.where(status: 'active').joins(:posts).pluck('posts.id') Another worksでは一緒に働ける仲間を探しています
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【図解】個人aを例に、APIの概要とRailsでの使い方を一番やさしく説明をする

記事の目的 「そもそもAPIとは?」って人がAPIの概要を理解できる Rails初学者がAPIの使い方を理解できる この記事を理解できる人 Webにおけるリクエストとレスポンスのイメージを、なんとなくでいいので理解している人 ProgateのRubyとRailsを完走できるレベルの人(APIの概要だけ見るなら不問) 目次 例に出すサービスの内容 APIとは APIが分かりにくい2つの理由 Railsでの一番簡単な使い方 リクエスト編 Railsでの一番簡単な使い方 レスポンス編 まとめ 補足(JSONとは?) 開発環境 例に出すサービスの内容 サービス概要 「いらないモノ診断」というお片付けアプリです。 写真をアップロードすると、そこに映ったモノに対してお片づけのアドバイスをするアプリです。 使用しているAPI 「いらないモノ診断」では、写真からモノを検出できる「Cloud Vision」というGoogle製アプリのAPIを使っています。 APIとは 「Application Programming Interface」の頭文字です。 Interface(インターフェース)とは直訳で「接点」であり、コンピュータ用語では「何かと何かをつなぐもの」です。 では、「何のための、何と何をつなぐ接点」なのか? 一言でいうと「アプリがアプリを使うための、アプリとアプリをつなぐ接点」ということになりますが、 アプリアプリ言い過ぎてさすがに分かりにくいと思うので図解します。 「いらないモノ診断」を使っているとき、 一見すると人間がブラウザを操作して「いらないモノ診断」を使っているだけのように見えますが、 実はその裏で「いらないモノ診断」が「Cloud Vision」を使っています。 そして「API」とは、”使われる側”のアプリに設置する「ドア」のようなものだと考えれば分かりやすいでしょう。 このドアのおかげで「いらないモノ診断」は「Cloud Vision」にアクセスし利用することができるのです。 ※以下、”使う側”のアプリを「APIユーザー」、”使われる側”のアプリを「APIプロバイダ」と呼びます。 APIが分かりにくい2つの理由 ①実体がない 先ほどは分かりやすく説明するためにAPIを「ドア」に例えましたが、厳密にいうとAPIは アプリがアプリを使うために必要な「仕組み」であり、実体のない抽象概念なのです。 (だから、「ドア」そのものに該当するコードを探しても見つかりません。) 初学者にしてみたら、APIという用語を理解するだけでも一苦労なのに、 その実体はなく、肝心の仕組みもAPIプロバイダの中にあるんだから、分かりにくくて当然です。 なので最初のうちは、上の図解でイメージを掴むだけでOKです。 ②主語がない 調べていくうちに「APIを使う」とか「APIを公開する」というようなワードを目にすると思いますが、 前者はAPIユーザー(今回でいう「いらないモノ診断」)が主語で、 後者はAPIプロバイダ(今回でいう「Cloud Vision」)が主語です。 日常会話でも主語がなくて分かりにくいことはありますが、APIはその典型といえるでしょう。 ましてや、これからAPIを理解する人にとっては尚更です。 「API」という言葉に触れるときは、主語が「ユーザー」なのか「プロバイダ」なのか、最初に考えてみると良いでしょう。 Railsでの一番簡単な使い方 リクエスト編 自分のアプリでAPIを利用するとき、通常のアクションとの一番の違いは「アプリがアプリにリクエストを送る」という点です。 ブラウザはURLの送信やリンクのクリックによってリクエストを送信しますが、 Railsアプリでリクエストを送る場合はこうです。 xxxx_controller.rb require 'net/http' def xxx api_key = "xxxxxxxxxxxxx" ・・・② api_url = URI("https://vision.googleapis.com/v1/images:annotate?key=#{vision_api_key}") ・・・③ body = { requests: [ { features: [ { maxResults: 10, type: "OBJECT_LOCALIZATION" } ], image: { content: "画像URLを記載" } } ] }.to_json ・・・④ headers = { "Content-Type" => "application/json" } ・・・⑤ response = Net::HTTP.post(api_url, body, headers) ・・・① end 以下ひとつずつ解説していきます。 ① ruby: response = Net::HTTP.post(api_url, body, headers) Net::HTTP.postメソッドによってAPIプロバイダにリクエストが送信され、そのレスポンスが変数responseに格納されています。 ちなみに今回はPOSTリクエストを送りたかったのでNet::HTTP.postというメソッドですが、GETリクエストを送りたい場合は Net::HTTP.getというメソッドになります。 (GET/POSTなどのいわゆる「HTTP動詞」はAPIプロバイダが指定するものなので、 自分が使いたいAPIプロバイダの公式リファレンスを見てください) 引数であるapi_url, body, headersについては以下で解説します。 ② ruby: api_key = "xxxxxxxxxxxxx" APIキーとは、文字通りですがAPIを使うために必要な認証キーです。 人間がアプリを使うときは、メールアドレスとパスワードを認証キーとしてログインする場面がよくあると思いますが、 アプリがアプリを使うときはこのAPIキーが認証キーとなります。 さっきの図でいうと、「ドア」であるAPIを開けるための「鍵」です。 このAPIキーはパスワードと同じで他人には絶対知られてはいけないのですが、 コントローラはGitHubなどから見れてしまうので、実は上の書き方は推奨されません。 Rails5.2以上ならconfig/credentials.yml.encを使うのがおすすめです。 credentials.yml.encはざっくりいうと「秘匿性のある情報を安全に保管できるファイル」です。(詳しくはRailsガイド参照) ここに credentials.yml.enc api_key: xxxxxxxxxxxxxxxxxxx と書けば、以下のより安全なコードに書き換えることができます。 xxxx_controller.rb api_key = Rails.application.credentials.api_key 基本的にAPIキーはAPIプロバイダに発行してもらうものなので、 使いたいAPIプロバイダの公式リファレンスで発行してもらうようにしてください。 (中にはAPIキーなしで使えるものもあるようです。) ③ ruby api_url = URI("https://vision.googleapis.com/v1/images:annotate?key=#{api_key}") ここはAPIプロバイダであるCloud Visionの公式リファレンスに従っているだけなので、 他のAPIプロバイダを使いたいときはその公式リファレンスに従ってください。 URLの文字列そのままではNet::HTTP.postメソッドの引数として適切な記法ではないためURIメソッドを使っていますが、 本題ではないので割愛します。 また認証をパスするため、?key=#{api_key}の部分でパラメータにAPIキーを渡しています。 ④ body = { ... }.to_json { }の中はurl同様、APIプロバイダの公式リファレンスに従ったまでです。 同じく公式リファレンスで「JSON形式にしろ」と言われているので、to_jsonメソッドでJSON形式に変換しています。 ⑤ headers = { "Content-Type" => "application/json" } リクエストヘッダーを決めるための記述です。 今回はJSON形式でリクエストを送信したいので"Content-Type" => "application/json"を指定しました。 (昨今のAPIのやりとりのほとんどがJSON形式なので、基本的に必要になる記述だと思います) 他に指定したい項目がある場合は { "Content-Type" => "application/json", "xxx" => "xxx", "xxx" => "xxx", ... } みたいに複数指定することもできます。 Railsでの一番簡単な使い方 レスポンス編 response = Net::HTTP.post(api_url, body, headers) この一文によって、APIプロバイダが返してくれたレスポンスは既に変数responseに格納されています。 「Cloud Vision」の場合、例えばこの写真をリクエストとして送信すると、 以下のようなJSON形式でレスポンスを返してくれます。 { "responses": [ { "localizedObjectAnnotations": [ { "mid": "/m/01bqk0", "name": "Bicycle wheel", "score": 0.89648587, "boundingPoly": { "normalizedVertices": [ (中略) ] } }, { "mid": "/m/0199g", "name": "Bicycle", "score": 0.886761, "boundingPoly": { "normalizedVertices": [ (中略) ] } }, (中略) ] } ] } 長いので一部割愛しましたが、写真に映ったモノの名前を返してくれていることが分かるでしょう。 あとはこの中の使いたい部分を取り出すことができれば、無事「APIを使えた」ことになります。 では解説していきます。 上述のレスポンスの内容はresponse.bodyで呼び出すことができますが、 映ったモノの名前など、さらに奥にあるデータを取り出すには JSON.perseメソッドでRubyオブジェクトに変換することをおすすめします。 JSON.parse(response.body) これにより、まるでハッシュや配列から値を取り出すように、欲しいデータを取り出すことができます。 例えば、最初に検出したモノの名前を取り出したければこうです。 JSON.parse(response.body)['responses'][0]["localizedObjectAnnotations"][0]['name'] # => "Bicycle wheel" 言葉にすると、 「responses配列の一番最初の要素の、localizedObjectAnnotations配列の一番最初の要素の、nameキーに対応する値」 ということになります。 筆者の場合は映ったモノの名前を全て取り出し、それを配列にしたかったのでこうです。 JSON.parse(response.body)['responses'][0]["localizedObjectAnnotations"]&.map {|i| i['name']} # => ["Bicycle wheel", "Bicycle wheel", "Bicycle", "Picture frame"] 今回は構造が複雑なので難しく感じますが、ハッシュや配列から要素を取り出す方法はProgate(ruby)でも学習したと思います。 必要に応じて復習しながら、あなたの用途に合わせて記述を変えてみるといいでしょう。 まとめ APIとは? アプリがアプリを使うために必要な「仕組み」 あくまで「仕組み」(抽象概念)であり、実体はない APIにはユーザーとプロバイダが存在する RailsにおけるAPIの使い方 リクエスト編 APIプロバイダの公式リファレンスを参考に、リクエストに必要なURL、APIキー、ボディ、ヘッダーを定義する。 定義した変数を引数に入れ、Net::HTTPメソッドでリクエストを送信する。 レスポンス編 返ってきたレスポンスをJSON.perseメソッドでRubyオブジェクトに変換する。 ハッシュや配列から要素を取り出すのと同じ要領で、自分の欲しいデータを取り出す。 補足 JSONとは Railsの学習初期ではあまりJSON形式は出てこないのでハードルが高いと感じるかもしれませんが、あくまで書き方のひとつです。 人間やブラウザがアプリを使うときは、人間にとって読みやすいHTML形式でレスポンスが返ってきますが、 アプリがアプリを使うときは、機械にとって読みやすいJSON形式でレスポンスが返されているというだけのことです。 なので、はじめは「そういう書き方があるんだ」という認識でもいいと思います。 開発環境 Ruby 3.0.0 Rails 6.1.4.1 その他 記事の分かりにくい箇所や過不足、誤りなどあればコメントいただけると幸いです。 本サービスのコード詳しく知りたい場合はGitHubをご覧ください。 (記事のコードは分かりやすさ重視のため、GitHubと若干コードが異なる部分もあります)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【図解】個人サービスを例に、APIの概要とRailsでの使い方を一番やさしく説明をする

記事の目的 「そもそもAPIとは?」って人がAPIの概要を理解できる Rails初学者がAPIの使い方を理解できる この記事を理解できる人 Webにおけるリクエストとレスポンスのイメージを、なんとなくでいいので理解している人 ProgateのRubyとRailsを完走できるレベルの人(APIの概要だけ見るなら不問) 目次 例に出すサービスの内容 APIとは APIが分かりにくい2つの理由 Railsでの一番簡単な使い方 リクエスト編 Railsでの一番簡単な使い方 レスポンス編 まとめ 補足(JSONとは?) 開発環境 例に出すサービスの内容 サービス概要 「いらないモノ診断」というお片付けアプリです。 写真をアップロードすると、そこに映ったモノに対してお片づけのアドバイスをするアプリです。 使用しているAPI 「いらないモノ診断」では、写真からモノを検出できる「Cloud Vision」というGoogle製アプリのAPIを使っています。 APIとは 「Application Programming Interface」の頭文字です。 Interface(インターフェース)とは直訳で「接点」であり、コンピュータ用語では「何かと何かをつなぐもの」です。 では、「何のための、何と何をつなぐ接点」なのか? 一言でいうと「アプリがアプリを使うための、アプリとアプリをつなぐ接点」ということになりますが、 アプリアプリ言い過ぎてさすがに分かりにくいと思うので図解します。 「いらないモノ診断」を使っているとき、 一見すると人間がブラウザを操作して「いらないモノ診断」を使っているだけのように見えますが、 実はその裏で「いらないモノ診断」が「Cloud Vision」を使っています。 そして「API」とは、”使われる側”のアプリに設置する「ドア」のようなものだと考えれば分かりやすいでしょう。 このドアのおかげで「いらないモノ診断」は「Cloud Vision」にアクセスし利用することができるのです。 ※以下、”使う側”のアプリを「APIユーザー」、”使われる側”のアプリを「APIプロバイダ」と呼びます。 APIが分かりにくい2つの理由 ①実体がない 先ほどは分かりやすく説明するためにAPIを「ドア」に例えましたが、厳密にいうとAPIは アプリがアプリを使うために必要な「仕組み」であり、実体のない抽象概念なのです。 (だから、「ドア」そのものに該当するコードを探しても見つかりません。) 初学者にしてみたら、APIという用語を理解するだけでも一苦労なのに、 その実体はなく、肝心の仕組みもAPIプロバイダの中にあるんだから、分かりにくくて当然です。 なので最初のうちは、上の図解でイメージを掴むだけでOKです。 ②主語がない 調べていくうちに「APIを使う」とか「APIを公開する」というようなワードを目にすると思いますが、 前者はAPIユーザー(今回でいう「いらないモノ診断」)が主語で、 後者はAPIプロバイダ(今回でいう「Cloud Vision」)が主語です。 日常会話でも主語がなくて分かりにくいことはありますが、APIはその典型といえるでしょう。 ましてや、これからAPIを理解する人にとっては尚更です。 「API」という言葉に触れるときは、主語が「ユーザー」なのか「プロバイダ」なのか、最初に考えてみると良いでしょう。 Railsでの一番簡単な使い方 リクエスト編 自分のアプリでAPIを利用するとき、通常のアクションとの一番の違いは「アプリがアプリにリクエストを送る」という点です。 ブラウザはURLの送信やリンクのクリックによってリクエストを送信しますが、 Railsアプリでリクエストを送る場合はこうです。 xxxx_controller.rb require 'net/http' def xxx api_key = "xxxxxxxxxxxxx" ・・・② api_url = URI("https://vision.googleapis.com/v1/images:annotate?key=#{vision_api_key}") ・・・③ body = { requests: [ { features: [ { maxResults: 10, type: "OBJECT_LOCALIZATION" } ], image: { content: "画像URLを記載" } } ] }.to_json ・・・④ headers = { "Content-Type" => "application/json" } ・・・⑤ response = Net::HTTP.post(api_url, body, headers) ・・・① end 以下ひとつずつ解説していきます。 ① response = Net::HTTP.post(api_url, body, headers) Net::HTTP.postメソッドによってAPIプロバイダにリクエストが送信され、そのレスポンスが変数responseに格納されています。 ちなみに今回はPOSTリクエストを送りたかったのでNet::HTTP.postというメソッドですが、GETリクエストを送りたい場合は Net::HTTP.getというメソッドになります。 (GET/POSTなどのいわゆる「HTTP動詞」はAPIプロバイダが指定するものなので、 自分が使いたいAPIプロバイダの公式リファレンスを見てください) 引数であるapi_url, body, headersについては以下で解説します。 ② api_key = "xxxxxxxxxxxxx" APIキーとは、文字通りですがAPIを使うために必要な認証キーです。 人間がアプリを使うときは、メールアドレスとパスワードを認証キーとしてログインする場面がよくあると思いますが、 アプリがアプリを使うときはこのAPIキーが認証キーとなります。 さっきの図でいうと、「ドア」であるAPIを開けるための「鍵」です。 このAPIキーはパスワードと同じで他人には絶対知られてはいけないのですが、 コントローラはGitHubなどから見れてしまうので、実は上の書き方は推奨されません。 Rails5.2以上ならconfig/credentials.yml.encを使うのがおすすめです。 credentials.yml.encはざっくりいうと「秘匿性のある情報を安全に保管できるファイル」です。(詳しくはRailsガイド参照) ここに credentials.yml.enc api_key: xxxxxxxxxxxxxxxxxxx と書けば、以下のより安全なコードに書き換えることができます。 xxxx_controller.rb api_key = Rails.application.credentials.api_key 基本的にAPIキーはAPIプロバイダに発行してもらうものなので、 使いたいAPIプロバイダの公式リファレンスで発行してもらうようにしてください。 (中にはAPIキーなしで使えるものもあるようです。) ③ api_url = URI("https://vision.googleapis.com/v1/images:annotate?key=#{api_key}") ここはAPIプロバイダであるCloud Visionの公式リファレンスに従っているだけなので、 他のAPIプロバイダを使いたいときはその公式リファレンスに従ってください。 URLの文字列そのままではNet::HTTP.postメソッドの引数として適切な記法ではないためURIメソッドを使っていますが、 本題ではないので割愛します。 また認証をパスするため、?key=#{api_key}の部分でパラメータにAPIキーを渡しています。 ④ body = { ... }.to_json { }の中はurl同様、APIプロバイダの公式リファレンスに従ったまでです。 同じく公式リファレンスで「JSON形式にしろ」と言われているので、to_jsonメソッドでJSON形式に変換しています。 ⑤ headers = { "Content-Type" => "application/json" } リクエストヘッダーを決めるための記述です。 今回はJSON形式でリクエストを送信したいので"Content-Type" => "application/json"を指定しました。 (昨今のAPIのやりとりのほとんどがJSON形式なので、基本的に必要になる記述だと思います) 他に指定したい項目がある場合は { "Content-Type" => "application/json", "xxx" => "xxx", "xxx" => "xxx", ... } みたいに複数指定することもできます。 Railsでの一番簡単な使い方 レスポンス編 response = Net::HTTP.post(api_url, body, headers) この一文によって、APIプロバイダが返してくれたレスポンスは既に変数responseに格納されています。 「Cloud Vision」の場合、例えばこの写真をリクエストとして送信すると、 以下のようなJSON形式でレスポンスを返してくれます。 { "responses": [ { "localizedObjectAnnotations": [ { "mid": "/m/01bqk0", "name": "Bicycle wheel", "score": 0.89648587, "boundingPoly": { "normalizedVertices": [ (中略) ] } }, { "mid": "/m/0199g", "name": "Bicycle", "score": 0.886761, "boundingPoly": { "normalizedVertices": [ (中略) ] } }, (中略) ] } ] } 長いので一部割愛しましたが、写真に映ったモノの名前を返してくれていることが分かるでしょう。 あとはこの中の使いたい部分を取り出すことができれば、無事「APIを使えた」ことになります。 では解説していきます。 上述のレスポンスの内容はresponse.bodyで呼び出すことができますが、 映ったモノの名前など、さらに奥にあるデータを取り出すには JSON.perseメソッドでRubyオブジェクトに変換することをおすすめします。 JSON.parse(response.body) これにより、まるでハッシュや配列から値を取り出すように、欲しいデータを取り出すことができます。 例えば、最初に検出したモノの名前を取り出したければこうです。 JSON.parse(response.body)['responses'][0]["localizedObjectAnnotations"][0]['name'] # => "Bicycle wheel" 言葉にすると、 「responses配列の一番最初の要素の、localizedObjectAnnotations配列の一番最初の要素の、nameキーに対応する値」 ということになります。 筆者の場合は映ったモノの名前を全て取り出し、それを配列にしたかったのでこうです。 JSON.parse(response.body)['responses'][0]["localizedObjectAnnotations"]&.map {|i| i['name']} # => ["Bicycle wheel", "Bicycle wheel", "Bicycle", "Picture frame"] 今回は構造が複雑なので難しく感じますが、ハッシュや配列から要素を取り出す方法はProgate(ruby)でも学習したと思います。 必要に応じて復習しながら、あなたの用途に合わせて記述を変えてみるといいでしょう。 まとめ APIとは? アプリがアプリを使うために必要な「仕組み」 あくまで「仕組み」(抽象概念)であり、実体はない APIにはユーザーとプロバイダが存在する RailsにおけるAPIの使い方 リクエスト編 APIプロバイダの公式リファレンスを参考に、リクエストに必要なURL、APIキー、ボディ、ヘッダーを定義する。 定義した変数を引数に入れ、Net::HTTPメソッドでリクエストを送信する。 レスポンス編 返ってきたレスポンスをJSON.perseメソッドでRubyオブジェクトに変換する。 ハッシュや配列から要素を取り出すのと同じ要領で、自分の欲しいデータを取り出す。 補足 JSONとは Railsの学習初期ではあまりJSON形式は出てこないのでハードルが高いと感じるかもしれませんが、あくまで書き方のひとつです。 人間やブラウザがアプリを使うときは、人間にとって読みやすいHTML形式でレスポンスが返ってきますが、 アプリがアプリを使うときは、機械にとって読みやすいJSON形式でレスポンスが返されているというだけのことです。 なので、はじめは「そういう書き方があるんだ」という認識でもいいと思います。 開発環境 Ruby 3.0.0 Rails 6.1.4.1 その他 記事の分かりにくい箇所や過不足、誤りなどあればコメントいただけると幸いです。 本サービスのコード詳しく知りたい場合はGitHubをご覧ください。 (記事のコードは分かりやすさ重視のため、GitHubと若干コードが異なる部分もあります)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【図解】個人サービスを例に、APIの概要とRailsでの使い方を一番やさしく説明する

記事の目的 「そもそもAPIとは?」って人がAPIの概要を理解できる Rails初学者がAPIの使い方を理解できる この記事を理解できる人 Webにおけるリクエストとレスポンスのイメージを、なんとなくでいいので理解している人 ProgateのRubyとRailsを完走できるレベルの人(APIの概要だけ見るなら不問) 目次 例に出すサービスの内容 APIとは APIが分かりにくい2つの理由 Railsでの一番簡単な使い方 リクエスト編 Railsでの一番簡単な使い方 レスポンス編 まとめ 補足(JSONとは?) 開発環境 例に出すサービスの内容 サービス概要 「いらないモノ診断」というお片付けアプリです。 写真をアップロードすると、そこに映ったモノに対してお片づけのアドバイスをするアプリです。 使用しているAPI 「いらないモノ診断」では、写真からモノを検出できる「Cloud Vision」というGoogle製アプリのAPIを使っています。 APIとは 「Application Programming Interface」の頭文字です。 Interface(インターフェース)とは直訳で「接点」であり、コンピュータ用語では「何かと何かをつなぐもの」です。 では、「何のための、何と何をつなぐ接点」なのか? 一言でいうと「アプリがアプリを使うための、アプリとアプリをつなぐ接点」ということになりますが、 アプリアプリ言い過ぎてさすがに分かりにくいと思うので図解します。 「いらないモノ診断」を使っているとき、 一見すると人間がブラウザを操作して「いらないモノ診断」を使っているだけのように見えますが、 実はその裏で「いらないモノ診断」が「Cloud Vision」を使っています。 そして「API」とは、”使われる側”のアプリに設置する「ドア」のようなものだと考えれば分かりやすいでしょう。 このドアのおかげで「いらないモノ診断」は「Cloud Vision」にアクセスし利用することができるのです。 ※以下、”使う側”のアプリを「APIユーザー」、”使われる側”のアプリを「APIプロバイダ」と呼びます。 APIが分かりにくい2つの理由 ①実体がない 先ほどは分かりやすく説明するためにAPIを「ドア」に例えましたが、厳密にいうとAPIは アプリがアプリを使うために必要な「仕組み」であり、実体のない抽象概念なのです。 (だから、「ドア」そのものに該当するコードを探しても見つかりません。) 初学者にしてみたら、APIという用語を理解するだけでも一苦労なのに、 その実体はなく、肝心の仕組みもAPIプロバイダの中にあるんだから、分かりにくくて当然です。 なので最初のうちは、上の図解でイメージを掴むだけでOKです。 ②主語がない 調べていくうちに「APIを使う」とか「APIを公開する」というようなワードを目にすると思いますが、 前者はAPIユーザー(今回でいう「いらないモノ診断」)が主語で、 後者はAPIプロバイダ(今回でいう「Cloud Vision」)が主語です。 日常会話でも主語がなくて分かりにくいことはありますが、APIはその典型といえるでしょう。 ましてや、これからAPIを理解する人にとっては尚更です。 「API」という言葉に触れるときは、主語が「ユーザー」なのか「プロバイダ」なのか、最初に考えてみると良いでしょう。 Railsでの一番簡単な使い方 リクエスト編 自分のアプリでAPIを利用するとき、通常のアクションとの一番の違いは「アプリがアプリにリクエストを送る」という点です。 ブラウザはURLの送信やリンクのクリックによってリクエストを送信しますが、 Railsアプリでリクエストを送る場合はこうです。 xxxx_controller.rb require 'net/http' def xxx api_key = "xxxxxxxxxxxxx" ・・・② api_url = URI("https://vision.googleapis.com/v1/images:annotate?key=#{vision_api_key}") ・・・③ body = { requests: [ { features: [ { maxResults: 10, type: "OBJECT_LOCALIZATION" } ], image: { content: "画像URLを記載" } } ] }.to_json ・・・④ headers = { "Content-Type" => "application/json" } ・・・⑤ response = Net::HTTP.post(api_url, body, headers) ・・・① end 以下ひとつずつ解説していきます。 ① response = Net::HTTP.post(api_url, body, headers) Net::HTTP.postメソッドによってAPIプロバイダにリクエストが送信され、そのレスポンスが変数responseに格納されています。 ちなみに今回はPOSTリクエストを送りたかったのでNet::HTTP.postというメソッドですが、GETリクエストを送りたい場合は Net::HTTP.getというメソッドになります。 (GET/POSTなどのいわゆる「HTTP動詞」はAPIプロバイダが指定するものなので、 自分が使いたいAPIプロバイダの公式リファレンスを見てください) 引数であるapi_url, body, headersについては以下で解説します。 ② api_key = "xxxxxxxxxxxxx" APIキーとは、文字通りですがAPIを使うために必要な認証キーです。 人間がアプリを使うときは、メールアドレスとパスワードを認証キーとしてログインする場面がよくあると思いますが、 アプリがアプリを使うときはこのAPIキーが認証キーとなります。 さっきの図でいうと、「ドア」であるAPIを開けるための「鍵」です。 このAPIキーはパスワードと同じで他人には絶対知られてはいけないのですが、 コントローラはGitHubなどから見れてしまうので、実は上の書き方は推奨されません。 Rails5.2以上ならconfig/credentials.yml.encを使うのがおすすめです。 credentials.yml.encはざっくりいうと「秘匿性のある情報を安全に保管できるファイル」です。(詳しくはRailsガイド参照) ここに credentials.yml.enc api_key: xxxxxxxxxxxxxxxxxxx と書けば、以下のより安全なコードに書き換えることができます。 xxxx_controller.rb api_key = Rails.application.credentials.api_key 基本的にAPIキーはAPIプロバイダに発行してもらうものなので、 使いたいAPIプロバイダの公式リファレンスで発行してもらうようにしてください。 (中にはAPIキーなしで使えるものもあるようです。) ③ api_url = URI("https://vision.googleapis.com/v1/images:annotate?key=#{api_key}") ここはAPIプロバイダであるCloud Visionの公式リファレンスに従っているだけなので、 他のAPIプロバイダを使いたいときはその公式リファレンスに従ってください。 URLの文字列そのままではNet::HTTP.postメソッドの引数として適切な記法ではないためURIメソッドを使っていますが、 本題ではないので割愛します。 また認証をパスするため、?key=#{api_key}の部分でパラメータにAPIキーを渡しています。 ④ body = { ... }.to_json { }の中はurl同様、APIプロバイダの公式リファレンスに従ったまでです。 同じく公式リファレンスで「JSON形式にしろ」と言われているので、to_jsonメソッドでJSON形式に変換しています。 ⑤ headers = { "Content-Type" => "application/json" } リクエストヘッダーを決めるための記述です。 今回はJSON形式でリクエストを送信したいので"Content-Type" => "application/json"を指定しました。 (昨今のAPIのやりとりのほとんどがJSON形式なので、基本的に必要になる記述だと思います) 他に指定したい項目がある場合は { "Content-Type" => "application/json", "xxx" => "xxx", "xxx" => "xxx", ... } みたいに複数指定することもできます。 Railsでの一番簡単な使い方 レスポンス編 response = Net::HTTP.post(api_url, body, headers) この一文によって、APIプロバイダが返してくれたレスポンスは既に変数responseに格納されています。 「Cloud Vision」の場合、例えばこの写真をリクエストとして送信すると、 以下のようなJSON形式でレスポンスを返してくれます。 { "responses": [ { "localizedObjectAnnotations": [ { "mid": "/m/01bqk0", "name": "Bicycle wheel", "score": 0.89648587, "boundingPoly": { "normalizedVertices": [ (中略) ] } }, { "mid": "/m/0199g", "name": "Bicycle", "score": 0.886761, "boundingPoly": { "normalizedVertices": [ (中略) ] } }, (中略) ] } ] } 長いので一部割愛しましたが、写真に映ったモノの名前を返してくれていることが分かるでしょう。 あとはこの中の使いたい部分を取り出すことができれば、無事「APIを使えた」ことになります。 では解説していきます。 上述のレスポンスの内容はresponse.bodyで呼び出すことができますが、 映ったモノの名前など、さらに奥にあるデータを取り出すには JSON.perseメソッドでRubyオブジェクトに変換することをおすすめします。 JSON.parse(response.body) これにより、まるでハッシュや配列から値を取り出すように、欲しいデータを取り出すことができます。 例えば、最初に検出したモノの名前を取り出したければこうです。 JSON.parse(response.body)['responses'][0]["localizedObjectAnnotations"][0]['name'] # => "Bicycle wheel" 言葉にすると、 「responses配列の一番最初の要素の、localizedObjectAnnotations配列の一番最初の要素の、nameキーに対応する値」 ということになります。 筆者の場合は映ったモノの名前を全て取り出し、それを配列にしたかったのでこうです。 JSON.parse(response.body)['responses'][0]["localizedObjectAnnotations"]&.map {|i| i['name']} # => ["Bicycle wheel", "Bicycle wheel", "Bicycle", "Picture frame"] 今回は構造が複雑なので難しく感じますが、ハッシュや配列から要素を取り出す方法はProgate(ruby)でも学習したと思います。 必要に応じて復習しながら、あなたの用途に合わせて記述を変えてみるといいでしょう。 まとめ APIとは? アプリがアプリを使うために必要な「仕組み」 あくまで「仕組み」(抽象概念)であり、実体はない APIにはユーザーとプロバイダが存在する RailsにおけるAPIの使い方 リクエスト編 APIプロバイダの公式リファレンスを参考に、リクエストに必要なURL、APIキー、ボディ、ヘッダーを定義する。 定義した変数を引数に入れ、Net::HTTPメソッドでリクエストを送信する。 レスポンス編 返ってきたレスポンスをJSON.perseメソッドでRubyオブジェクトに変換する。 ハッシュや配列から要素を取り出すのと同じ要領で、自分の欲しいデータを取り出す。 補足 JSONとは Railsの学習初期ではあまりJSON形式は出てこないのでハードルが高いと感じるかもしれませんが、あくまで書き方のひとつです。 人間やブラウザがアプリを使うときは、人間にとって読みやすいHTML形式でレスポンスが返ってきますが、 アプリがアプリを使うときは、機械にとって読みやすいJSON形式でレスポンスが返されているというだけのことです。 なので、はじめは「そういう書き方があるんだ」という認識でもいいと思います。 開発環境 Ruby 3.0.0 Rails 6.1.4.1 その他 記事の分かりにくい箇所や過不足、誤りなどあればコメントいただけると幸いです。 本サービスのコード詳しく知りたい場合はGitHubをご覧ください。 (記事のコードは分かりやすさ重視のため、GitHubと若干コードが異なる部分もあります)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【図解】個人サービスを例に、Web APIの概要とRailsでの使い方を一番やさしく説明する

記事の目的 「そもそもWebAPIとは?」って人がWebAPIの概要を理解できる Rails初学者がWebAPIの使い方を理解できる この記事を理解できる人 Webにおけるリクエストとレスポンスのイメージを、なんとなくでいいので理解している人 ProgateのRubyとRailsを完走できるレベルの人(WebAPIの概要だけ見るなら不問) 目次 例に出すサービスの内容 APIとは APIが分かりにくい2つの理由 Railsでの一番簡単な使い方 リクエスト編 Railsでの一番簡単な使い方 レスポンス編 まとめ 補足(JSONとは?) 開発環境 例に出すサービスの内容 サービス概要 「いらないモノ診断」というお片付けアプリです。 写真をアップロードすると、そこに映ったモノに対してお片づけのアドバイスします。 使用しているWebAPI 「いらないモノ診断」では、写真からモノを検出できる「Cloud Vision」という Google製サービスのWebAPIを使っています。 APIとは 「Application Programming Interface」の頭文字です。 Interface(インターフェース)とは直訳で「接点」であり、コンピュータ用語では 「何かと何かをつなぐもの」です。 ソフトウェアだとイメージが湧かないかもしれませんが、 ハードウェアだと例えばケーブル類は「何かと何かをつなぐ」のでインターフェースの一種です。 では、「何のための、何と何をつなぐ接点」なのか? 一言でいうと、APIは「アプリがアプリを使うための、アプリとアプリをつなぐ接点」です。 そして、中でもWeb上のリクエスト/レスポンスを利用する「接点」を「WebAPI」といいます。 (APIは総称であり、その中にWebAPIがあるというイメージを持てればOKです。 WebAPI以外のAPIもありますが、本題から逸れるのでここでは説明しません。) ※ここからは、便宜上WebAPIを「API」と呼んで説明します 図解するとこんな感じです。 「いらないモノ診断」を使っているとき、 一見すると人間がブラウザを操作して「いらないモノ診断」を使っているだけのように見えますが、 実はその裏で「いらないモノ診断」が「Cloud Vision」を使っています。 そして「API」とは、”使われる側”のアプリに設置する「ドア」のようなものだと考えれば分かりやすいでしょう。 このドアのおかげで「いらないモノ診断」は「Cloud Vision」にアクセスし利用することができるのです。 ※以下、”使う側”のアプリを「APIユーザー」、”使われる側”のアプリを「APIプロバイダ」と呼びます。 APIが分かりにくい2つの理由 ①実体がない 先ほどは分かりやすく説明するためにAPIを「ドア」に例えましたが、厳密にいうとAPIは アプリがアプリを使うために必要な「仕組み」であり、実体のない抽象概念なのです。 (だから、「ドア」そのものに該当するコードを探しても見つかりません。) 初学者にしてみたら、APIという用語を理解するだけでも一苦労なのに、 その実体はなく、肝心の仕組みもAPIプロバイダの中にあるんだから、分かりにくくて当然です。 なので最初のうちは、上の図解でイメージを掴むだけでOKです。 ②主語がない 調べていくうちに「APIを使う」とか「APIを公開する」というようなワードを目にすると思いますが、 前者はAPIユーザー(今回でいう「いらないモノ診断」)が主語で、 後者はAPIプロバイダ(今回でいう「Cloud Vision」)が主語です。 日常会話でも主語がなくて分かりにくいことはありますが、APIはその典型といえるでしょう。 ましてや、これからAPIを理解する人にとっては尚更です。 「API」という言葉に触れるときは、主語が「ユーザー」なのか「プロバイダ」なのか、最初に考えてみると良いでしょう。 Railsでの一番簡単な使い方 リクエスト編 自分のアプリでAPIを利用するとき、通常のアクションとの一番の違いは「アプリがアプリにリクエストを送る」という点です。 ブラウザはURLの送信やリンクのクリックによってリクエストを送信しますが、 Railsアプリでリクエストを送る場合はこうです。 xxxx_controller.rb require 'net/http' def xxx api_key = "xxxxxxxxxxxxx" ・・・② api_url = URI("https://vision.googleapis.com/v1/images:annotate?key=#{vision_api_key}") ・・・③ body = { requests: [ { features: [ { maxResults: 10, type: "OBJECT_LOCALIZATION" } ], image: { content: "画像URLを記載" } } ] }.to_json ・・・④ headers = { "Content-Type" => "application/json" } ・・・⑤ response = Net::HTTP.post(api_url, body, headers) ・・・① end 以下ひとつずつ解説していきます。 ① response = Net::HTTP.post(api_url, body, headers) Net::HTTP.postメソッドによってAPIプロバイダにリクエストが送信され、そのレスポンスが変数responseに格納されています。 ちなみに今回はPOSTリクエストを送りたかったのでNet::HTTP.postというメソッドですが、GETリクエストを送りたい場合は Net::HTTP.getというメソッドになります。 (GET/POSTなどのいわゆる「HTTP動詞」はAPIプロバイダが指定するものなので、 自分が使いたいAPIプロバイダの公式リファレンスを見てください) 引数であるapi_url, body, headersについては以下で解説します。 ② api_key = "xxxxxxxxxxxxx" APIキーとは、文字通りAPIを使うために必要な認証キーです。 人間がアプリを使うときは、メールアドレスとパスワードを認証キーとしてログインする場面がよくあると思いますが、 アプリがアプリを使うときはこのAPIキーが認証キーとなります。 さっきの図でいうと、「ドア」であるAPIを開けるための「鍵」です。 このAPIキーはパスワードと同じで他人には絶対知られてはいけないのですが、 コントローラはGitHubなどから見れてしまうので、実は上の書き方は推奨されません。 Rails5.2以上ならconfig/credentials.yml.encを使うのがおすすめです。 credentials.yml.encはざっくりいうと「秘匿性のある情報を安全に保管できるファイル」です。(詳しくはRailsガイド参照) ここに credentials.yml.enc api_key: xxxxxxxxxxxxxxxxxxx と書けば、以下のより安全なコードに書き換えることができます。 xxxx_controller.rb api_key = Rails.application.credentials.api_key 基本的にAPIキーはAPIプロバイダに発行してもらうものなので、 使いたいAPIプロバイダの公式リファレンスで発行してもらうようにしてください。 (中にはAPIキーなしで使えるものもあるようです。) ③ api_url = URI("https://vision.googleapis.com/v1/images:annotate?key=#{api_key}") ここはAPIプロバイダであるCloud Visionの公式リファレンスに従っているだけなので、 他のAPIプロバイダを使いたいときはその公式リファレンスに従ってください。 URLの文字列そのままではNet::HTTP.postメソッドの引数として適切な記法ではないためURIメソッドを使っていますが、 本題ではないので割愛します。 また認証をパスするため、?key=#{api_key}の部分でパラメータにAPIキーを渡しています。 ④ body = { ... }.to_json { }の中はurl同様、APIプロバイダの公式リファレンスに従ったまでです。 同じく公式リファレンスで「JSON形式にしろ」と言われているので、to_jsonメソッドでJSON形式に変換しています。 ⑤ headers = { "Content-Type" => "application/json" } リクエストヘッダーを決めるための記述です。 今回はJSON形式でリクエストを送信したいので"Content-Type" => "application/json"を指定しました。 (昨今のAPIのやりとりのほとんどがJSON形式なので、基本的に必要になる記述だと思います) 他に指定したい項目がある場合は { "Content-Type" => "application/json", "xxx" => "xxx", "xxx" => "xxx", ... } みたいに複数指定することもできます。 Railsでの一番簡単な使い方 レスポンス編 response = Net::HTTP.post(api_url, body, headers) この一文によって、APIプロバイダが返してくれたレスポンスは既に変数responseに格納されています。 「Cloud Vision」の場合、例えばこの写真をリクエストとして送信すると、 以下のようなJSON形式でレスポンスを返してくれます。 { "responses": [ { "localizedObjectAnnotations": [ { "mid": "/m/01bqk0", "name": "Bicycle wheel", "score": 0.89648587, "boundingPoly": { "normalizedVertices": [ (中略) ] } }, { "mid": "/m/0199g", "name": "Bicycle", "score": 0.886761, "boundingPoly": { "normalizedVertices": [ (中略) ] } }, (中略) ] } ] } 長いので一部割愛しましたが、写真に映ったモノの名前を返してくれていることが分かるでしょう。 あとはこの中の使いたい部分を取り出すことができれば、無事「APIを使えた」ことになります。 では解説していきます。 上述のレスポンスの内容はresponse.bodyで呼び出すことができますが、 映ったモノの名前など、さらに奥にあるデータを取り出すには JSON.perseメソッドでRubyオブジェクトに変換することをおすすめします。 JSON.parse(response.body) これにより、まるでハッシュや配列から値を取り出すように、欲しいデータを取り出すことができます。 例えば、最初に検出したモノの名前を取り出したければこうです。 JSON.parse(response.body)['responses'][0]["localizedObjectAnnotations"][0]['name'] # => "Bicycle wheel" 言葉にすると、 「responses配列の一番最初の要素の、localizedObjectAnnotations配列の一番最初の要素の、nameキーに対応する値」 ということになります。 筆者の場合は映ったモノの名前を全て取り出し、それを配列にしたかったのでこうです。 JSON.parse(response.body)['responses'][0]["localizedObjectAnnotations"]&.map {|i| i['name']} # => ["Bicycle wheel", "Bicycle wheel", "Bicycle", "Picture frame"] 今回は構造が複雑なので難しく感じますが、ハッシュや配列から要素を取り出す方法はProgate(ruby)でも学習したと思います。 必要に応じて復習しながら、あなたの用途に合わせて記述を変えてみるといいでしょう。 まとめ APIとは? アプリがアプリを使うために必要な「仕組み」 あくまで「仕組み」(抽象概念)であり、実体はない APIにはユーザーとプロバイダが存在する RailsにおけるAPIの使い方 リクエスト編 APIプロバイダの公式リファレンスを参考に、リクエストに必要なURL、APIキー、ボディ、ヘッダーを定義する。 定義した変数を引数に入れ、Net::HTTPメソッドでリクエストを送信する。 レスポンス編 返ってきたレスポンスをJSON.perseメソッドでRubyオブジェクトに変換する。 ハッシュや配列から要素を取り出すのと同じ要領で、自分の欲しいデータを取り出す。 補足 JSONとは Railsの学習初期ではあまりJSON形式は出てこないのでハードルが高いと感じるかもしれませんが、あくまで書き方のひとつです。 人間やブラウザがアプリを使うときは、人間にとって読みやすいHTML形式でレスポンスが返ってきますが、 アプリがアプリを使うときは、機械にとって読みやすいJSON形式でレスポンスが返されているというだけのことです。 なので、はじめは「そういう書き方があるんだ」という認識でもいいと思います。 開発環境 Ruby 3.0.0 Rails 6.1.4.1 その他 記事の分かりにくい箇所や過不足、誤りなどあればコメントいただけると幸いです。 本サービスのコード詳しく知りたい場合はGitHubをご覧ください。 (記事のコードは分かりやすさ重視のため、GitHubと若干コードが異なる部分もあります)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsで出てくるparams[:id]ってなんだ?paramsについて深く理解してみる

はじめに どうも、27歳未経験からエンジニア転職を目指しているもきおです。 Ruby on Railsを学習しているとよくコントローラーにおいてparamsってやつが出てきますよね? 例としてはこんな感じ users_controller.rb def show @user = User.find(params[:id]) end でもshowの他にeditとかcreateとかでも出てきてしかも記載の仕方がちょくちょく変わっている。 自分自身もとりあえず見様見真似でnewの時はこの記載、showはこの記載みたいな感じで記載してまあエラー起きず動いたら満足って感じでコードを書いてました。 今回はparamsについて理解を深めたのでただコピペでなくちゃんと理解をした上でparamsを使用できるようこの記事に書き記しておきます。 ※createに関してのparamsの記載は後日別記事にて記載してます。 paramsってなんぞ? paramsとは送られてきた値を受け取るためのメソッドのことです。っていっても分からないので例を見てみましょう。 ユーザー一覧はこんな感じのURLになっています。URLの最後がusersとなってますね ユーザー一覧で一番上のid:1のkkkkというユーザーの詳細画面(Show)を押すと するとURLの最後に/1が追加されました。 ここでターミナルを見てみると黄色い枠にidに1が代入されている事がわかります。 このようにparamsは送られて来た値を受け取る事ができます。 users_controller.rb def show @user = User.find(params[:id]) end このparamsにおいてユーザーの:idを取得している事がわかります。 これはidに紐ずくユーザー情報を全て取って来ているので次のような事もできます。 View index.htm.erb 今までこのような記載だったのを nameをキーとしてユーザーネームも渡してあげます。 するとidの後に名前も挿入されることが分かります。少しparamsが理解できてきたのではないかなと思います。 あとがき 今回でparamsの理解を少し深める事ができました。 この記事が少しでも良いと感じていただけましたらLGTMポチっとしていただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Slackでリアルタイムにログを確認する

これはなに? アプリのバッチを動かすときに、私はSlackでログを見たくなります。 Slackで見れることでPCが見れない環境下でも状況を確認できますし、メールなど他チャネルに分散せず一箇所で確認・議論・対応できる点がお気に入りです。 バッチ監視の従来の手法 古来からサーバーに潜ってログファイルをtailして確認したし、最近だとCloudWatch Logsでtailしたりしますよね。 Slackでのバッチログについてバッチ開始時と終了時にpostするくらいがよくある形かと思いますが、Slackのメッセージ更新APIを使えばリアルタイムにバッチの状況を確認できます。 本記事はそういった使い方の共有です。 利用イメージ 後述のようにloggerを用意することで、このような形でバッチの途中経過が更新されます。 使い方 log_filepath = "log/sample.log" logger = SlackLogger.new(logger: Jets::Logger.new(log_filepath)) logger.post!("Start.") (:A .. :E).each do |alphabet| logger.post!("#{alphabet}の処理 開始") sleep(1) # 大量に出力されるものはリアルタイムにSlack通知せず、ファイルにバッファして終了時にスレッドにポスト 1000.times do |i| logger.write!("#{alphabet} - #{i}回目") end logger.post!("#{alphabet}の処理 終了") sleep(1) end # ログファイルをポスト logger.post_thread_file!(File.new(log_filepath)) # アタッチメントカラーを緑に logger.good!("Completed.") なお、かなりの数のバッチをこれで長年更新していますが、(本ロガーの件で)Slackの制限に引っかかったことはありません。 ロガークラスの実装 class SlackLogger attr_accessor :color def initialize(pretext = nil, *args) pretext ||= begin c = caller_locations(2, 1).first "#{c.path.gsub(Jets.root.to_s, '')} - #{c.label}" end @options = args.extract_options! @options[:channel] ||= :test @options[:username] ||= "バッチログ" @options[:username] += "(開発環境)" if Rails.env.development? @logs = [] @pretext = pretext @color = :default @post_to_slack = true @logger = @options.delete(:logger) || Rails.logger end def post!(text) begin full_text = "#{Time.current.strftime('%T')} - #{text}" @logger.info(text) unless @post_to_slack puts full_text return end @logs << full_text attachments = [{ pretext: @pretext, color: @color, text: @logs.reverse.join("\n"), }] # 初回はpost、2回目からはupdate if @message.nil? @message = Slack.client.chat_postMessage(@options.merge({ attachments: attachments.to_json, })) else Slack.client.chat_update(@options.merge({ channel: @message["channel"], ts: @message["ts"], attachments: attachments.to_json, })) end rescue => e @logger.error("fail. \n#{e.message}\n" + %!#{e.backtrace[0..3].join("\n")}!) end end def good!(text) @color = :good post!(text) end def danger!(text) @color = :danger post!(text) end # 頻度が多い場合はpost!せずwrite!でファイルに溜めて、処理の終了時にログファイルをpost_thread_file!する def write!(text) @logger.info(text) end # スレッドにファイルをpostする def post_thread_file!(text_file, filetype: "text", filename: "tmp") ret = Slack.client.files_upload({ channels: @message['channel'], thread_ts: @message['ts'], filename: filename.to_s, filetype: filetype.to_s, file: Faraday::UploadIO.new(text_file, 'text/plain'), }) end end バッチに余計な処理をはさみたくないというケースもあるかと思いますが、長年使っても安定していてここでトラブったことはないので快調ではあります。 (とはいえデリケートな処理の箇所ではタイムアウト設定や、一度でもタイムアウトしたらその日は更新しないなどの制御が必要です。) 誰かのお役に立てば幸いです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Jetsでサーバーレス

これはなに? 普段からRubyを使っているのですが、バッチ主体のシステムを開発するにあたり安価にサーバーレスを使いたく、Ruby on Jetsを選択して半年ほど運用した上での共有です。 Ruby on Jets https://rubyonjets.com/ Ruby on Jetsの特徴 Railsライク書いたコードでAWSのアーキテクチャを扱えるフレームワークです。 これらのRailsに慣れた人なら見覚えのあるコマンド群が使える。 jets new jets generate scaffold jets db:migrate jets server jets console jets deploy jets routes jets call jets status jets url jets delete ActiveSupportやActiveRecordなども使えるので、Railsのコードをほとんどそのまま持っていけます。 console rails consoleと同じようなコンソールが使えます。 jets console デプロイ JETS_ENV=production jets deploy これにより、JetsがCloudFormationを構築し、AWS上に展開を行ってくれるためCloudFormationでポシャるとツラいが、Railsライクに書いたコードが以下のように展開されるのでLambdaが扱いやすい。 コントローラーやジョブのコードがAWS上でLambdaにデプロイされる。 routes.rbの内容がAPI Gatewayに展開される。 Lambdaの権限設定 application.rbで以下のようにご所望の権限を記述すれば設定できます。 config.iam_policy = [ { action: ["logs:*"], effect: "Allow", resource: [ "arn:aws:logs:#{Jets.aws.region}:#{Jets.aws.account}:log-group:*", ], }, { action: ["s3:Get*", "s3:List*"], effect: "Allow", resource: "arn:aws:s3:::#{Jets.aws.s3_bucket}*", }, { action: ["rds-db:connect"], effect: "Allow", resource: "!Sub arn:aws:rds-db:#{Jets.aws.region}:#{Jets.aws.account}:xxx:*/*", }, { action: ["secretsmanager:GetSecretValue"], effect: "Allow", resource: "!Sub arn:aws:secretsmanager:#{Jets.aws.region}:#{Jets.aws.account}:secret:#{config.project_name}/#{Jets.env}/*", }, ] カスタムドメイン こんな感じでカスタムドメインも設定できます。 config.domain.hosted_zone_name = "xxxx.co.jp" if Jets.env.production? config.domain.apex = true else config.domain.name = "#{Jets.env}.xxxx.co.jp" end config.domain.cert_arn = "arn:aws:acm:xxxxxxxxxx:certificate/xxxxxxxxxxxx" その他、細かいところもドキュメントを見れば代替はセッティング可能。 https://rubyonjets.com/docs/ 面倒なのはgem周り 前提として、gemのコードはLambdaの環境用にコンパイルする必要があります。 Jetsはデフォルトでは「Serverless Gems」というサービスを使っていて、このサービスからLambda用にコンパイルされたgemコードをzipでダンロードしてLambdaに展開する作りになっています。 そして、このサービスが無料版だとダウンロード数制限(30回/日)があります。 https://www.serverlessgems.com/ 無料で使いたい場合 通常なら課金してこれを使えば楽なんですが、回避する手法も用意されています。 独自にgemをコンパイルしてLambdaのレイヤーとしてプッシュすることで、以下のように自前でコンパイルしたgemをLambdaレイヤーとして利用可能です。 Jets.application.configure do config.gems.disable = true config.lambda.layers = [ "arn:aws:lambda:xxxxx:layer:gem-layer:xx", ] end このように独自のレイヤーでgemを利用する場合は、amazon/aws-sam-cli-build-image-ruby2.7のコンテナ内でbundle installし、zipにしてs3に転送する必要があり、ざっくりですが以下のような処理で可能です。 mkdir -p tmp/gemlayer/ cp Gemfile* tmp/gemlayer/ cd tmp/gemlayer mkdir -p lib mkdir -p bin docker run --rm \ -v $PWD:/var/layer \ -w /var/layer \ -e BUNDLE_GITHUB__COM \ -e HOST_UID=`id -u` \ -e HOST_GID=`id -g` \ amazon/aws-sam-cli-build-image-ruby2.7 \ bash bundle install --path ruby rm -rf lib/ruby/2.7.0/cache mv ruby/ruby ruby/gems zip -q -r zip.zip ruby/gems/ zip -q -r zip.zip lib zip -q -r zip.zip bin export HASH=$(md5sum zip.zip | cut -f1 -d ' ') aws s3 cp zip.zip s3://gemlayer-bucket-name/$HASH cd ../../ aws cloudformation update-stack \ --stack-name xxxx \ --template-body xxxx \ --capabilities CAPABILITY_AUTO_EXPAND \ --parameters ParameterKey=Hash,ParameterValue=$HASH 困ったこと 半年以上運用して結構使いやすいんですが、たまにCloudFormationでうまくデプロイできなかったときがツラかったです。 ※ なので、ロールバックしたりCloudFormationについてのナレッジもあると安心。 特にgemレイヤーを更新するデプロイ時にロールバックする羽目になると辛くて、Lambdaのレイヤーは最新バージョンのみ保持できてバージョン番号を巻き戻せないため、アプリのロールバック時に旧レイヤーバージョンが存在しない事態になりロールバックできなかったです。 このときはアプリのプロジェクト自体をdeleteして再度createする形になりました。 RDSやパラメーターストアなど永続化するべきものはアプリのプロジェクトに含まず構築していたので再作成も楽にできました。 それ以外はいい感じで、Slackボットやジョブをたくさん捌いてもサーバーレスならではの安価な利用ができています。 その他の選択肢 最近見知ったのでまだ使えていないのですが、RubyでサーバーレスをするにあたってRuby on Jets以外にも以下の選択肢も気になっています。 https://github.com/customink/lamby 現場からは以上です!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む