Question

I'm having trouble understanding how to implement the Presenter pattern alongside MVC using Sinatra.

I've read lots of posts and none really are focused on the specific use cases i'm interested in.

Just to be clear I'm already using the MVC pattern as defined in "Sinatra Up and Running" (see: https://github.com/Integralist/sinatra-mvc/ -> my code has changed since I originally created this repo but it'll give you an idea of the MVC structure I'm using).

what I'm trying to achieve...

My understanding of the Presenter is to collate Model data and then pass it through to a View. Then pass that back to the Controller who then renders the View.

The reason I want to use the Presenter pattern is to not only keep the Controllers clean but to also be able to compose a page made up of 'components' (chunks of HTML) so I can reuse some components on different pages.

how to implement?

But I'm not sure how to implement this. Can some one please show me an example of how I could do this (pseudo-code is fine if writing a real example would be a lot of work)?

Here's some example code of how I envision it could look but I'm not sure if what I'm thinking would be correct or of how the implementation would work (I've tried different things but hit issues with my lack of understanding of how Sinatra works under the covers)...

class ContactController < ApplicationController
    get '/' do
        @component_a = require './presenter/a'
        @component_b = require './presenter/b'
        erb :contact
    end
end

...I assume I'd still need some basic logic in my View to determine where about in the page to load the component, like...

<%
    if @component_a
        erb :"#{@component_a}"
    end
%>

So this makes me think that loading a presenter should maybe return something that allows that to happen.

Any suggestions on how to do this better is also very welcome.

Thanks!

Was it helpful?

Solution 2

I managed to get this working. See my repository of code here: https://github.com/Integralist/MVCP

OTHER TIPS

I don't really know about the Presenter pattern (knowingly:) only what I occasionally read when I feel I don't have enough patterns to hold in my head… but here are some options I know of for composing a page from parts:

Sinatra Partial

You may want to have a look at Sinatra Partial (disclosure: I'm the maintainer), as it makes it very easy to put views within views or into variables in the route, e.g.

require "sinatra/partial"
class ContactController < ApplicationController
  register Sinatra::Partial

  set :partial_template_engine, :erb

  get '/' do
    # do some stuff here, fill some models etc
    # then…
    # will render the template in views/presenter/a.erb
    @component_a = partial :"presenter/a"
    # will render the views/presenter/b.erb
    @component_b = partial :"presenter/b"
    erb :contact
  end
end

although I'd probably just put those calls to partial in the view:

# contact.erb
<%= partial :"presenter/a" if @mymodel.is_full %>
<%= partial :"presenter/b" %>

with whatever logic you wanted.

Mustache

Mustache is worth a look, I don't use it with Ruby or Sinatra, but it appears to be a ready made Presenter pattern. It even has Sinatra integration and examples.

Sinatra::ContentFor

https://rubygems.org/gems/sinatra-contrib

I've never used it, I just know it exists and does something similar to Sinatra Partial.

This is a good (even though it's for Rails and from 2007) article on using Forwardable to build the Presenter. Then you could pass it on to the contact.erb template as just one object, but you'd still need to put some logic in the template or the presenter to deal with which fields were present.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top