query: tag:DM

dm-is-remixable
は、Commentなどの複数のリソースにまたがって共用されるがちなリソースをDRYにするためのDataMapperプラグインです。

しかし、Validationのためのコードを記述しても、正常に動作しないという問題がありました。これは、以下のようにすれば解決できます。

ruby>>
module Commentable
include DataMapper::Resource
is :remixable, :suffix => "comment"

(..snip..)

def self.included(base)
base.class_eval do
validates_present :message
end
end
end
<<--

See Also

posted by genki genki on Tue 5 May 2009 at 01:54 with 0 comments

I shipped new dm-datastore-adapter today.

This update is a long jump from previous version. It includes following functions

  • Transaction. It utilizes the DataStore's Transaction API
  • OR conditions
    ruby>>
    Post.all(:id => [1,2])
    <<--
  • NOT conditions
    ruby>>
    Post.all(:id.not => 4)
    <<--

So now we can use most of functions defined in DM by using this adapter.

Enjoy!

posted by takiuchi takiuchi on Fri 17 Apr 2009 at 05:44 with 0 comments

DataMapper用のDataStoreアダプター、dm-datastore-adapter-0.2.2をリリースしました。

今回のリリースで以下のような機能がサポートされます。

  • トランザクション
  • OR条件
    ruby>>
    Post.all(:id => [1,2,3])
    <<--
    のような事が出来るようになりました。
  • NOT条件
    ruby>>
    Post.all(:updated_at.not => nil)
    Post.all(:id.not => 3)
    <<--
    などが出来るようになりました。

DataMapperのアダプタとして主に必要な機能はだいたい揃ってきました。

デモサイトであるWatchMe!もアップデートしています。

まだ実用的なサービスになってないですが、登録したサイトをクローリングして全てのページの監視を行い、エラーが発生したらメールで知らせるサービスになる予定です。

posted by genki genki on Fri 17 Apr 2009 at 04:29 with 8 comments

Today I shipped a new DataMapper plugin that enables us to easily develop Merb-apps been worked with GAE/J.

By using this plugin, you can seamlessly develop your Merb-apps between local and GAE/J environment.

For example, this site is powered by Merb/DM with the dm-datastore-adapter and running on the GAE/J

(This service is under construction :-p)

As a matter of fact, because it is still being alpha status,
you must treat various issues regarding gem dependencies yet.
I appreciate any kind of feedback and of course patches :-)

Enjoy!

posted by takiuchi takiuchi on Mon 13 Apr 2009 at 05:43 with 11 comments

DataMapper用のDataStore用アダプタ、dm-datastore-adapterを作りました。

これを使えば、MerbアプリをほぼそのままGoogle App Engine for Javaの上で動かせるようになります。
(実際にはgemの依存関係など、細かい調整が必要になりますが)

実際に以下のサイトでdm-datastore-adapterを使っています。

ローカル環境でも別なアダプタを利用すれば、普通のMerbアプリとして動作テストできるので、開発効率が飛躍的に向上します。

posted by genki genki on Mon 13 Apr 2009 at 05:37 with 0 comments

Merb/DataMapperをしばらく使っていたのですが、
少なくともバージョン0.9.10, 0.9.11では、
associationの実装にバグがあり、
レコード数が多いテーブルがあると、aggregation系の処理に時間がかかるという問題がある事が分かりました。

例えば、Post.has n, :comments な関係がある時に、
以下のようなコードを実行すると、このようになります。

ruby>>
?> Post.first.comments.count #=> 188
~ (0.000865) SELECT "id" FROM "posts" ORDER BY "id" LIMIT 1
~ (0.000094) SELECT "id", "post_id" FROM "comments" WHERE ("post_id" IN (1)) ORDER BY "id"
~ (0.000063) SELECT COUNT(*) FROM "comments" WHERE ("post_id" = 1)
<<--

2つ目のSQLは不要なのですが、発行されてしまいます。
例えばCommentのレコード数が多かった場合、Commentオブジェクトを大量に生成しようとしてしまうため、致命的な遅さになってしまいます。

目下この問題の解決策を探しているところですが、
Edge-DMのspec/仕様でerrorが出ている状態なので、なかなか手が付けられない感じです。
とりあえず、dm-coreのassociations/relationship.rbの中の、

ruby>>
# @api private
def get_children(parent, options = {}, finder = :all, *args)
parent_value = parent_key.get(parent)
bind_values = [ parent_value ]

    with_repository(child_model) do |r|
      parent_identity_map = parent.repository.identity_map(parent_model)

      query_values = parent_identity_map.keys
      bind_values = query_values unless query_values.empty?
      query = child_key.zip(bind_values.transpose).to_hash
      collection = child_model.send(finder, *(args.dup << @query.merge(optio

ns).merge(query)))

      return collection unless collection.kind_of?(Collection) && collection.any?

