作成したカスタム Engine でマイグレーションを追加する場合、Refinery CMS のお作法としてどうするのがよいか? 如何様にもできそうだが、カスタム Engine のメンテナンス性が保てるやり方がよい。そのメモ。
まず最初に product という簡単なサンプルカスタム Engine を作成する。 その後にマイグレーションを追加する方法を記載していく。作業の流れは以下の通り。
- Rails 標準の rails generate migration でマイグレーションファイルを作成する
- 作成されたマイグレーションファイルをカスタム Engine 配下(
vendor/engines/my_engine/db/migrate
)に配置する - generator を使用して Rails プロジェクト本体に配置し直して、
rake db:migrate
Table of Contents
Open Table of Contents
0. 新規のカスタム Engine を作成しておく
これから作業するための新規のカスタム Engine を作成しておく。product という簡易な engine になる。
$ rails g refinery_engine product title:string description:text image:image
create vendor/engines/products/app/controllers/admin/products_controller.rb
create vendor/engines/products/app/controllers/products_controller.rb
create vendor/engines/products/app/models/product.rb
...(snip)...
create vendor/engines/products/refinerycms-products.gemspec
create vendor/engines/products/spec/models/product_spec.rb
------------------------
Now run:
bundle install
rails generate refinerycms_products
rake db:migrate
------------------------
最後のメッセージの指示通り引き続きコマンドを叩き、カスタム Engine を動作可能な状態としておく。
$ bundle install
...(snip)...
$ rails g refinerycms_products
create db/migrate/20110615142942_create_products.rb
create db/seeds/products.rb
------------------------
Now run:
rake db:migrate
------------------------
$ rake db:migrate
== CreateProducts: migrating =================================================
-- create_table(:products)
-> 0.0014s
-- add_index(:products, :id)
-> 0.0005s
== CreateProducts: migrated (0.4472s) ========================================
以上で OK。サーバを起動して管理画面を確認してみると確かに product の管理画面が追加されている。
1. Rails 標準の rails generate migration でマイグレーションファイルを作成する
Product のモデルはすでに作成済みであるが、販売促進用のブローシャアをそれぞれの製品につけたくなったとする。製品に添付ファイルをつけられるようにする。
まずは、Rails 標準の rails generate migration を使用して普通に(Rails way で)マイグレーションファイルを作成する。
$ rails g migration AddBrochureToProducts
invoke active_record
create db/migrate/20110616161904_add_brochure_to_products.rb
マイグレーションファイルに必要な記載を行っておく。
db/migrate/20110615145336_add_brochure_to_product.rb
:
class AddBrochureToProducts < ActiveRecord::Migration
def self.up
add_column :products, :brochure_id, :integer
end
def self.down
remove_column :products, :brochure
end
end
マイグレーションファイルへの追加は以上で終了となる。
上記のマイグレーションの記載に関して、products テーブルに brochure_id という外部キーのフィールドを追加し、関連付けまでさせてたのはわかるが、brochure 本体はどこ?となるだろう。
ここでは、Refinery CMS が標準で用意している Resources Engine を利用している。
resource(ファイル)を扱う為の仕組みは既に Refinery CMS には用意されており、Resource モデルも既に存在する。上記はその外部キーを products テーブルに作成しようとしている。
当然上記のスキーマの更新だけでは動作しないので、既に作成済みの Product モデルにも Resouce への関連を追加しておく。
vendor/engines/products/app/models/product.rb
:
class Product < ActiveRecord::Base
acts_as_indexed :fields => [:title, :description]
validates :title, :presence => true, :uniqueness => true
belongs_to :image
belongs_to :brochure, :class_name => 'Resource' # add
end
2. 作成されたマイグレーションファイルをカスタム Engine 配下(vendor/engines/my_engine/db/migrate)に配置する
先ほどの作成されたマイグレーションファイルは Rails プロジェクト本体の db/migrate 配下に作成されている。 これを Engine の db/migrate 配下に移動する。
$ mv db/migrate/20110616161904_add_brochure_to_products.rb vendor/engines/products/db/migrate/
3. generator を使用して Rails プロジェクト本体に配置し直し rake db:migrate
Refinery CMS が用意している generator を使用して、Rails プロジェクト本体に配置し直す。
$ rails g refinerycms_products
create db/migrate/20110616163831_add_brochure_to_products.rb
You already have a migration called create_products
create db/seeds/products.rb
------------------------
Now run:
rake db:migrate
------------------------
products Engine 配下の db/migrate に移動したマイグレーションファイルが、Rails プロジェクト本体の db/migrate 配下にコピーされる。 これで migrate する。
$ rake db:migrate
== AddBrochureToProducts: migrating ==========================================
-- add_column(:products, :brochure, :integer)
-> 0.0014s
== AddBrochureToProducts: migrated (0.0015s) =================================
仮に同じ名前のマイグレーションファイルがあった場合には、rails g refinerycms_products を実行しても Rails プロジェクト本体にはファイルはコピーされない。
$ rails g refinerycms_products
You already have a migration called add_brochure_to_products
You already have a migration called create_products
identical db/seeds/products.rb
------------------------
Now run:
rake db:migrate
------------------------
以上となる。
スキーマに変更を加える場合には 1 〜 3 の同様の作業を繰り返す。
まどろっこしいことをやっているようだが、この方法により、カスタム Engine ディレクトリ内に全て完結した構成がとれる。
独立性が保たれるので、他プロジェクトへの移植性も高くなる。
(蛇足) 管理画面にブローシャアの登録機能を追加
「カスタム Engine でのマイグレーションの追加」の作業は以上で終了だが、モデルには手を加えたものの、管理画面にブローシャアを登録する為の機能が存在しないので追加する。
既に管理画面用の共通部品として refinerycms-core で resource 用の Picker(/shared/admin/_resource_picker.html.erb
)が用意されているので、これを利用する。
管理画面のフォームの view に以下の追加を行っておく。
vendor/engines/products/app/views/admin/products/_form.html.erb
:
イメージのフィールドの下あたりで brochure 用のフィールドを追加しておく。
...(snip)
<div class='field'>
<%= f.label :image -%>
<%= render :partial => "/shared/admin/image_picker", :locals => {
:f => f,
:field => :image_id,
:image => @product.image,
:toggle_image_display => false
} %>
</div>
# add
<div class='field'>
<%= f.label :brochure -%>
<%= render :partial => "/shared/admin/resource_picker", :locals => {
:f => f,
:field => :brochure_id,
:resource => @product.brochure,
} %>
</div>
管理画面で確認すると確かにブローシャア用のフィールドが追加されておりちゃんと機能する。
同様にユーザに表示する画面にもブローシャアをダウンロードするための機能を追加しておく必要があるが、ここでは割愛する。