SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

Rails ActionWebServiceジェネレータのカスタマイズ

Rails ActionWebServiceジェネレータをカスタマイズする方法の御紹介

ダウンロード サンプルソース (2.0 KB)

もとになるジェネレータの格納場所

 カスタマイズを加えるもとになるジェネレータのソースファイルは、Rubyのインストールディレクトリの配下である「lib\ruby\gems\1.8\gems\rails-1.2.5\lib\rails_generator\generators\components\web_service」といったパスに存在しています。このパスに存在しているファイルに対してカスタマイズを加えます。

これから作成するジェネレータの格納場所

カスタマイズを加えたジェネレータの格納場所

 さて、これから作成するジェネレータの格納場所ですが、Railsは次に示すディレクトリからユーザー定義のジェネレータを探しますので、本稿では「lib\generators」配下にジェネレータを配置します。「generators」フォルダが無い場合は、作成します。

  • RAILS_ROOT\lib\generators
  • RAILS_ROOT\vendor\generators
  • RAILS_ROOT\vendor\plugins\任意のサブディレクトリ\generators
 RAILS_ROOTはRailsで生成したアプリケーションのルートディレクトリを表しています。

格納場所の作成

 前述の「もとになるジェネレータの格納場所」にあるディレクトリやファイルをコピーして、次のようにファイル名を変更することで、「これから作成するジェネレータの格納場所」を作ります。

  1. 「RAILS_ROOT\lib\generators」に「mst_web_service」というディレクトリを作成します。その配下に「mst_web_service_generator.rb」というファイルを作成します。
  2. また、「mst_web_service」ディレクトリの配下に「templates」ディレクトリを作成します。「templates」ディレクトリの配下にはジェネレートするファイルのテンプレートを保存します。

ジェネレータのカスタマイズコード その1

web_service_generator.rbのカスタマイズ

 まず、「web_service_generator.rb」をカスタマイズします。各要素の内容は次のとおりです。

  • NamedBaseは、Railsにおけるジェネレータの拡張元となるクラスです。
  • class_colissionsメソッドにより、これから生成するクラスが、RubyやRailsのクラスとして既に使用されていないことを確認します。
  • directoryメソッドにより、これから生成するクラスを格納するディレクトリを作成します。
  • templateメソッドにより、テンプレートをもとにクラスを生成します。
  • templateメソッドでは、第1引数にテンプレートとなるファイルを指定し、第2引数に出力するファイルパスを指定します。
mst_web_service_generator.rb
class MstWebServiceGenerator < Rails::Generator::NamedBase
  def manifest
    record do |m|
      # Check for class naming collisions.
      m.class_collisions class_path, "#{class_name}ServiceApi", 
         "#{class_name}ServiceController","#{class_name}ApiTest"
      # API and test directories.
      m.directory File.join('app/apis', class_path)
      m.directory File.join('app/controllers', class_path)
      m.directory File.join('test/functional', class_path)

      # API definition, controller, and functional test.
      m.template 'api_definition.rb',
                  File.join('app/apis',
                            class_path,
                            "#{file_name}_service_api.rb")

      m.template 'controller.rb',
                  File.join('app/controllers',
                            class_path,
                            "#{file_name}_service_controller.rb")

      m.template 'functional_test.rb',
                  File.join('test/functional',
                            class_path,
                            "#{file_name}_service_api_test.rb")
    end
  end
end

 次に、テンプレートをカスタマイズしていきます。

「api_definition.rb」テンプレートのカスタマイズ

 「api_definition.rb」テンプレートは、WebサービスのAPIクラスを作成するテンプレートです。データベース上のテーブルを更新するサービスメソッドを外部に公開するためには、データベース上のテーブルに対応する構造体をAPIクラスで定義する必要があります。先頭のmodule XmlrpcStructで、その構造体を定義しています。

 Webサービスでメソッドを公開するためには、api_methodでそのメソッドを指定する必要があります。api_methodではexpectsで引数を、returnsで返り値に関する定義を行います。

 Webサービスを通じてデータベース上のテーブルを更新するためには、そのテーブルのデータ型を公開する必要があります。RailsではActiveRecordを継承したモデルクラスが、テーブルのデータ型に当たるので、これを公開すれば良いように思えます。しかし、ActiveRecordは返り値に指定できても、引数には指定することができません。

 そこでfind_allでは、returnsにActiveRecordを継承したクラスを指定します。find_all以外のメソッドでは、expectsにActiveRecordを継承したクラスを指定することはできないので、module XmlrpcStructで定義したクラスを指定し、その代わりとしています。

api_definition.rb
module XmlrpcStruct
  class <%= class_name %> < ActionWebService::Struct
    <% @model_klass = Module.const_get(class_name) %>
    <% for column in @model_klass.columns %>
      <%
        if column.name == 'created_at' or column.name == 'updated_at'
          next
        end
      %>
      <% if column.name == 'id' %>
        member :id, :integer
      <% else %>
        member :<%= column.name %>, :string
      <% end %>
    <% end %>
  end
end

class <%= class_name %>ServiceApi < ActionWebService::API::Base
<% for method_name in args -%>
  api_method :<%= method_name %>
<% end -%>

  api_method :find_all,
    :returns => [[<%= class_name %>]]

  api_method :create,
    :expects=>[{:arg_<%= file_name %>=>XmlrpcStruct:: 
        <%= class_name %>}],
    :returns=>[:string]

  api_method :update,
    :expects=>[{:arg_<%= file_name %>=>XmlrpcStruct:: 
        <%= class_name %>}],
    :returns=>[:string]

  api_method :destroy,
    :expects=>[{:arg_<%= file_name %>=>XmlrpcStruct:: 
        <%= class_name %>}],
    :returns=>[:string]
end

次のページ
ジェネレータのカスタマイズコード その2

この記事は参考になりましたか?

特集記事連載記事一覧

もっと読む

この記事の著者

ryujinseiichi(リュウジンセイイチ)

http://ryujinseiichi.sblo.jp/ RubyやAIRなどの新規技術に興味があり、研究を行っています。 最近、seasar2やBPMの研究も始めました。  

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2659 2008/07/11 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー