Ruby on RailsでAPIを利用して、簡単なアプリケーションを作成する

今回はRuby on Railsで外部のAPIを利用して、イベント検索機能を実装する方法を公開します。
基本的なAPIを経由してのJson取得方法から検索フォームから値を加工する部分までをサンプルコードを用いて解説していきます。
利用する外部API
株式会社ビープラウドが開発・運営しているITエンジニアのイベント検索サービスのAPIを利用します。
関連記事
Rubyでサイトをスクレイピングし、ローカルに画像を保存する
Ruby on RailsとGoogle Geocoding APIで住所から緯度・経度を取得する方法
アプリケーション概要
Ruby on Railsのアプリケーションから、API経由でイベント情報をgetし、イベント結果を表示します。
検索フォームでキーワードと日付を選択すれば検索を実行できるようにします。
動作は こちらから確認できます。
全体処理の概要
処理のサンプルコードは下記3つになります。
1:ライブラリのサンプルコード
2:Controllerのサンプルコード
3:フォームのサンプルコード
※若干クソコードの匂いがする部分があるので、その点はご了承いただければと思います。
ライブラリファイルのサンプルコード解説
今回はAPIでイベント情報をgetするだけなので、Modelなどは特に利用しません。その為本API用のライブラリを作成します。
ファイルパス:lib/connpass_client.rb
class ConnpassClient def search_area(form_words, start_date, end_date, retry_count = 10) raise ArgumentError, 'too many HTTP redirects' if retry_count == 0 uri = Addressable::URI.parse("https://connpass.com/api/v1/event/?keyword=#{form_words}&ym=#{start_date},#{end_date}&count=30&order=3") begin response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http| http.open_timeout = 5 http.read_timeout = 10 http.get(uri.request_uri) end case response when Net::HTTPSuccess json = JSON.parse(response.body) if json['results_returned'] == 0 nil else json end when Net::HTTPRedirection location = response['location'] Rails.logger.error(warn "redirected to #{location}") search_area(form_words, start_date, end_date, retry_count - 1) else Rails.logger.error([uri.to_s, response.value].join(" : ")) end rescue => e Rails.logger.error(e.message) raise e end end end
基本コードはこの記事を参考にしました
またRuby on Rails5の場合Libファイルの読み込みを以下に変更する必要があります。
#config/application.rb config.paths.add 'lib', eager_load: true
詳細はRails5でlib配下のクラス読み込みがNameErrorになる
search_areaメソッドの引数でフォームで入力された、検索キーワードとイベントの開始 終了日付を渡します。
retry_countはリダイレクト処理が発生した場合に何回その処理を行うかの上限となります。
class ConnpassClient def search_area(form_words, start_date, end_date, retry_count = 10) #省略 end
Net::HTTPSuccessはレスポンスコードが200した場合の処理です。
connpassのイベント結果はjsonで返却されます。 検索結果が0の場合はnilを返し、検索結果が存在すれば そのままjsonをパースした結果を返します。
case response when Net::HTTPSuccess json = JSON.parse(response.body) if json['results_returned'] == 0 nil else json end
本当は以下のようにしたかったのですが、以下の場合だと なぜかnilを返さなかったので、if elseで設定しています。
json = JSON.parse(response.body) if json['results_returned'] == 0 return json end
以下はレスポンスが300台の場合の処理です location = response['location']でリダイレクトのURLを取得し、 ロガーへリダイレクトのURLを記録し、再度メソッドを回帰的に呼び出します。呼び出す際にカウントを減らして、カウントがなくなったらエラーとなります
when Net::HTTPRedirection location = response['location'] Rails.logger.error(warn "redirected to #{location}") search_area(form_words, start_date, end_date, retry_count - 1) else Rails.logger.error([uri.to_s, response.value].join(" : "))
なおエラーの場合はロガーへ出力していますが、 ローカルでの検証の場合はputsで問題ないかと思います。
Controllerのサンプルコード解説
以下はControllerのサンプルコードです
class ConnpassClientsController < ApplicationController def index if params[:start_date] start_year = params[:start_date][:year].to_i start_month = params[:start_date][:month].to_i else start_year = Time.now.year.to_i start_month = Time.now.month.to_i end if params[:end_date] end_year = params[:end_date][:year].to_i end_month = params[:end_date][:month].to_i else end_year = Time.now.year.to_i end_month = Time.now.month.to_i end @start_date = Time.mktime(start_year,start_month) @end_date = Time.mktime(end_year,end_month) start_date = @start_date.strftime("%Y%m") end_date = @end_date.strftime("%Y%m") @form_words = params[:form_words] if params[:form_words].blank? params[:form_words] = "," else params[:form_words] = params[:form_words].gsub(/( | )+/, ",") end #ライブラリをnewしてメソッドを呼び出す @result = ConnpassClient.new.search_area(params[:form_words], start_date, end_date) end end
以下Controllerのparams部分は選択フォームでイベント開始月と終了月を選択された場合は、その値を選択されていない場合は 現在日時の年月を設定します。
def index if params[:start_date] start_year = params[:start_date][:year].to_i start_month = params[:start_date][:month].to_i else start_year = Time.now.year.to_i start_month = Time.now.month.to_i end if params[:end_date] end_year = params[:end_date][:year].to_i end_month = params[:end_date][:month].to_i else end_year = Time.now.year.to_i end_month = Time.now.month.to_i end #paramsの値をTimeクラスへ変換する @start_date = Time.mktime(start_year,start_month) @end_date = Time.mktime(end_year,end_month) #Timeクラスから年月へ変換 start_date = @start_date.strftime("%Y%m") end_date = @end_date.strftime("%Y%m") end
@form_wordsはgetした後に、テキスト入力欄で入力された内容を表示する際に利用します。
#中略 @form_words = params[:form_words] if params[:form_words].blank? #テキスト入力欄へ未入力の場合カンマを設定 params[:form_words] = "," else #入力された値の半角 全角スペースを,へ変換 params[:form_words] = params[:form_words].gsub(/( | )+/, ",") end
connpassの仕様(2019年5月時点)でキーワードでor検索をする場合、空の値でgetするとbadリクエストになるため、テキスト欄が空の場合はカンマを設定するようにしています。
この部分は変更の余地があるかもしれません。
フォームのサンプルコード解説
Modelを利用しないフォームなので、form_tagを利用しています。
以下はerbでも可能ですが、slimで書いています。
【初心者・独学者向け】Ruby on Railsのviewを劇的に変える?!Slim入門
※Ruby on Rails5の場合はformtagも、formfor もform_withに統一されています。
- start_time = @start_date || Time.now - end_time = @end_date || Time.now = form_tag connpass_clients_path, :method => 'get' do div = text_field_tag :form_words, @form_words, placeholder: '東京都 プログラミング' div = select_date(start_time, {:use_month_numbers => true, discard_day: true, prefix: :start_date, :start_year => Time.now.year - 1, :end_year => Time.now.year + 1}) div = select_date(end_time, {:use_month_numbers => true, discard_day: true, prefix: :end_date, :start_year => Time.now.year - 1, :end_year => Time.now.year + 1}) = submit_tag "Search" - if @result.present? - @result['events'].each_with_index do |event, i| - start_time_to_time = Time.parse(event['started_at']) - end_time_to_time = Time.parse(event['ended_at']) .m-t-b-30 .articleEntry-Title a.event-link href= event['event_url'] target="_blank" = event['title'] .articleContent-event-dates = event['catch'] .flex.articleContent-event-dates div = t('text.date_and_time') div = ":" div = l(start_time_to_time, format: :long) div = "〜" div = l(end_time_to_time, format: :short) .flex.articleContent-event-dates div = event['address'] - else div = "検索結果がありません"
イベント情報の戻り値はjsonの['events']内に設定されるので、 配列で回して、イベント情報を表示します。
日付情報はTimeクラスへ変換するためにパースします。
- @result['events'].each_with_index do |event, i| - start_time_to_time = Time.parse(event['started_at']) - end_time_to_time = Time.parse(event['ended_at']) #以下は日付の情報をi18へ変換しています。 div = l(start_time_to_time, format: :long)
日付情報をi18へ変換する際は以下の記事を御覧ください
Ruby on Railsでi18を使ってDate型の項目を年月日形式に変換する
以上になります。
その他関連記事
Ruby on RailsでRedisを利用してランキング機能を実装する
エンジニア転職で転職エージェントを使った方が良い人|使わなくて良い人
Ruby on Railsでredcarpetを利用し、シンタックスハイライトに対応したブログ機能を実装する
チャットボット Hubot(ヒューボット)とSlackを連携してみる
ITエンジニアに強い転職エージェント4選|現役エンジニアが解説
Ruby on Railsとtwitterの投稿機能を連携する