This Project Has Not Released Any Files
engineて何?
目次
engineの雛型はrailsコマンドが作ってくれる。
rails plugin new xxx
クリエイティブコモンズ3.0をcreative_commons_v30_licensesというengine名で作ってみる。
C:\Sites>rails plugin new creative_commons_v30_licenses --mountable -T --dummy-path=spec/dummyこのengineを組み込むと、engineの機能は以下のurlでアクセスできる
engineが作った雛型にもrailsコマンドが含まれている。これでモデルとコントローラを作成する。
ぺったんRでは、どちらもAttribute(attributes)という名前で作成することになっている。
creative_commons_v30_licensesに、モデルとコントローラを作る。
C:\Sites>cd creative_commons_v30_licenses C:\Sites\creative_commons_v30_licenses>rails g model Attribute C:\Sites\creative_commons_v30_licenses>rails g controller attributes
前編で作成したjsonデータをファイルとしてengine内に配置する。dbディレクトリにengine名.jsonの規則で配置する。
creative_commons_v30_licensesの場合
db/creative_commons_v30_licenses.json
spec/dummyにengineを組み込む想定の環境を構築する。それはつまり、ぺったんRの環境。擬似環境でそれを作り出すのは大変だから、たぶんぺったんRをコピーする方が速い。しかし、ただコピーするだけでは動かない。dummy以下を一旦バックアップコピーしておいて、ぺったんRを上書きコピーしちゃう。その後、両者を見比べながら差異を埋めていく。
creative_commons_v30_licensesの場合
Railsルートのconfig.ruとRakefile、config/boot.rbは上書きダメだから、dummyのバックアップから戻してくる。
config/application.rbはengine読み込みがたりないので以下を追加。
Bundler.require require "creative_commons_v30_licenses"
gemの依存関係はspec/dummyではなく、engine本体で記述。GemfileとGemfile.lockをengineルートに移動。spec/dummy直下の方が優先順位が高いので、必ず移動する。Gemfileをいじったのでgem更新。
C:\Sites\creative_commons_v30_licenses\spec\dummy>cp Gemfile ..\..\ C:\Sites\creative_commons_v30_licenses\spec\dummy>bundle update
ApplicationControllerの書き換え。ぺったんR本体の事前処理を読み込むようにする。これをしないとログイン中のアカウントはわからなくなる。
module TestSpeechBalloon class ApplicationController < ::ApplicationController end end
Dummyの置換。ぺったんR本体のアプリケーション名が変わっているので再定義し直す。
module Dummy end Pettanr = Dummy
ただし、development.rbのTestLayout部分は置換すると面倒なので、そのまま。
spec/dummy以下を削除した時点でspec/dummyをgit管理から無視するように.gitignoreを編集する。ダミーアプリケーション丸ごと管理するのは無理がある。
ライセンス付与までの流れ
事前準備として以下の作業がある
ライセンス付与に関係する処理は、OriginalPictures、OriginalPictureLicenseGroups、engine、ResourcePictures。この内、ライセンス作成者が作成する部分はengine(ライセンス選択)だけ。そのライセンス選択はRailsのengineとして作成する。
以上のことから、ライセンス作成とは、ライセンスのマスターデータ作成とライセンス付与処理のengine作成のことだと言える。
先ほどの前提知識を読むと、engineのコントローラがすべきことは以下のことだとわかる。
engineのモデルは、フォームで入力されたライセンス固有の情報を検証するためにある。固有情報の他には、全ライセンスに共通した必須項目である著作者名とライセンスidを検証する。また、素材モデルはライセンス固有の情報をカラム別には受け取れないので、jsonテキストに変換する機能を実装するためにある。
ResourcePictureModelの作成に必要なデータで補充が効かないもの。
どっちつかずな項目にロゴ画像のidがある。ライセンスのマスターデータから取ってこれる情報だから素材モデルにカラムはない。しかし、現実はロゴを取るだけにライセンスを引っ張ってくるのはアレなので、creditに含んでいる。ライセンスに「ロゴは必須だ」と言い切れないから半端になっている。
ライセンス固有の情報をdbのテーブルに落としてMigrationファイルを編集する。さらに以下の必須項目を追加する。
creative_commons_v30_licensesの場合
前編でデータ構造を以下のように決めた。
すべてテキストの入力フィールドで、制限はない。
class CreateCreativeCommonsV30LicensesAttributes < ActiveRecord::Migration def change create_table :creative_commons_v30_licenses_attributes do |t| t.column :license_id, :integer, :null => false, :default => 0 t.column :artist_name, :string, :null => false, :default => 'unknown' t.column :caption, :string t.column :artist_url, :string t.column :source_url, :string t.column :more_permission_url, :string t.timestamps end end endこうなった。
creative_commons_v30_licensesの場合
結果、こうなった。
module CreativeCommonsV30Licenses class Attribute < ActiveRecord::Base belongs_to :license validates :license_id, :presence => true, :numericality => true, :existence => true validates :artist_name, :presence => true def supply_default ar self.artist_name = ar.name end def credit { :system_picture_id => self.license.system_picture_id, :caption => self.caption, :artist_url => self.artist_url, :source_url => self.source_url, :more_permission_url => self.more_permission_url }.to_json.to_s end end end
engine側ではぺったんRのApplicationControllerの機能が処理されない。認証フィルタが動かないと困るから、engine側ApplicationControllerを書き換えて認証処理を通す。
creative_commons_v30_licensesの場合
module CreativeCommonsV30Licenses class ApplicationController < ::ApplicationController end end
前提知識(コントローラ編)では、コントローラの仕事は入力フォームの表示と入力データの検証と確認した。つまり、NewとCreateがあればよい。Newは検証で引っ掛かかったときに動く。
engineはぺったんRとルートが被らないようにコンフィグファイルが独立している。engineのアクションはengine名以下のurlで表す。
engineのconfig/routes.rbを編集する。
creative_commons_v30_licensesの場合
CreativeCommonsV30Licenses::Engine.routes.draw do resources :attributes do new do get :new end collection do post :create end end end
Create処理のキモは
オブジェクト生成以外は共通した処理。
creative_commons_v30_licensesの場合
require_dependency "creative_commons_v30_licenses/application_controller" module CreativeCommonsV30Licenses class AttributesController < ApplicationController layout 'test' if Pettanr::TestLayout before_filter :authenticate_user!, :only => [:new, :create] before_filter :authenticate_artist, :only => [:new, :create] def new @original_picture = OriginalPicture.show params[:original_picture_id], @artist @original_picture_license_group = OriginalPictureLicenseGroup.new(params[:original_picture_license_group]) @license_group = LicenseGroup.show @original_picture_license_group.license_group_id @creative_commons_v30_license = CreativeCommonsV30License.new @creative_commons_v30_license.supply_default @artist respond_to do |format| format.html # new.html.erb format.js end end def create @original_picture = OriginalPicture.show params[:original_picture_id], @artist @original_picture_license_group = OriginalPictureLicenseGroup.new params[:original_picture_license_group] @license_group = LicenseGroup.show @original_picture_license_group.license_group_id @creative_commons_v30_license = CreativeCommonsV30Licenses::Attribute.new params[:creative_commons_v30_license] @license = License.show @creative_commons_v30_license.license_id @resource_picture = @original_picture.resource_picture || ResourcePicture.new @resource_picture.attributes = { :original_picture_id => @original_picture.id, :license_id => @license.id, :artist_name => @creative_commons_v30_license.artist_name, :classname => @license_group.classname, :credit => @creative_commons_v30_license.credit, :settings => @license.settings } respond_to do |format| if @creative_commons_v30_license.valid? format.html { render main_app.new_resource_picture_path } format.js { render :template => "resource_pictures/new" } else format.html { render action: "new" } format.js { render action: "new" } end end end end end
以下のビューを用意する。
テンプレートで得られるデータは以下。
留意点は、検証モデルのオブジェクトがないこと。これはOriginalPictureLicenseGroupsCreateからはengineを見ていられない構造だから。よって、テンプレートでは必ず検証モデルを生成しておく。ただし、検証エラーでRenderingされる時だけはオブジェクトが生成されているので、このケースでは生成してはならない。
creative_commons_v30_licensesの場合
<% unless @creative_commons_v30_license @creative_commons_v30_license = CreativeCommonsV30Licenses::Attribute.new @creative_commons_v30_license.supply_default @artist end %> <%= form_tag('/creative_commons_v30_licenses/attributes') do %> <%= collection_select :creative_commons_v30_license, :license_id, @license_group.licenses.map {|l| [l.caption, l.id] }, :last, :first %> 略 <% end %>
engine内で検証モデルの検証を通過した後は素材の新規作成をRenderしてぺったんRに処理を返すが、そこは入力結果の確認なので、入力されたライセンス固有の情報をengine側に表示してもらう必要がある。
テンプレートで得られるデータは以下。
クレジットを表示するために部分テンプレートを用意する。実素材だけを参照できる。
<div> <%= content_tag(:a, tag(:img, :src => picture.license.system_picture.url, :alt => h(picture.license.license_group.caption.to_s + '[' + picture.license.caption.to_s + ']')), :href => picture.license.url ) %> </div>
ダミーアプリケーションのルーティングを書き換えてengineをマウントする。spec/dummy/config/routes.rbに以下を追加する。
mount CreativeCommonsV30Licenses::Engine => "/creative_commons_v30_licenses"
engineのmigrateファイルをダミーアプリケーションにコピーしてMigrationする。
C:\Sites\creative_commons_v30_licenses\spec\dummy>rake creative_commons_v30_licenses:install:migrations C:\Sites\creative_commons_v30_licenses\spec\dummy>rake db:migrate
jsonデータをインポートする。
C:\Sites\creative_commons_v30_licenses\spec\dummy>rails r "LicenseGroup.import('C:\Sites\creative_commons_v30_licenses\db\creative_commons_v30_license.json')"これをRakeタスクでインポートさせたい。
そしてサーバ起動。
C:\Sites\creative_commons_v30_licenses\spec\dummy>rails sぺったんRが動いて、ライセンスのengineが動くことを確認する。
単純に言えば.gemspecのTODO部分を編集してgem buildするだけ。
C:\Sites\creative_commons_v30_licenses>gem build XXXX.gemspec
ライセンスはrubygems.orgで配布する。
gemの参照先が変わったので、テストファイルを作り直し。途中何か聞かれるかもしれないがデフォルト値で進む。
C:\Sites\creative_commons_v30_licenses>rails g rspec:install C:\Sites\creative_commons_v30_licenses>rails g rspec:model Attribute C:\Sites\creative_commons_v30_licenses>rails g rspec:controller Attributespec_helperをengineのspec下に配置する。下記の編集。アプリケーションの位置とサポートツールの位置を設定。
require File.expand_path("../dummy/config/environment", __FILE__)
ENGINE_RAILS_ROOT=File.join(File.dirname(__FILE__), '../') # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories. Dir[File.join(ENGINE_RAILS_ROOT, "spec/support/**/*.rb")].each {|f| require f }factories.rbもspec下に配置する。
specファイルはspec下に配置する。controllersとmodelsディレクトリを作成する。controllerは必ずcontrollers\engine名\attributes_controller_spec.rbの要領で配置する。
engineの名前空間に従って記述する。
attributes_controller_spec.rbでは
describe StandardLicenses::AttributesController doモデルを参照するには
StandardLicenses::Attributeコントローラのget、POSTでNo route matchesに悩まされたら
get :new, :use_route => :standard_licensesのようにルートを指示してやる。
テストdbにテーブルを作成していない
rake standard_licenses:install:migrations rake db:migrate RAILS_ENV='test'Gemfileでテスト対象のengineを読み込んでいる
[PageInfo]
LastUpdate: 2013-06-23 09:47:08, ModifiedBy: yasushiito
[Permissions]
view:all, edit:login users, delete/config:members