<<--

の最後の collection.any? で件のSQLが実行されているところまでは分かりました。
DataMapper::CollectionはextlibのLazyArrayを継承しているクラスなのですが、どうもそのへんの仕様が変わったのに追従できてないのかな。
モジュールを過度に分散しすぎるのも、整合性を保つのが大変になるという問題がありますね。
注意深く完全なSpecを書く事を心がけていれば防げる問題かもしれないですが。

posted by genki genki on Wed 8 Apr 2009 at 04:52 with 0 comments

DataMapperはSQLを解さないアダプタも利用可能なので、この方法でSQLが実行できるかどうかはアダプタを選びますが、一般的には以下のようにすれば直接SQLを実行できます。

ruby>>
Post.repository.adapter.execute("sql string")
<<--

結果は、例えばmysqlを使っている場合にはDataObjects::Mysql::Resultが帰ってきます。

posted by genki genki on Tue 7 Apr 2009 at 00:54 with 0 comments

DataMapperでSetterメソッドを上書きして、プロパティの設定をコントロールするには、以下のようにします。

ruby>>
def uri=(uri)
attribute_set :uri, ::URI.parse(uri).normalize.to_s
end
<<--

posted by genki genki on Sun 5 Apr 2009 at 06:54 with 0 comments

Merb/DataMapper/CouchDBの環境で rspec を使う場合には、
spec_helper.rb
で以下のように設定すると良いようです。

ruby>>
config.before(:all) do
DataMapper::AutoMigrator.auto_migrate(nil,
*(DataMapper::Resource.descendants - [Merb::DataMapperSessionStore]))
end
<<--

セッションストアを使っている場合は、
Merb::DataMapperSessionStore用のrepositoryを
別途指定すると良いと思います。

posted by genki genki on Sat 4 Apr 2009 at 22:07 with 0 comments

DataMapper#auto_migrate!を実行すると、以下のようなコードが実行される。

ruby>>
self.auto_migrate!(repository_name = nil)
AutoMigrator.auto_migrate(repository_name)
end
<<--

AutoMigrator#auto_migrateは以下のようになっている。

ruby>>
def self.auto_migrate(repository_name = nil, *descendants)
auto_migrate_down(repository_name, *descendants)
auto_migrate_up(repository_name, *descendants)
end
<<--

第二引数以降でDMのクラスリストを指定できる。
省略すると、DataMapper::Resource.decendantsが指定されたものとして動作する。
特定のリソースだけまとめてauto_migrateするには便利そうだ。

posted by genki genki on Sat 4 Apr 2009 at 12:49 with 0 comments

あのAsakusa.rbから、dm-paginationバージョン0.3.2がリリースされました。

dm-pagination-0.3.2 is out from Asakusa.rb

最近の改善が取り込まれています。
dm-paginationはMerb with DataMapper用のpaginationを提供するプラグインです。
Rails用の
pagination_scope
の姉妹プラグインです。

See Also

posted by genki genki on Tue 31 Mar 2009 at 10:32 with 0 comments

DataMapper用のバージョン管理プラグイン、
dm-has-versions
をリリースしました。

dm-is-versionedというライブラリが既にあるのですが、Railsで慣れ親しんだacts_as_versionedと微妙に挙動が違うのと、revert_toやversion=ができないなど、細かいところが足りない感じがしたので作りました。

USAGE:

以下のコードをご覧の通りです。

ruby>>
class Story
include DataMapper::Resource

property :id, Integer, :serial => true
property :title, String
property :updated_at, DateTime

has_versions :ignore => [:updated_at]
end

Story.auto_upgrade!

story = Story.create(:title => 'hello')
story.version #=> 0
story.update_attributes :title => 'good night'
story.version #=> 1
story.title #=> 'good night'
story.version = 0
story.title #=> 'hello'
<<--

auto_upgrade!は最初に一回だけ必要です。

