I have just released my first gem!
It tries to leverage the pain in the ass that is model localization. It's for mongoid in this case, and its a pleasure to use (supposing that it works fine, since it hasn't been tested in a real environment yet).
I won't bother you with the details, since you can see a readme or even check the kind of announcement I made in the mongoid google group.
If you apps uses mongoid and you need to localize your fields, please check it out and test as much as you can. I need feedback to fix broken stuff and add new features.
n.times { code! }
Monday, May 03, 2010
i18n gem for mongoid
Posted by
Papipo
at
1:19 am
0
comments
Labels: gem, i18n, mongodb, mongoid, programming, rails, ruby
Friday, September 25, 2009
Congo-cms, a content management framework in rails and mongodb
I've started a project in github, which is a prototype of something that I've been searching for years: a flexible content management system/framework that makes sense.
I've looked into ez publish and similar stuff, recently I've met expression engine, and I have even considered the drupal model. What all these systems have in common is one --in my opinion-- bad constraint: they store their data in a relational database.
Those CMS or CMF basically "simulate" a documental database on top of a relational one. I can't see how that can be good.
My aim with congo-cms (a name which comes from content+mongo -- yeah, I know, pretty smart name xD) is to offer a framework to define flexible datatypes, as ez publish and its companions do, but with the actual data stored in the proper way. If you create a blog using congo-cms, the blog post documents stored in mongodb, won't differ from those that you could store if the application was a plain weblog made with rails as in the old fashion.
I'm using MongoMapper mainly because it really fits my idea of using embedded datatypes. For example a User could have Addresses, and those should be stored in the User document itself. With MongoMapper this feature comes straight out of the box.
I hope to improve development a bit in the next weeks, and hopefully we will use something similar in my company's next project.
Posted by
Papipo
at
4:58 pm
0
comments
Labels: cmf, cms, documental database, mongo, mongodb, rails, ruby
Thursday, August 30, 2007
BDD, isolation, integration
I have been reading a lot of posts about skinny controllers, isolation and good behaviour-driven development. Let me explain from the beginning:
The typical approach to spec a 'create' action looks like this (Taken from rspec documentation):
describe PeopleController do
it "with a valid person should redirect to index on successful POST to create" do
@person.should_receive(:new_record?).and_return(false)
Person.should_receive(:create).with({"name" => 'Aslak'}).and_return(@person)
post 'create', {:person => {:name => 'Aslak'}}
response.should redirect_to(:action => 'index')
end
end
That is too tied to the implementation. What if I want to use the 'create' method in my controller? And what about assigning attributes in a block?
What you are spec-ing here, is how your controller should look, not how it should behave.
Then I saw this in one of the blogs that I linked above:
it "should create a new thing" do
lambda { do_post }.should change { Thing.count }.by(1)
end
This is really testing behaviour. The main problem with this (although I really liked it the first time I saw it) is, of course, that interacts with the database and the models. I don't want to hit the database from my controller specs at all, I want full isolation.
Add a pair of helpers in spec_helper.rb:
def mock_valid_model(klass)
mock_model(klass, :save => true, :save! => true)
end
def mock_invalid_model(klass)
m = mock_model(klass, :save => false)
m.stub!(:save!).and_raise(ActiveRecord::RecordNotSaved)
m
end
Then stub Model.new to return the mock you want. Spec your controller 'create' action in order to redirect in case that the mock is valid, and to render a template if it is not valid (of course you can add specs for flash or whatever):
describe ThingsController, '"create" a valid model by POST' do
before do
@thing = mock_valid_model(Thing)
Thing.stub!(:new).and_return(@thing)
end
it 'should redirect to model show' do
post :create
response.should redirect_to(thing_url(@thing))
end
end
describe ThingsController, '"create" an invalid model by POST' do
before do
@thing = mock_invalid_model(Thing)
Thing.stub!(:new).and_return(@thing)
end
it 'should render "create" template' do
post :create
response.should render_template('things/create')
end
end
There are various interesting things here:
- You don't need to keep adding expectations to your mocks. Expectations couple your specs with the implementation. With my approach you can use create, new + save, new + block assignement, whatever. And the spec still passes.
- The database isn't touched at all. That's good stuff, I guess.
- You are really testing the behaviour. You know that the only way your controller will know if it should redirect or render, is to create a new instance of Thing, and call save or save!. That is actually an implied expectation, but without the need of should_receive(), just stubs.
The only moment that you want your controller mess with params, is when you are not isolating. Because, if you are isolating, you can't validate parameters, since you stubbed save and save!.
With this approach, you keep your specs to a minimum amount of lines, you isolate, you test just behaviour.
Anyway, let me know of any issues you find with this.
Thanks for reading and sorry about the syntax non-highlighting.
