Rspec Your Presenters.

It took me an hour to find what I was looking for, so it might help someone. Whenever you inject the view in an object, for example when you create presenters, writing your spec can be quite tricky as a simple stub of the view is rapidly limited.

To make the situation easier with RSpec, you can give a look to two useful modules

1
2
  Rspec::Rails::RailsExampleGroup
  ActionView::TestCase::Behavior

You can now call the view method in your spec.

1
2
3
4
5
6
7
8
9
10
11
12
  describe Breadcrumb do
    include RSpec::Rails::RailsExampleGroup
    include ActionView::TestCase::Behavior

    let(:page) { stub(name: 'homepage', ...) }

    it "is beautiful" do
      b = Breadcrumb.new(view, page)
      b.should be_beautiful
    end

  end

That’s it, all green !

Deep Nesting Resources in Practice

In a classic resource oriented application/API, the nesting description is an important concern as it is a key of the simplicity of your model. Back in 2007 Jamis Buck published this good article about the question, even if the syntax is not really up to date, it is still valid on a conceptual purpose http://weblog.jamisbuck.org/2007/2/5/nesting-resources.

Basically if this kind of situation happens that you have in your model

1
2
3
class Blog
  has_many :posts
end
1
2
3
class Post
  has_many :comments
end

While describing your routes you can be tempted to take a shortcut and do this

1
2
3
4
5
resources :blogs do
  resources :posts do
      resources :comments
  end
end

In the above example rails would generate the following helper, which takes in parameter the array of ids

1
blog_post_comment_path([blog_id, post_id, comment_id])

However this is not a good solution when you want to retrieve a unique ressource like one comment, it would be good to avoid refering ids of the blog and post associated. A simple call to the ressource with its id should be enough.

GET /comments/3

There is still some actions in the CRUD requiring the nesting, the creation of a comment for example, if we want to associate a new comment to a specific blog, we can just post a form containing its attribute to the following URI

POST /blogs/2/comments

The rule in general is this “The maximum level of nesting is 1 only if you don’t already have the id of your ressource.”

Following this, a good routing description for our hierarchy would be.

1
2
3
4
5
6
7
resources :blogs do
  resources :posts, :only => [:new, :create]
end
resources :posts, :except => [:new, :create] do
  resources :comments, :only => [:new, :create]
end
resources :comments, :except =>  [:new, :create]

Giving the following simple and explicit routes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
albandiguer@iceberg ~/tmp/nesting $ rake routes                                                                                   [ruby-1.9.3-p194]
      blog_posts POST   /blogs/:blog_id/posts(.:format)        posts#create
   new_blog_post GET    /blogs/:blog_id/posts/new(.:format)    posts#new
           blogs GET    /blogs(.:format)                       blogs#index
                 POST   /blogs(.:format)                       blogs#create
        new_blog GET    /blogs/new(.:format)                   blogs#new
       edit_blog GET    /blogs/:id/edit(.:format)              blogs#edit
            blog GET    /blogs/:id(.:format)                   blogs#show
                 PUT    /blogs/:id(.:format)                   blogs#update
                 DELETE /blogs/:id(.:format)                   blogs#destroy
   post_comments POST   /posts/:post_id/comments(.:format)     comments#create
new_post_comment GET    /posts/:post_id/comments/new(.:format) comments#new
           posts GET    /posts(.:format)                       posts#index
       edit_post GET    /posts/:id/edit(.:format)              posts#edit
            post GET    /posts/:id(.:format)                   posts#show
                 PUT    /posts/:id(.:format)                   posts#update
                 DELETE /posts/:id(.:format)                   posts#destroy
        comments GET    /comments(.:format)                    comments#index
    edit_comment GET    /comments/:id/edit(.:format)           comments#edit
         comment GET    /comments/:id(.:format)                comments#show
                 PUT    /comments/:id(.:format)                comments#update
                 DELETE /comments/:id(.:format)                comments#destroy