Using DataMapper and Rails with Legacy Schemas »

Created at: 01.06.2011 03:05, source: Engine Yard Blog, tagged: community Open Source Technology Tips & Tricks datamapper

Today's guest post hails from community contributor Piotr Solnica of Code Benders, an agile software collective based in Bend, Oregon. In his free time Piotr supports OSS, is a DataMapper core contributor, an author of DataMapper plugins and adapters and one of the developers of rubytime.org and coderack.org.
Ruby on Rails makes it easy to bootstrap a greenfield project. Unfortunately not all projects are greenfield, so sometimes you need to work with a legacy database schema. ActiveRecord is a great choice when you have a full control over your database from the very beginning, but what should you do if you need to connect to a database with a schema that isn’t in-line with Rails conventions? In this post I will explain how to setup a Rails application that uses DataMapper as the ORM. I'll also guide you through configuring your models to work with a legacy schema. If you are not familiar with DataMapper I recommend reading the “Getting Started” section of the official documentation.

A legacy schema

For the sake of this post let’s use an example schema of a blog application using MySQL:
CREATE TABLE `post` (
 `postId` varchar(45) NOT NULL,
 `postAuthorId` int(11) DEFAULT NULL,
 `postTitle` varchar(45) DEFAULT NULL,
 `postContent` text,
 `postPublishTime` varchar(45) DEFAULT NULL,
 PRIMARY KEY (`postId`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;     

CREATE TABLE `user` (
 `userId` int(11) NOT NULL AUTO_INCREMENT,
 `userName` varchar(45) DEFAULT NULL,
 `userEmail` varchar(45) DEFAULT NULL,
 PRIMARY KEY (`userId`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Here’s what’s “wrong” with it:
  • table names are singularized
  • column names use camel-case naming convention prefixed with a table name
  • post primary key is an md5 sum of concatenated values of “author” and “publishTime”
  • post => user foreign key has a custom name “author”
  • “postPublishTime” is stored as a string and we would like to use DateTime object

Creating a rails application with DataMapper as ORM

This is actually a straight-forward task. All you need to do is to use a template provided by DataMapper when generating an application skeleton as follows: rails new blog-legacy -m http://datamapper.org/templates/rails.rb By default the skeleton uses sqlite as the database. To change that, simply edit Gemfile and change ‘dm-sqlite-adapter’ to ‘dm-mysql-adapter’ and run bundle install. To generate empty models run:
script/rails g model user
script/rails g model post

Naming conventions

DataMapper gives you two ways of defining table and column names. You can either set it manually in every model or you can configure global naming conventions for all models. Here’s how to set table and field names explicitly in the model:
class User
  include DataMapper::Resource
   
  storage_names[:default] = "user"     

  property :id,	Serial, :field => "userId"
  property :name,  String, :field => "userName"
  property :email, String, :field => "userEmail"
end
With many properties it would add clutter to our models, that is why it is better to set global naming conventions for resources and fields. Those conventions will be applied to every model and will eliminate the need to define storage names and set :field options for every property. To set global naming conventions, we can create datamapper.rb initializer like this:
# config/initializers/datamapper.rb   
Rails::DataMapper.configuration.resource_naming_convention[:default] = lambda do |name|
  name.downcase.singularize
end

# note: this will be available in dm-rails 1.1.1
Rails::DataMapper.configuration.field_naming_convention[:default] = lambda do |property|
  "#{property.model.name.downcase}#{property.name.to_s.camelize}"
end
Now we can clean up our User model like this:
class User
  include DataMapper::Resource     

  property :id,	Serial
  property :name,  String
  property :email, String
end
Much better!

Dealing with natural primary keys

In our example schema, a post’s primary key is an MD5 sum of concatenated fields “postAuthorId” and “postPublishTime”. If we want to have the value generated in Ruby we can use :default options in property declaration:
class Post
  include DataMapper::Resource     

  property :id, String, :key => true, :default => lambda { |resource, property|
	Digest::MD5.hexdigest("#{author}#{publish_time}") }     

  # ...
end
Now whenever you create a post and don’t provide :id it will be generated automatically based on the values of :author and :publish_time properties. As you can see this doesn’t look very nice in the model. So, we could create a custom property with a generalized functionality to clean this up! This way we can re-use this code in different scenarios whenever we want an MD5 sum of concatenated fields. You might be surprised how easy this is to do:
 module ::DataMapper
   class Property
     class MD5 < String
   	key	true
   	length 32     

   	accept_options :fields     

   	default lambda { |resource, property|
     	  Digest::MD5.hexdigest(property.options[:fields].join) }
     end
   end
 end
Now we can define post :id like this:
class Post
 include DataMapper::Resource     

 property :id, MD5, :fields => [ :author, :publish_time ]
end
How easy was that?!?

Associations with custom foreign keys

Our database has a basic 1:M relationship between User and Post models. The only caveat is that foreign key on post table pointing to user id has a name that doesn’t follow our global naming conventions. To configure the association we must override our defaults:
class User
  include DataMapper::Resource     

  property :id,	Serial
  property :name,  String
  property :email, String     

  # We need to set child_key otherwise DataMapper would use :user_id
  has n, :posts, :child_key => :author_id
end

class Post
  include DataMapper::Resource     

  property :id,	MD5, :fields => [ :author, :publish_time ]
  property :title,  String
  property :content, Text     

  # This creates a property called :author_id for you. We also set “User” as the parent model
  belongs_to :author, “User”
end
Easy enough.

Fine tuning - typecasting properties

Post :publish_time is a String property as values are stored in a VARCHAR column. Our goal is to work with DateTime objects, not strings. To achieve that we could simply override property accessor and do typecasting like this:
class Post
  # …     

  def publish_time
    DateTime.parse(super)
  end
end
While this approach works, it is not a recommended approach. DataMapper is based on the concept that a model’s logic should be decoupled from the database schema. A much better and cleaner way is to abstract away that logic in to a custom property object. An extra benefit comes with that too - you can re-use that code in many applications as it’s not tied to a specific model. Here’s another approach:
module DataMapper
  class Property
    class DateTimeString < String
      def load(value)
        ::DateTime.parse(value)
      end     

      def dump(value)
        value.to_s
      end
    end
  end
end
Better?

Wrap-up

All right! We’ve got all we need to work with our legacy schema. Let’s take a look at the final version of the models:
class User
  include DataMapper::Resource     

  property :id,            Serial
  property :name,  String
  property :email, String     

  has n, :posts, :child_key => :author_id
end     

class Post
  include DataMapper::Resource     

  property :id, MD5, :fields => [ :author, :publish_time ]  

  property :publish_time, DateTimeString
  property :title,    	 String
  property :content,  Text     

  belongs_to :author, "User"
end
At first sight it is hard to tell that the underlying database has a funky schema, isn’t it? These models look almost as if you were starting a fresh project. Let’s take a look at how we could work with them:
user = User.create(:name => "John Doe", :email => "john.doe@example.com")
=> #<User @id=2 @name="John Doe" @email="john.doe@example.com">
This creates a following insert statement:
INSERT INTO `user` (`userName`, `userEmail`) VALUES ('John Doe', 'john.doe@example.com')
Let’s create some posts too:
user.posts.create(:title => "Hello World!", :content => "DataMapper is awesome :)", :publish_time => DateTime.now)
=>  #<Post @id="4a585935e1d2dd21da146f6d3bcfc41b"  @publish_time="2011-05-12T13:39:04+02:00" @title="Hello World!"  @content="DataMapper is awesome :)" @author_id=2>
And SQL:
INSERT  INTO `post` (`postId`, `postPublishTime`, `postTitle`, `postContent`,  `postAuthorId`) VALUES ('4a585935e1d2dd21da146f6d3bcfc41b',  '2011-05-12T13:39:04+02:00', 'Hello World!', 'DataMapper is awesome :)',  2)

Further reading and resources

This post explains basics as well as some more advanced things you can do with DataMapper. If you would like to learn more, please take a look at the documentation, subscribe to the Mailing List or jump into the #datamapper IRC channel. Other useful links:
Author Bio Piotr Solnica is a team member at Code Benders, an agile software collective based in Bend, Oregon. When Piotr’s not writing great code, he’s writing awesome code. He has been working as a web developer for 6+ years and has solid experience with Ruby-based technologies and frameworks. His proficiencies include a range of JavaScript libraries such as Prototype, jQuery, YUI and MooTools. Piotr is an unobtrusive JavaScript evangelist, an HTML/CSS purist and a linux geek. In his free time he supports OSS, is a DataMapper core contributor, an author of DataMapper plugins and adapters and one of the developers of rubytime.org and coderack.org.


more »

Rails and Merb Merge: ORM Agnosticism (Part 5 of 6) »

Created at: 23.02.2010 20:15, source: Engine Yard Blog, tagged: Technology ActionPack ActiveModel activerecord api datamapper haml Rails 3 Railties

It’s been a little while since I’ve last posted in this series. During that time, we released Rails 3.0 beta, and announced the launch of RailsPlugins.org. Plugin authors have registered almost 150 plugins, with 40 already boasting compatibility with Rails 3. Over the next few weeks, we’re going to roll out some more features to help users find projects to help get updated, so keep an eye out.

Today I’m going to talk about the features we added to Rails 3 to provide ORM agnosticism. When we first started, the idea of such agnosticism was pretty fuzzy. As we approached the beta, we became convinced that we would shoot for the moon and give DataMapper, Sequel and other ORMs first-class access to all of the same parts of the framework that ActiveRecord had. Again, this sounds pretty fuzzy, so let me lay it out for you.

ActiveRecord is a Framework Extension

You read that right. While Rails itself ships with ActiveRecord as a default, the Railties gem, responsible for bootstrapping Rails, knows nothing about ActiveRecord. In order to achieve this, we had to make that bootstrapping process much more pluggable. While this is amazing for extensions, like DataMapper, that want to replace a built-in framework, it also exposes more functionality to any Rails extension distributed as a gem.

Rails::Railtie

In short, Railties now coordinates the initialization process, which involves the activation of a number of individual Railtie subclasses. Cute, no? Every Rails framework has its own Railtie subclass, which provides a number of useful pieces of functionality:

  • The ability to add a key (like config.active_record) to an Application’s configuration, and assign it defaults that will exist before Application configuration. For instance, a plugin could use this functionality to set a configuration key as an Array, so the Application could simply do config.action_view.view_paths << "my_path". While this isn’t exactly earth-shattering, it levels the playing field between Rails components, like ActiveRecord, and third-party extensions, like DataMapper or Haml
  • The ability to create additional generators that hook into Rails’ default generators. For instance, Rails’ scaffold generator invokes sub-generators for stylesheets, template engine, test framework, helpers, and ORM. For instance, when a user installs Haml as a gem, it can register itself as the handler for template engine generators, and provide replacements for each case where Rails provides a default implementation. In this case, Haml would replace the template engine generators provide by ActionController’s Railtie
  • The ability to supply Rake tasks to load when the user invokes the Rake command. If DataMapper supplies the same named Rake tasks as those supplied by the ActiveRecord Railtie, the user can completely remove ActiveRecord and replace it with DataMapper, retaining all of the named Rake tasks. This would allow other tasks, such as those used in testing, to automatically prepare the database and other tasks it performs by invoking tasks with certain names (like db:create)
  • Supply a log subscriber to integrate seamlessly with the uniform request logging. This allows extensions like DataMapper to add their timings into the log output. In this case, DataMapper simply replaces the “Model” timing that ActiveRecord provides, allowing a level of very tight integration with the rest of the framework
  • Specify initializers that should run at specific points in the initialization process. This allows extensions to set things up very early in the boot process, but then defer some setup until after the user has configured their application, or after specific parts of the initialization process have occurred. Each initializer also receives an instance of the Application object, giving it full access to the user’s configuration

In fact, if you take a look at ActiveRecord’s deep integration with the rest of the framework (which is roughly equivalent to its highly coupled implementation in Rails 2.3), you’ll find that it looks extremely similar to DataMapper’s equally deep integration. In fact, a major goal of the work we put into improving modularity in Rails 3 was to maintain the same level of stack integration we’ve historically had, while exposing the same toolchain for those who wanted to replace only certain elements of the stack.

The ActiveModel API

Giving DataMapper access to the same level of integration with Railties as ActiveRecord is one of two major pillars in making Rails truly ORM agnostic. The second part is decoupling Rails’ historic connection between ActiveRecord, its ORM, and ActionPack, its controller and view layer. In this area, Rails takes a holistic, very conventional approach to linking the model and the view using REST principles.

In particular, domain objects, persisted via the ORM, can have canonical URLs that are used pervasively throughout the controller and view layer. The specific URLs can be configured via the router, and Rails 3’s router is particularly powerful, but once configured, objects do have canonical URLs.

@post = Post.first
 
redirect_to @post           #=> Location: /posts/orm-agnositicism
redirect_to Post            #=> Location: /posts
 
form_for @post              #=> <form action="/posts/orm-agnosticism" method="PUT">
form_for Post.new           #=>
 
error_messages_for @post    #=> a representation of the validation errors that exist on the object
 
link_to @post.title, @post  #=> <a href="/posts/orm-agnosticism">
                            #     Rails and Merb Merge: ORM Agnosticism (Part 5 of 6)
                            #   </a>
 
posts_path                  #=> "/posts"
post_path(@post)            #=> "/posts/orm-agnosticism"
 
@posts = Post.where(:author => "wycats")
 
render @post                #=> renders "_post.html.erb", passing in @post as a local
render @posts               #=> renders a collection of "_post.html.erb", passing in each
                            #   Post instance as a local in turn
 
respond_with @post          #=> performs content negotiation between the formats
                            #   the client is willing to Accept (xml, json, html),
                            #   and the formats the @post object is willing to
                            #   provide. The available providable formats are
                            #   transparently determined by introspecting the @post
                            #   object. Additionally, if the object has not been persisted,
                            #   redirect it back to the editing page for further modification.
                            #   If it has been persisted, redirect it back to the index (or
                            #   some other appropriate path).</form>

In short, Rails 2.3 provided a fair bit of integrated functionality between ActiveRecord and ActionPack. For instance, to determine what an object’s canonical URL was, Rails called an internal .class.naming method on it, which provided the information needed to form the canonical URLs. And while other ORMs could attempt to emulate these internals, there was no guarantee that they’d be used in the same way from release to release (and, in fact, they evolved quite a bit, making them a moving target at best).

In Rails 3, we opened them up, exposing an explicit public API via ActiveModel. The ActiveModel API requires that objects respond to to_model, returning an Object that complies with the larger ActiveModel API. This allows objects that already implement methods with the same names as those required by the API to create a facade that presents itself to ActionPack as a fully compliant model.

The API itself is fairly small, with a few methods around validation, the ability to determine whether an object has persisted or not (which can be safely stubbed by objects without persistence), and a number of methods that tell ActionPack how to convert the object into a canonical URL or template name. By doing this, Rails has completely decoupled ActionPack from ActiveRecord directly, and ActiveRecord becomes just one of many ORMs to implement the ActiveModel API.

The DataMapper ORM has already released a Rails extension (called dm-rails) that implements both the Railtie functionality and ActiveModel, making it a full drop-in replacement for ActiveRecord. The Sequel ORM is also hard at work on their Railtie and ActiveModel adapter.

The really great thing about all of this is that we didn’t need to sacrifice one bit of the (some have said overly) tight integration between various parts of Rails, to provide the ability to swap in entirely different components with the same apparent “coupling” that the Rails frameworks have with each other.

As always, questions and comments are welcome!


more »

Let Them Code Cake! »

Created at: 09.02.2010 20:00, source: Engine Yard Blog, tagged: Technology activerecord cake datamapper refactoring

In TDD and BDD we write small, focused, technical tests, sometimes called micro-tests. One of the core ideas is that these tests should run fast, really fast—each one measured in milliseconds. If you’re writing plain Ruby code, that’s pretty easy to accomplish. However, when you’re using something like Rails or Merb and DataMapper or ActiveRecord, it can get a bit more challenging.

Why do we end up with model tests/specs that run slowly? In looking at how we write and test our code, let’s ignore controllers and views, and focus on models. After all, models are where you put your business logic.

There can be several reasons for a slow test suite: database access, unnecessary objects, a massive setup that takes a while to load—just to name a few. This time though, I want us to focus on a new reason, one that’s a result of operating in the context of ActiveRecord or DataMapper. One that tricks us into thinking we’re doing well. One that exposes a few somewhat major flaws in the design of AR and DM.

With ActiveRecord and DataMapper, each model class is responsible for its own persistence, hence DHH using the name “Active Record.” It was inspired by Fowler’s writing on the pattern in Patterns of Enterprise Application Architecture and is the enabler of our model addiction.

OverActive Record

Used properly, the active record pattern is great for persisting data. These objects are great at handling their own persistence. Accessors, associations, and validation make a good wrapper around the transactional nature of a database. This is fine when the model is a simple data object, but we all run into problems when we start adding other behavior to the model class.

Weighted Companion CakeWeighted Companion Cake: The cube was the cake!

(Compliments to flickr user Mandrake88)

Recall the Single Responsibility Principle: “There should never be more than one reason for a class to change.” As we commonly use them, ActiveRecord and DataMapper1 classes almost always violate this principle. There are usually at least two responsibilities handled by every AR/DM model: persistence and business logic. Carrying around that persistence behavior, and all the dependencies that go along with it, is what bloats and slows down our specs.

There have been various attempts at dealing with this: in memory databases, stubbing parts of the DM/AR frameworks, etc. None of these are ideal. Either they don’t speed things up as much as we’d like, they’re awkward, or they bulk up the specs an objectionable amount.

Is There a Better Way? Why, Yes! Yes There Is.

DM/AR lets you define a model’s properties, its persistent parts, and generates the associated accessors and mutators. All access to the persistent properties is handled through these accessors and mutators. This gives us a perfect seam along which to split the class. All of the persistence-dependent functionality is on one side of this seam, and the business logic of the model is on the other.

Dragon CakeWe need a good saving throw against this frosting.

Courtesy of Mike’s Amazing Cakes

Pretend… It’s a Cake.

Yes, you read that correctly. Keep on reading—it makes sense!

Each of our models is like a frosted cake. We have the nice fluffy cake batter, baked with our properties, validations, and persistence. Then we frost the outside with our business logic. We can take a simple ActiveRecord cake and make it into almost anything, with a good amount of frosting.

Now herein lies the problem: the frosting starts to take on a life of its own. Before we know it we’re baking a few 100 ActiveRecord cakes each time we need to test the frosting behavior… There are two really good ways to get around this: cupcakes and cardboard.

Strategy 1: Oh Look! Cupcakes!

When we build a web application with ActiveRecord or DataMapper, it’s really hard to think outside the persistence box. If something is persisted on that model, or if it uses something on that model, we automatically add the code to the model. This leads quickly to a gigantic cake that does everything.

This is especially bad with primary models like User. The poor bloated User gets tons of code stuffed into it because our app is usually focused around users. Users do things in our app. Users get affected by things. They control the app and most things belong to the user in some way. But this doesn’t mean our User class should be 1000 lines.

This cake does too much.This cake does too much (yes that’s cake)

The solution is to break out chunks of code into their own classes. There are many common patterns that we can find in our classes: Factory, Provider, Policy, Strategy, and plenty of types that are custom to each domain (Cake Decorator?). Let’s lump these all into something that we’ll call Cupcake Classes.

At Engine Yard, one of the places we found an opportunity for a Cupcake was our Deployment initialize. The method had to do a lot of data mutating before it could create an instance. Blank strings needed to become nil, string representations of a type needed to be converted to the actual type, and defaults needed to be applied to fill out the incoming data. The initialize method was a ridiculous 50 lines long. This needed to become its own class.

The result is a really clean initialize:

  def initialize(params={})
    merger = Deployment::DefaultsMerger.new(params)
    merger.each_attribute { |att, val| send("#{att}=", val) }
  end

…and a class that knows all about how to merge incoming params and defaults. It has a clear API, and it’s easily testable. We know what comes in and what comes out and we don’t have to create a database record every time we test it.

class Deployment
  class DefaultsMerger

    def initialize(params)
      @attributes = merge_with_defaults(params)
      scrub_blank 0, :data_volume_size, :app_server_count
      scrub_blank nil, :db_volume_id, :data_volume_id
      coerce_value(:instance_size, :db_instance_size) do |val|
        Instance::Size.coerce(val)
      end
      # ...
    end

    def each_attribute
      @attributes.each do |k,v|
        yield k, safe_to_i(v)
      end
    end

  private

    def defaults
      Mash.new({
        :data_volume_size => Volume::DEFAULT_SIZE,
        :app_server_count => 1,
        # ...
      })
    end
    # ...
  end
end

Cupcake Cake of the Hungry Hungry Caterpillar

A maintainable and testable model should be a collection of cupcakes. (This model is a bit buggy)

- Thanks to Coco Cake for this one.

Cupcake Coding Rule of Thumb: Messy Code Makes for Good Cupcakes!

When you want to clean up your models, look for messy code. Long methods or sets of utility methods (methods that barely, if at all, touch instance state) are just begging to be cut up into smaller classes.

What tipped us off was that the initialize method was long, nasty, and really had nothing to do with the class it was in. Mostly, it dealt with params, a hash. Almost every line in the old method did hash operations, not operations dealing with the actual model.

We clearly needed a class that would know how to work with merging our defaults into an incoming hash. The resulting class would also improve our real test coverage. It’s much easier to test a bunch of branches when they don’t have to pass through the model life cycle.

describe Deployment::DefaultsMerger do
  describe_attribute :data_volume_size do
    it_defaults_to Volume::DEFAULT_SIZE
    it_converts ["", nil, 0, "0"], :to => 0
    it_converts [123, "123"],      :to => 123
  end

  describe_attribute :app_server_count do
    it_defaults_to 1
    it_converts ["", nil, 0, "0"], :to => 0
    it_converts [2, "2"],          :to => 2
  end
  # ...
end

With a focused class, it’s easy to write focused specs. With a few custom methods in your specs, you have beautifully concise descriptions of behavior to match your simple code.

Cardboard CakeLooks yummy!

Thanks to flickr user hazellterry

Strategy 2: Cardboard Cake

The next way to improve your models and your testing is to extract the model’s behavior from the persistence. The idea is to test the frosting without having to bake a cake every time. Our example class after the behavior has been extracted:

class Oven
  include DataMapper::Resource
  include Oven::Behavior

  ## Properties

  property :id,           Serial
  property :oven_type,    String
  property :temp_setting, String

  has 1, :heating_element
  has 1, :latch
  ## ...

end

Here’s the frosting, or behavior, that has been extracted from it:

class Oven
  module Behavior

    def check_lock
      latch.engage! if dangerous_temperature?
    end

    def dangerous_temperature?
      Oven::Temperatures.dangerous? temp_setting
    end

    def turn_on(temp = 350) # ...
    def turn_off # ...
    def preheating? # ...
  end
end

Once this is done, you can write specs that focus on the logic in isolation. Instead of testing every aspect of behavior on top of the persistence framework (slow), you can isolate the behavior (fast). Sort of like making the cake out of cardboard so you can test our frosting without the baking time (See? Told you it would make sense!).

How Do We Achieve This Isolation? Mock Object Trickery, But of Course!

Let’s create a mock to stand in for the model object being tested. Let’s call these Cake Mocks. Then, we’ll extend the mock object with with the Behavior we’re testing.

  @oven = mock("Oven").extend(Oven::Behavior)

It still acts like an oven, but instead we’ve frosted the outside of a cardboard cake with the same business logic that we would add to a real ActiveRecord object. The trick is to have the mock object extend the module that contains the business logic. The result is an object containing the behavior of the model but not its persistence.

Now we can stub accessors on the mock (but only those involved in the example) and set expectations on the mutators. Then the example can call methods on the mock oven as if it was a real Oven instance. Those calls invoke the actual business logic methods that we want to test. When those methods access the internal behavior of our persistence layer, our mock answers with the methods we stubbed. The mock merely fills in the center of the cake.

describe Oven::Behavior do
  describe "preheating" do
    before(:each) do
      @latch = mock("latch")
      @oven = mock("Oven", :latch => @latch).extend(Oven::Behavior)
    end

    it "isn't locked when temperature setting is less than 500" do
      @oven.stub!(:temp_setting).and_return(350)
      @latch.should_receive(:engage!).never
      @oven.check_lock
    end

    it "isn't locked when temperature setting is 500" do
      @oven.stub!(:temp_setting).and_return(500)
      @latch.should_receive(:engage!).never
      @oven.check_lock
    end

    it "is locked when temperature setting is greater than 500" do
      @oven.stub!(:temp_setting).and_return(505)
      @latch.should_receive(:engage!).once
      @oven.check_lock
    end
  end
end

This cake mock style encourages another good testing practice: integration testing. When the model is completely mixed up with behavior, the need for integration testing is easier to ignore, but no less important. With separated behavior and persistence we can write simple integration tests that make sure the seam between the cake and the frosting is still intact.

Give Your Models Some Attention

When looking at models this way, whether you’re breaking them up in to cupcakes or separating the frosting, it’s easier to see the difference between behavior and persistence. If the logic can stand on its own, make a new class. If it’s more like an extension of the model, make a module and mix it back in. Allow ActiveRecord and DataMapper models to take care of what they do best without all the extra weight.

Take a few minutes and look at the models in your project. If the classes weren’t backed by the database, would you still have all that stuff jammed into one place? Are your models more complex than they need to be? If so… do something about it!


[1] DataMapper may be named after Fowler’s DataMapper pattern, but that’s where the similarity ends. “DataMapper” is little more than a variation of ActiveRecord. The objects are responsible for their own persistence, while the DataMapper pattern uses a separate object (the mapper) that manages persistence: “A layer of Mappers (473) that moves data between objects and a database while keeping them independent of each other and the mapper itself.”


more »

Engine Yard hiring developers to help build our cloud »

Created at: 07.04.2009 23:19, source: Brainspl.at, tagged: cloud deployment automation chef merb datamapper nanite aws

I’m looking for a few good folks to join my team. You need to be able to work on site in San Francisco, we can assist with moving expenses for the right candidate.

You would work with my team(currently 5 devs). We do no bs agile style development with pairing where appropriate and test infected mentality . generally we have a fun, tight team and get to work on some of the hardest and most rewarding areas of software development relevant today.

You would be on my team working on http://engineyard.com/solo and it’s successors as well as Engine Yard’s on premises infrastructure.

You would be working on/with the following ruby technologies:

Ruby
Merb
Rails
Sinatra
DataMapper
Nanite
Chef
Event Machine
Many others..

You would be working on the following problem domains:

Scalable Ruby Deployment Architectures
Scalable Cloud Computing Architectures
Scalable Database Architecture
Distributed Computing
Key Value Data Stores
Infrastructure automation
Cloud provider API's
Multi-Cloud portability
Monitoring and alerting systems
Security in the Cloud
Horizontally Scalable Architectures
Many other interesting areas of computing

Familiarity with the following tech is nice but not necessarily required if you can learn fast:

Gentoo Linux
Nginx
Apache
Monit
Daemontools
Mysql
Postgresql
Memcached
Passenger
Mongrel
Thin
SSL Certs
Iptables/Networking
Erlang

If you think you have the “right stuff” and you have the kick ass take names attitude then send a resume with a short intro about who you are and why you are the person we should hire.

ez@engineyard.com


more »

db fixtures replacement solution step by step »

Created at: 07.09.2008 19:06, source: Rails on the Run - Home, tagged: datamapper factory_girl fixtures merb rspec rspec spec testing

Like most people who started with Rails a while back, I first loved Rails fixtures and ended up hating them (slow, a pain to maintain etc...).

I went through different experiments, trying different existing libs, writing my own solutions etc... I wasn't quite satisfied until I found factory_girl from thoughtbot.

You might not feel the need for a decent fixtures solution if you do a lot of mocking/stubbing, but I recently came back from my "mock everything you can outside of models" approach and I'm getting closer to the mock roles, not objects approach. So, I'm loosing my model/controller testing separation but I'm gaining by not having to maintain "dumb mocks" which don't always represent the real API behind. I mean, how many times did I change a Model, messing up my app but all my specs were still passing. Anyway, that's a long discussion, which will be covered by wycats during merbcamp

So here is a simple example of how I use factory girl in a Merb + DataMapper app. (you can do the same in a Rails app, there is nothing specific to Merb in factory_girl).

  • I. create an empty app, set the ORM etc...

  • II. git pull and install factorygirl from http://github.com/thoughtbot/factorygirl/tree/master. Or install thoughtbot-factory_girl gem using GitHub gem server.

  • III. create a spec/factories.rb file. (You might prefer to create a folder called spec/factories and add a factory per model)

  • IV. modify spec_helper.rb and add the following

1
2
3

  require 'factory_girl'
  require File.dirname(__FILE__) + '/factories'
  • V. write some specs against a Client model
  • VI. Create the Model
  • VII. create a factory
  • IIX. run your specs

    failing specs

  • IX. fix the model (note that I set dependencies "dm-validations" in my init.rb)

  • X. run the specs

    passing specs

  • XI. add more specs

As you can see, Factory.build(:client) only creates a new instance of the Object, while Factory(:client) creates, saves and loads the instance.

  • XII. get them to pass

Factory Girl makes fixtures simple and clean. Here is another example for creating associations:

Factory Girl also supports sequencing, check out FG read me

In conclusion, Factory Girl is a mature and solid factory solution which will take you less than 15 minutes to get used to. It will offer you loads of flexibility and less frustration than good old yaml fixtures. You can also use it with existing fixtures if you want to start using it in an existing app.


more »