読者です 読者をやめる 読者になる 読者になる

ActiveResourceでRedmine REST使ってみた

今更だけどActiveResource使ってみた.

ActiveResourceっていうのは,Railsのレールに完全に乗っかったモデルがあってREST APIが定義されていたら,別RailsアプリからでもActiveRecordみたいに触れる機能らしい.

ActiveResource腰にRedmineを触ることがあったのでメモがてらまとめ.

github.com

参考サイトは以下

qiita.com

使い方

今回はRails5でためす,Rails5で使う際には,masterのを使う必要があるみたいなのでGemfileに指定.

gem 'activeresource', github: 'rails/activeresource', branch: 'master'

参考サイト通りRedmineとつなげる.

class RedmineBase < ActiveResource::Base
  self.site = 'https://redmine.example'
  self.headers['X-Redmine-API-Key'] = 'hogee'
  self.format = :xml
end

あとは,同名のモデルを作ればいい(migrateなどは不要なのでおもむろにmodelを追加する形でもいい)

class Project < RedmineBase
end

Project.find(:all)

ここで罠がある. unicornみたいな複数スレッドを回すパターンだと何故か self.headers[X-Redmine-API-Key'] の中身が消失し,認証に失敗し続けるという事があったので,何とかして回避させる.

class RedmineBase < ActiveResource::Base
  self.site = 'https://redmine.example'
  self.headers['X-Redmine-API-Key'] = 'hogee'
  self.format = :xml

  def self.configure
    self.site = 'https://redmine.example'
    self.headers['X-Redmine-API-Key'] = 'hogee'
    self.format = :xml
  end
end

こうした上で,application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  before_action :configure_redmine_base

  private
  def configure_redmine_base
    RedmineBase.configure
  end
end

こうやって書くと毎回セットアップされるようになるので良さそう.

モデル名とRESTのPathが一致しない場合には,prefixを設定する.

class Membership < RedmineBase
  def self.set_project(project_id)
    self.prefix = "/projects/#{project_id}/"
  end
end

Project.find(:all)で一度に取れるプロジェクト数などがxml apiの関係でデフォルト25件になっている.*1

全件取りたいときはこんな感じ

@projects = []

page_index = 1
loop do
  projects = Project.find(:all, params: {page: page_index})
  page_index = page_index + 1

  break if projects.count == 0
  @projects = @projects.concat(projects)
end

limitは最大100件なので,paramsにlimit: 100とすればもう少しリクエストを少なくできる.クエリーにつけるオプションなどもparamsに引っ付ければいい.

使ってみて

whereなどが使えないのでActiveRecordかと思いきやそうでもないので意外と使いにくい.今回の利用では問題なかったけどこれで思いっきり何かをするというのは意外と使えなさそう. Rails本家からパージされて別プロジェクトとかで管理されているので今後どうなるかわからない(純粋に分離しただけ説もありますが)

全件取るときなどは非常に時間がかかるので,結局mysqlに直繋ぎしたほうが早そうという気持ちもある.

Project.findでIssue(この場合はチケット)で取れるカラムと直接Issue.findで取れるカラムが少し違うことがあって困った.今回はredmine pluginを作って必要なカラムを足すことで回避した.

*1:allってついているのにややこしいな...