posted by genki genki on Fri 16 Jan 2009 at 03:37 with 0 comments
dm-is-paginated-0.0.1は、specが走らない状態だったので、 Railsの [pagination_scope](https://github.com/genki/pagination_scope/tree)風味のDataMapper用Paginationライブラリとして、 [dm-pagination](http://github.com/genki/dm-pagination/tree/master) を作りました。 ruby>> class Posts def index @posts = Post.paginate(:page => params[:page]) end <<-- 上記のようにコントローラでpaginationオブジェクトを作成し、 Viewから以下のように参照します。 html>>
    <% @posts.each do |post| %>
  • <%= h(post.body) %>
  • <% end %>
<%= paginate @posts %> <<--
posted by genki genki on Thu 15 Jan 2009 at 01:41 with 0 comments

DataMapperのResourceの派生クラスを列挙するには、以下のようにします。

ruby>>
DataMapper::Resource.descendants
=> #<Set: {User, Event, Merb::DataMapperSessionStore, Comment}>
<<--

簡単ですね。

posted by genki genki on Sun 11 Jan 2009 at 16:54 with 1 comment

Railsでいうところの@user.errors.addに相当する機能について、
merb(DataMapper)でも似たような仕組みがあります。

エラー情報を追加するためには、以下のようにします。

ruby>>
@user.errors.add(:login, "login is invalid")
@user.errors.add(:general, "I'm in a bad mood today :-P"
<<--

errorsは、
DataMapper::Validate::ValidationErrorsクラス
のインスタンスです。特定のプロパティーに関連するメッセージは、第一引数でプロパティを示すシンボルを、それ以外の場合は:generalを指定するようです。

posted by genki genki on Thu 1 Jan 2009 at 21:32 with 0 comments

Railsで言う所のbefore_saveのようなフィルタは、
Merb(DataMapper)では以下のように使う。

ruby>>
class Post
include DataMapper::Resource

before :save do
# do some stuff
end

def foo
puts "foo!"
end

before :foo, :bar

def bar
puts "bar!"
end
end
<<--

このbeforeメソッドは、ExtLibのhook.rbの中で定義されている。
上記のように、ブロックを取る形式と、イベントをハンドルするメソッド名をシンボルで指定する形式があります。

ExtLibが提供するhookは、saveやvalid?のような特定のイベントだけではなく、全てのメソッドに対して汎用的に利用出来るようです。
ただし、before :foo, :barのように、hookをインストールする時点で、
hookされるメソッド(この場合はfoo)が定義されている必要があります。

クラスメソッドに対するhookも用意されていて、

ruby>>
before_class_method :new do
puts "new!"
end
<<--

のように利用出来ます。

Update

beforeフィルターでメソッドの実行を中止する場合は、

ruby>>
before :save do
throw :halt
end
<<--

のように、:haltをthrowすればOKです(thanks maiha)。
これは美しい。

posted by genki genki on Tue 30 Dec 2008 at 11:27 with 0 comments

僕はMerbではDataMapperを使うのがお勧めだと思いますが、
DataMapperで利用可能なpropertyの型をまとめておきます。

  • TrueClass, Boolean
  • String
  • Text (デフォルトでは65536バイト)
  • Float
  • Integer
  • BigDecimal
  • DateTime
  • Date
  • Time
  • Object (マーシャル/アンマーシャルされる)
  • Class (Stringと同様に扱われる)

基本的には、

ruby>>
property :name, Type[, options]
<<--

という感じで利用します。

optionsとしては、Hashの形式で以下のようなものが指定出来ます。

  • :accessor, :reader, :writer => :private, :protected, :public
  • :nullable => true
  • :default => value
  • :lazy => true, false (遅延読み込みのオン/オフ)
  • :key => true (Model[key]でアクセスできるようになる)
  • :index => true, "name" (インデックスを作成)
  • :size => length (テキストの長さなど)
  • and so on...

See Also

posted by genki genki on Fri 19 Dec 2008 at 15:11 with 0 comments

CapistranoをMerbでDataMapperを使ってる場合に、
cap deploy:migrationsを実行した時に、rake db:migrateではなく、
rake db:autoupgradeをするようにするための設定の書き方のメモです。

具体的には、以下のようにdeploy:migrateタスクを書き換えます。

config/deploy.rb

ruby>>
namespace :deploy do
desc "Run autoupgrade"
task :migrate do
run "cd #{release_path}; rake db:autoupgrade MERB_ENV=production"
end
end
<<--

これでOKです。

posted by genki genki on Tue 2 Dec 2008 at 15:04 with 0 comments

MerbでDataMapperを使っている場合にアソシエイションを記述する場合、
以下のようにhasメソッドを利用します。

ruby>>
class User
include DataMapper::Resource

property :id, Serial
property :login, String

has n, :assignments
has n, :groups, :through => :assignments
end
<<--

第一引数はカーディナリティを指定します。nは
DataMapper::Associations#nで、値はInfinityです。
1, 2, 3などの数値や、1..3, 5..n などのRangeを指定する事もできます。

上の例のように、Railsのhas_many :throughのようなこともできます。

posted by genki genki on Fri 21 Nov 2008 at 16:35 with 0 comments