Posts Tagged ‘datamapper’
inspecting a many_to_many datamapper relationship object
June 25th, 2009 •
tags: datamapper, ruby
The output of calling inspect on a datamapper many_to_many relationship object is very informative
migrating to datamapper 0.10.0
June 3rd, 2009 •
17 comments
tags: datamapper, ruby
Some prerequisites to get ready for datamapper 0.10.0
You need to have at least rubygems 1.3.5
You need to have a reasonably fresh rspec
The following git instructions only apply if you want to keep track of the ongoing datamapper development.
You can safely omit them if you followed the instructions in the original post to the google group.
sudo gem install addressable mkdir git-sources cd git-sources/ git clone git://github.com/datamapper/extlib.git git clone git://github.com/datamapper/do.git git clone git://github.com/datamapper/dm-core.git git clone git://github.com/datamapper/dm-more.git git clone git://github.com/snusnu/merb.git cd extlib/ rake install cd .. cd do/data_objects/ rake install cd ../do_sqlite3/ rake install cd ../do_xxx/ rake install cd ../.. cd dm-core/ rake install cd .. cd dm-more/ rake install cd ..
Migrating your app to datamapper 0.10.0 is pretty painless,
you mainly need to deal with deprecation notices:
options[:class_name] is now options[:model]
PropertySet#has_property? is now PropertySet#named?
update_attributes is now update and doesn’t support the *allow_attributes parameter anymore
new_record? is now new?
:mutable => true on a has(n, :things, :through => :others) relationship is not supported/necessary anymore
:remote_name option for has(n, :things, :through => :others) is now called :via
:some_property.in => ['val1', 'val2'] is not supported anymore in queries, just use :some_property => ['val1', 'val2']
belongs_to :parent now defaults to :nullable => false
When adding to associations, post.comments.build(...) is now post.comments.new(...)
If you’re using merb and you’re fine using the master branch (upcoming merb-1.1) and not the latest release, all you need to do is update your wycats/merb clone or run the following commands.
cd git-sources/ git clone git://github.com/wycats/merb.git cd merb sudo rake install
If you however want to use datamapper 0.10.0 with latest merb release (1.0.12 at the time of writing) you will currently need to run these commands (Thx again teamon for taking the time to backport stuff!).
merb-1.0.13 will be released soon and will be fully compatible with datamapper 0.10.0.
cd git-sources/ git clone git://github.com/wycats/merb.git cd merb git checkout -b 1.0.x --track origin/1.0.x sudo rake install
You will maybe get some warnings about merb-more but you can safely ignore them.
datamapper storage engine reflection
May 7th, 2009 •
tags: datamapper, ruby
# Find out what storage engines are installed and are supported by datamapper
# This could be especially useful in testing scenarios, where one wants to run
# specs against all adapters that are available on the machine in use.
require "rubygems"
require "dm-core"
require "spec"
module DataMapper
def self.available_storage_engines
[ :sqlite3, :mysql, :postgres ].select do |name|
storage_engine_available?(name)
end
end
def self.storage_engine_available?(name)
::DataObjects.const_defined?(Extlib::Inflection.classify(name.to_s))
end
end
# spec helper
# set it so that it fits your actually installed do_xxx drivers
AVAILABLE_STORAGE_ENGINES = [
:sqlite3,
:mysql
# :postgres
]
describe 'DataMapper storage engine reflection: ' do
describe 'DataMapper.storage_engine_available?(name)' do
it 'should return true for adapters known to be installed on this machine' do
DataMapper.storage_engine_available?(:sqlite3).should == AVAILABLE_STORAGE_ENGINES.include?(:sqlite3)
DataMapper.storage_engine_available?(:mysql).should == AVAILABLE_STORAGE_ENGINES.include?(:mysql)
DataMapper.storage_engine_available?(:postgres).should == AVAILABLE_STORAGE_ENGINES.include?(:postgres)
end
end
describe 'DataMapper.available_storage_engines' do
it 'should try all adapters shipped with dm-core and return all adapters known to be installed on this machine' do
storage_engines = DataMapper.available_storage_engines
storage_engines.size.should == AVAILABLE_STORAGE_ENGINES.size
storage_engines.each do |storage_engine|
AVAILABLE_STORAGE_ENGINES.should include(storage_engine)
end
end
end
end
# mungo:Desktop snusnu$ spec -cfs storage_engine_reflection.rb
#
# DataMapper storage engine reflection: DataMapper.storage_engine_available?(name)
# - should return true for adapters known to be installed on this machine
#
# DataMapper storage engine reflection: DataMapper.available_storage_engines
# - should try all adapters shipped with dm-core and return all adapters known to be installed on this machine
#
# Finished in 0.002688 seconds
#
# 2 examples, 0 failures
#validatable? should work on a belongs_to association
April 30th, 2009 •
tags: datamapper, ruby
The following ONLY APPLIES to datamapper-0.9.x, datamapper-0.10.0 doesn’t have this problem anymore
require "rubygems"
require "dm-core"
require "dm-validations"
require "spec"
DataMapper.setup(:default, "sqlite3::memory:")
class Person
include DataMapper::Resource
property :id, Serial
has 1, :profile
has n, :project_memberships
has n, :projects, :through => :project_memberships
end
class Profile
include DataMapper::Resource
property :id, Serial
property :person_id, Integer, :nullable => false
belongs_to :person
end
class Project
include DataMapper::Resource
property :id, Serial
has n, :tasks
end
class ProjectMembership
include DataMapper::Resource
property :id, Serial
property :person_id, Integer, :nullable => false
property :project_id, Integer, :nullable => false
belongs_to :person
belongs_to :project
end
class Task
include DataMapper::Resource
property :id, Serial
property :project_id, Integer, :nullable => false
belongs_to :project
end
describe "Resource#validatable?" do
before(:all) do
DataMapper.auto_migrate!
end
describe "when called directly on a Resource" do
it "should return true if dm-validations are present" do
Person.create.should be_validatable
Profile.create.should be_validatable
Project.create.should be_validatable
ProjectMembership.create.should be_validatable
end
end
describe "when called on an DataMapper::Associations::ManyToOne::Proxy" do
it "should return true if dm-validations are present" do
person = Person.create
project = Project.create
membership = ProjectMembership.create :person => person, :project => project
membership.person.should be_validatable
membership.project.should be_validatable
end
end
describe "when called on an DataMapper::Associations::OneToMany::Proxy" do
describe "that points to a Resource related with has(n)" do
it "should return true if dm-validations are present" do
p = Project.create
t = Task.create :project_id => p.id
p.reload
p.tasks.all? { |task| task.validatable? }.should be_true
end
end
describe "that points to a Resource related with has(n, :through)" do
it "should return true if dm-validations are present" do
person = Person.create
project = Project.create
membership = ProjectMembership.create :person => person, :project => project
person.reload
person.projects.all? { |p| p.validatable? }.should be_true
end
end
end
end
# mungo:Desktop snusnu$ spec -c -f -s validatable.rb
#
# Resource#validatable? when called directly on a Resource
# - should return true if dm-validations are present
#
# Resource#validatable? when called on an DataMapper::Associations::ManyToOne::Proxy
# - should return true if dm-validations are present (FAILED - 1)
#
# Resource#validatable? when called on an DataMapper::Associations::OneToMany::Proxy that points to a Resource related with has(n)
# - should return true if dm-validations are present
#
# Resource#validatable? when called on an DataMapper::Associations::OneToMany::Proxy that points to a Resource related with has(n, :through)
# - should return true if dm-validations are present
#
# 1)
# 'Resource#validatable? when called on an DataMapper::Associations::ManyToOne::Proxy should return true if dm-validations are present' FAILED
# expected validatable? to return true, got false
# ./validatable.rb:67:
#
# Finished in 0.028411 seconds
#
# 4 examples, 1 failure
extlib/hook breaks if hooked method is redefined
April 29th, 2009 •
tags: datamapper, extlib, ruby
require "rubygems"
require "dm-core"
require "spec"
DataMapper.setup(:default, "sqlite3::memory:")
class Person
include DataMapper::Resource
property :id, Serial
before :save, :shower
after :save, :shave
def shower
@showered = true
end
def shave
@shaved = true
end
def showered?
@showered
end
def shaved?
@shaved
end
end
describe "Hooking Resource#save" do
before(:all) do
DataMapper.auto_migrate!
end
describe "when the hooked method DOES CALL super" do
before(:each) do
class Person
def save(context = nil)
super(context)
end
end
end
it_should_behave_like "hooks"
end
describe "when the hooked method DOES NOT CALL super" do
before(:each) do
class Person
def save(context = nil)
true
end
end
end
it_should_behave_like "hooks"
end
describe "hooks", :shared => true do
it "should preserve established before and after hooks" do
p = Person.new
p.should_not be_showered
p.should_not be_shaved
p.save
p.should be_showered
p.should be_shaved
end
end
end
# mungo:Desktop snusnu$ spec -c -f -s freak.rb
#
# Hooking Resource#save when the hooked method DOES CALL super
# - should preserve established before hooks
#
# Hooking Resource#save when the hooked method DOES NOT CALL super
# - should preserve established before hooks (FAILED - 1)
#
# 1)
# 'Hooking Resource#save when the hooked method DOES NOT CALL super should preserve established before hooks' FAILED
# expected showered? to return true, got nil
# ./freak.rb:76:
#
# Finished in 0.007412 seconds
#
# 2 examples, 1 failure
datamapper and inflection of the english word address
April 20th, 2009 •
1 comment
tags: datamapper, ruby
require 'rubygems'
gem 'dm-core', '=0.9.12'
gem 'rspec'
require 'dm-core'
require "spec"
#DataMapper::Logger.new(STDOUT, :debug)
DataMapper.setup(:default, 'sqlite3:memory:')
Extlib::Inflection.rule 'ess', 'esses'
Extlib::Inflection.singular_word("address", "address")
class Person
include DataMapper::Resource
property :id, Serial
has n, :addresses, :through => Resource
end
class Address
include DataMapper::Resource
property :id, Serial
end
describe "Inflection of 'Address'" do
it "should work in DataMapper.auto_migrate!" do
lambda { DataMapper.auto_migrate! }.should_not raise_error
end
end
# mungo:Desktop snusnu$ spec -c -f -s address.rb
#
# Inflection of 'Address'
# - should work in DataMapper.auto_migrate!
#
# Finished in 0.040151 seconds
#
# 1 example, 0 failures
textmate rspec bundle (datamapper) helpers
April 9th, 2009 •
1 comment
tags: datamapper, rspec, ruby
I found that I often want to add debug outputs to the specs while working on them. Since I use textmate’s rspec bundle to run (focused) unit tests, I needed my debug messages to be html. Here’s what I came up with
dm-accepts_nested_attributes
April 8th, 2009 •
tags: datamapper, ruby
I just pushed http://github.com/snusnu/dm-accepts_nested_attributes/tree/master
It’s probably not quite complete yet, but it’s already reasonably specced and functional.
254 examples, 0 failures 89.7% 3 file(s) 473 Lines 234 LOC
Current status:
- belongs_to: create / destroy / update
- has(1): create / update/ destroy
- has(n): create / update / destroy
- has(n, :through): create / update / destroy
Also, since I need this rather soon for my current (merb) project, I wrote it for 0.9.11 I definitely want it to be available for next branch (of course) but I cannot spend any time on it now, since from what I read, the datamapper next branch is not production ready yet.
Anyways, I think it’d be really cool to have this in datamapper! (a plugin is perfeclty fine, needn’t be core). The API is almost the same (one minor change for now - have a look at the README) like the one activerecord has, which should mean, that once rails3 comes out, multimodel forms are totally possible with datamapper as ORM.
As for merb, I don’t really know if it has support for nested model assignment in its form_for and fields_for helpers. I have to say though, that I don’t really care, since I don’t use these helpers, but write the html that my designer colleague wants to see.
Any help, ideas, discussions on irc/email, forks, patches, whatever … really appreciated!
UPDATE 12
This commit added initial support for transactions. Currently, every call to save gets wrapped inside a transaction. However,there is still some work to do to make this solid. It’s also totally not specced atm.
UPDATE 11
This commit added a hook to allow to sanitize nested model attributes that get passed to a resource. See this thread on the rails-core list for the motivation behind this new method. Currently the method doesn’t do anything, but can be overwritten to perform just the amount of sanitization that you would like to apply.
UPDATE 10
With this patch from Rupert Voelcker, it is now possible to access the nested attributes also after Resource#save was called. This means that if for example a controller’s create action needs to redirect to the new action because the resource couldn’t be saved, the values the user previously entered can be displayed on the new form, just as you would expect. Thx again Rupert!
UPDATE 9
This commit added (experimental) support for dm-validations. More details explaining the current status and TODO list can be found in my post to the datamapper mailinglist
UPDATE 8
Rupert Voelcker sent a patch that allows renamed has(n, :through, :class_name, :child_key, :parent_key) associations to work with dm-accepts_nested_attributes. Thx a lot!
UPDATE 7
This commit added a new helper method for many_to_one (belongs_to) and one_to_one (has 1) associations, that will return either the associated record (if present) or a new record of the associated class. This is somehow close to activerecords build_association, I guess, but it differs in that it won’t build a new record in case that one is already associated. For this reason, I named it get_#{association}. It isn’t available for _to_many associations, since datamapper already provides get and build methods on their association proxy.
After I added this method, I read through Ryan’s Scraps again, and got reminded of his cool trick to achieve the same thing I’m trying to do with view helpers (I mainly added this feature to support fields_for a nested attribute). I totally agree when he says that it’s actually a view concern to prepare the resource for form submission, and I’m now thinking that I will maybe remove this added feauture from dm-accepts_nested_attributes
UPDATE 6
This commit added the possibility to specify a reject_if proc that gets passed all attributes. If the proc returns true, the creation of a new associated entry will be rejected. Now, dm-accepts_nested_attributes supports the same features as activerecord nested attribute assignment (I think).
UPDATE 5
This commit added the possibility to update has(n, :through) associations via #{association_name}_attributes=
This means that all (current) specs pass and everything works so far :) Hooray!
UPDATE 4
This commit added the possibility to destroy has(n, :through) associations via #{association_name}_attributes=
UPDATE 3
This commit added the possibility to create has(n, :through) associations via #{association_name}_attributes=
UPDATE 2
It seems to me that this commit fixes the issue mentioned in UPDATE 1 since the new code should behave the same as dm-core-0.9.11 does if the association to be saved does not accept_nested_attributes
UPDATE 1
In order to get update working for belongs_to, has(1) and has(n), I commented out a line of dm-core-0.9.11 code which doesn’t seem to have too many effects. I ran the specs for 0.9.11 with this change incorporated, and mostly mocks(!) that expect the method call that i commented, fail. However, there is also one stack level too deep error Now, I don’t really know if this means that something else is broken really badly now, or if this can be worked around. The new failing dm-core specs after this commit are:
1)
SystemStackError in ‘DataMapper::Associations one to many associations #<< should add the correct number of elements if they are created’
stack level too deep
/Users/snusnu/projects/github/dm-core/lib/dm-core/repository.rb:41:in `scope’
/Users/snusnu/projects/github/dm-core/lib/dm-core.rb:181:in `repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core/support/kernel.rb:6:in `repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/relationship.rb:172:in `with_repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/one_to_many.rb:298:in `save_resource’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/one_to_many.rb:210:in `save’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/one_to_many.rb:309:in `send’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/one_to_many.rb:309:in `method_missing’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/one_to_many.rb:210:in `save’
/Users/snusnu/projects/github/dm-core/lib/dm-core/resource.rb:301:in `hookable__save_nan_before_advised’
/Users/snusnu/projects/github/dm-core/lib/dm-core/resource.rb:301:in `each’
/Users/snusnu/projects/github/dm-core/lib/dm-core/resource.rb:301:in `hookable__save_nan_before_advised’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/many_to_one.rb:64:in `save’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/relationship.rb:172:in `with_repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core/support/kernel.rb:6:in `repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core.rb:181:in `repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core/repository.rb:44:in `scope’
……………………
2)
Spec::Mocks::MockExpectationError in ‘DataMapper::Associations::ManyToOne::Proxy#save when the parent is not a new record should not save the parent’
#<ManyToOneSpec::Parent:0×1159388> expected :save with (no args) 0 times, but received it once
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/many_to_one.rb:64:in `save’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/relationship.rb:172:in `with_repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core/support/kernel.rb:6:in `repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core.rb:181:in `repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core/repository.rb:44:in `scope’
/Users/snusnu/projects/github/dm-core/lib/dm-core.rb:181:in `repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core/support/kernel.rb:6:in `repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/relationship.rb:172:in `with_repository’
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/many_to_one.rb:63:in `save’
/Users/snusnu/projects/github/dm-core/spec/integration/associations/many_to_one_spec.rb:116:
11)
Spec::Mocks::MockExpectationError in ‘DataMapper::Associations::ManyToOne::Proxy#save when the parent is not a new record should not save the parent’
Mock ‘relationship’ received unexpected message :with_repository with (#<Spec::Mocks::Mock:0×217d426 @name=”parent”>)
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/many_to_one.rb:63:in `save’
/Users/snusnu/projects/github/dm-core/spec/unit/associations/many_to_one_spec.rb:91:
12)
Spec::Mocks::MockExpectationError in ‘DataMapper::Associations::ManyToOne::Proxy#save when the parent is not a new record should return true’
Mock ‘relationship’ received unexpected message :with_repository with (#<Spec::Mocks::Mock:0×216d9cc @name=”parent”>)
/Users/snusnu/projects/github/dm-core/lib/dm-core/associations/many_to_one.rb:63:in `save’
/Users/snusnu/projects/github/dm-core/spec/unit/associations/many_to_one_spec.rb:95:
13)
Spec::Mocks::MockExpectationError in ‘DataMapper::Associations::ManyToOne::Proxy#save when the parent is a new record should save the parent’
Mock ‘parent’ expected :new_record? with (no args) once, but received it 0 times
/Users/snusnu/projects/github/dm-core/spec/unit/associations/many_to_one_spec.rb:101:
14)
Spec::Mocks::MockExpectationError in ‘DataMapper::Associations::ManyToOne::Proxy#save when the parent is a new record should return the result of the save’
Mock ‘parent’ expected :new_record? with (no args) once, but received it 0 times
/Users/snusnu/projects/github/dm-core/spec/unit/associations/many_to_one_spec.rb:101:
datamapper debug output in Textmate RSpec Bundle
April 8th, 2009 •
tags: datamapper, ruby
# stick this in spec_helper.rb
# this will append a <br /> to every logged message, which produces
# nicely formatted DataMapper debug outputs in Textmate's RSpec Bundle's output
module DataMapper
class TextmateRspecLogger < Logger
def prep_msg(message, level)
"#{super}<br />"
end
end
end
# comment this for spec runs where you don't need to see logs
DataMapper::TextmateRspecLogger.new(STDOUT, :debug)
dm-is-cloneable
April 1st, 2009 •
tags: datamapper, ruby
I just pushed dm-is-cloneable.
A DataMapper plugin that adds the ability to clone any model. As this alone wouldn’t really be a big deal, it is also possible to specifiy a 1:n relation with so called clone_specs. In these, the attributes_to_clone are persisted, thus leaving clients with the choice of selecting predefined sets of attributes to clone. Currently, associated objects don’t get cloned, although this might change if I need this in the future.
Client code looks something like this:
require 'rubygems' gem 'dm-core', '=0.9.11' gem 'dm-validations', '=0.9.11' gem 'dm-is-remixable', '=0.9.11' gem 'dm-is-cloneable', '=0.0.1' require 'dm-core' require 'dm-validations' require 'dm-is-remixable' require 'dm-is-cloneable' DataMapper::Logger.new(STDOUT, :debug) DataMapper.setup(:default, 'sqlite3:memory:') class Item include DataMapper::Resource property :id, Serial property :master_item_id, Integer # add this property if backlinks are desired property :name, String property :description, String is :cloneable # adds the following api to this class # # # attributes_to_clone can be one of # # <:all|String|Array[String|Symbol]|ItemCloneSpec> # Item#clone_resource(nr_of_clones, attributes_to_clone = :all) # Item#master_resource # Item#cloned_resources # Item#has_backlinks_to_master? # Item#has_clone_specs? end