ruby-on-railsinitializationpresenter

initialize method for an index action presenter


I want to make a presenter for an index action for Event.

here is what it looks like. there will be more methods and things added to the presenter and the view, but right now I just want to get this working:

class EventPresenter

  def initialize(events, template)
    @events = events
    @template = template
  end

  def h
    @template
  end

  def event_title
    h.link_to event.name, event_path(event)
  end
end

index.html.erb:

<% present @events do |event_presenter| %> <tr>
    <td><%= event_presenter.event_title %></td>
<% end %>

application helper:

module ApplicationHelper
  def present(object, klass = nil)
    klass ||= "#{object.class}Presenter".constantize
    presenter = klass.new(object, self)
    yield presenter if block_given?
    presenter
  end
end

events_controller:

  def index
    @events = Event.all.map{ |event| EventPresenter.new(event) }
   # render json: @events
  end

the way it is now, I'm getting the wrong number of arguments (1 for 2) error for the presenter's initialize method. I was trying to see which of the two objects is not getting passed into the initializer by removing either @events or @template, such as:

  def initialize(template)
    @template = template
  end

but, in both cases the app breaks at the klass ||= line of the application_helper with uninitialized constant ArrayPresenter, while it's supposed to be looking for the EventPresenter constant.

Full trace:

activesupport (5.0.0.beta3) lib/active_support/inflector/methods.rb:259:in `const_get'
activesupport (5.0.0.beta3) lib/active_support/inflector/methods.rb:259:in `block in constantize'
activesupport (5.0.0.beta3) lib/active_support/inflector/methods.rb:257:in `each'
activesupport (5.0.0.beta3) lib/active_support/inflector/methods.rb:257:in `inject'
activesupport (5.0.0.beta3) lib/active_support/inflector/methods.rb:257:in `constantize'
activesupport (5.0.0.beta3) lib/active_support/core_ext/string/inflections.rb:66:in `constantize'
app/helpers/application_helper.rb:3:in `present'
app/views/events/index.html.erb:1:in `_app_views_events_index_html_erb__1682590753278671208_70298040094320'
actionview (5.0.0.beta3) lib/action_view/template.rb:158:in `block in render'
activesupport (5.0.0.beta3) lib/active_support/notifications.rb:166:in `instrument'
actionview (5.0.0.beta3) lib/action_view/template.rb:348:in `instrument'
actionview (5.0.0.beta3) lib/action_view/template.rb:156:in `render'
actionview (5.0.0.beta3) lib/action_view/renderer/template_renderer.rb:54:in `block (2 levels) in render_template'
actionview (5.0.0.beta3) lib/action_view/renderer/abstract_renderer.rb:42:in `block in instrument'
activesupport (5.0.0.beta3) lib/active_support/notifications.rb:164:in `block in instrument'
activesupport (5.0.0.beta3) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (5.0.0.beta3) lib/active_support/notifications.rb:164:in `instrument'
actionview (5.0.0.beta3) lib/action_view/renderer/abstract_renderer.rb:41:in `instrument'
actionview (5.0.0.beta3) lib/action_view/renderer/template_renderer.rb:53:in `block in render_template'
actionview (5.0.0.beta3) lib/action_view/renderer/template_renderer.rb:61:in `render_with_layout'
actionview (5.0.0.beta3) lib/action_view/renderer/template_renderer.rb:52:in `render_template'
actionview (5.0.0.beta3) lib/action_view/renderer/template_renderer.rb:14:in `render'
actionview (5.0.0.beta3) lib/action_view/renderer/renderer.rb:42:in `render_template'
actionview (5.0.0.beta3) lib/action_view/renderer/renderer.rb:23:in `render'
actionview (5.0.0.beta3) lib/action_view/rendering.rb:103:in `_render_template'
actionpack (5.0.0.beta3) lib/action_controller/metal/streaming.rb:217:in `_render_template'
actionview (5.0.0.beta3) lib/action_view/rendering.rb:83:in `render_to_body'
actionpack (5.0.0.beta3) lib/action_controller/metal/rendering.rb:52:in `render_to_body'
actionpack (5.0.0.beta3) lib/action_controller/metal/renderers.rb:144:in `render_to_body'
actionpack (5.0.0.beta3) lib/abstract_controller/rendering.rb:25:in `render'
actionpack (5.0.0.beta3) lib/action_controller/metal/rendering.rb:36:in `render'
actionpack (5.0.0.beta3) lib/action_controller/metal/instrumentation.rb:43:in `block (2 levels) in render'
activesupport (5.0.0.beta3) lib/active_support/core_ext/benchmark.rb:12:in `block in ms'
/usr/local/Cellar/ruby/2.2.3/lib/ruby/2.2.0/benchmark.rb:303:in `realtime'
activesupport (5.0.0.beta3) lib/active_support/core_ext/benchmark.rb:12:in `ms'
actionpack (5.0.0.beta3) lib/action_controller/metal/instrumentation.rb:43:in `block in render'
actionpack (5.0.0.beta3) lib/action_controller/metal/instrumentation.rb:86:in `cleanup_view_runtime'
activerecord (5.0.0.beta3) lib/active_record/railties/controller_runtime.rb:25:in `cleanup_view_runtime'
actionpack (5.0.0.beta3) lib/action_controller/metal/instrumentation.rb:42:in `render'
actionpack (5.0.0.beta3) lib/action_controller/metal/implicit_render.rb:19:in `default_render'
actionpack (5.0.0.beta3) lib/action_controller/metal/basic_implicit_render.rb:4:in `block in send_action'
actionpack (5.0.0.beta3) lib/action_controller/metal/basic_implicit_render.rb:4:in `tap'
actionpack (5.0.0.beta3) lib/action_controller/metal/basic_implicit_render.rb:4:in `send_action'
actionpack (5.0.0.beta3) lib/abstract_controller/base.rb:183:in `process_action'
actionpack (5.0.0.beta3) lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack (5.0.0.beta3) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:126:in `call'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:126:in `call'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:506:in `block (2 levels) in compile'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:455:in `call'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:455:in `call'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:101:in `__run_callbacks__'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:750:in `_run_process_action_callbacks'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:90:in `run_callbacks'
actionpack (5.0.0.beta3) lib/abstract_controller/callbacks.rb:19:in `process_action'
actionpack (5.0.0.beta3) lib/action_controller/metal/rescue.rb:27:in `process_action'
actionpack (5.0.0.beta3) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
activesupport (5.0.0.beta3) lib/active_support/notifications.rb:164:in `block in instrument'
activesupport (5.0.0.beta3) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (5.0.0.beta3) lib/active_support/notifications.rb:164:in `instrument'
actionpack (5.0.0.beta3) lib/action_controller/metal/instrumentation.rb:29:in `process_action'
actionpack (5.0.0.beta3) lib/action_controller/metal/params_wrapper.rb:248:in `process_action'
activerecord (5.0.0.beta3) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
actionpack (5.0.0.beta3) lib/abstract_controller/base.rb:128:in `process'
actionview (5.0.0.beta3) lib/action_view/rendering.rb:30:in `process'
actionpack (5.0.0.beta3) lib/action_controller/metal.rb:190:in `dispatch'
actionpack (5.0.0.beta3) lib/action_controller/metal.rb:262:in `dispatch'
actionpack (5.0.0.beta3) lib/action_dispatch/routing/route_set.rb:50:in `dispatch'
actionpack (5.0.0.beta3) lib/action_dispatch/routing/route_set.rb:32:in `serve'
actionpack (5.0.0.beta3) lib/action_dispatch/journey/router.rb:39:in `block in serve'
actionpack (5.0.0.beta3) lib/action_dispatch/journey/router.rb:26:in `each'
actionpack (5.0.0.beta3) lib/action_dispatch/journey/router.rb:26:in `serve'
actionpack (5.0.0.beta3) lib/action_dispatch/routing/route_set.rb:724:in `call'
actionview (5.0.0.beta3) lib/action_view/digestor.rb:12:in `call'
rack (2.0.0.alpha) lib/rack/etag.rb:25:in `call'
rack (2.0.0.alpha) lib/rack/conditional_get.rb:25:in `call'
rack (2.0.0.alpha) lib/rack/head.rb:12:in `call'
rack (2.0.0.alpha) lib/rack/session/abstract/id.rb:220:in `context'
rack (2.0.0.alpha) lib/rack/session/abstract/id.rb:214:in `call'
actionpack (5.0.0.beta3) lib/action_dispatch/middleware/cookies.rb:613:in `call'
activerecord (5.0.0.beta3) lib/active_record/query_cache.rb:36:in `call'
activerecord (5.0.0.beta3) lib/active_record/connection_adapters/abstract/connection_pool.rb:963:in `call'
activerecord (5.0.0.beta3) lib/active_record/migration.rb:558:in `call'
actionpack (5.0.0.beta3) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:97:in `__run_callbacks__'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:750:in `_run_call_callbacks'
activesupport (5.0.0.beta3) lib/active_support/callbacks.rb:90:in `run_callbacks'
actionpack (5.0.0.beta3) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (5.0.0.beta3) lib/action_dispatch/middleware/reloader.rb:71:in `call'
actionpack (5.0.0.beta3) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
actionpack (5.0.0.beta3) lib/action_dispatch/middleware/debug_exceptions.rb:49:in `call'
web-console (3.1.1) lib/web_console/middleware.rb:131:in `call_app'
web-console (3.1.1) lib/web_console/middleware.rb:28:in `block in call'
web-console (3.1.1) lib/web_console/middleware.rb:18:in `catch'
web-console (3.1.1) lib/web_console/middleware.rb:18:in `call'
actionpack (5.0.0.beta3) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
railties (5.0.0.beta3) lib/rails/rack/logger.rb:36:in `call_app'
railties (5.0.0.beta3) lib/rails/rack/logger.rb:24:in `block in call'
activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:70:in `block in tagged'
activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:70:in `tagged'
railties (5.0.0.beta3) lib/rails/rack/logger.rb:24:in `call'
actionpack (5.0.0.beta3) lib/action_dispatch/middleware/request_id.rb:24:in `call'
rack (2.0.0.alpha) lib/rack/method_override.rb:22:in `call'
rack (2.0.0.alpha) lib/rack/runtime.rb:22:in `call'
activesupport (5.0.0.beta3) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
actionpack (5.0.0.beta3) lib/action_dispatch/middleware/load_interlock.rb:13:in `call'
actionpack (5.0.0.beta3) lib/action_dispatch/middleware/static.rb:136:in `call'
rack (2.0.0.alpha) lib/rack/sendfile.rb:111:in `call'
railties (5.0.0.beta3) lib/rails/engine.rb:522:in `call'
puma (3.4.0) lib/puma/configuration.rb:224:in `call'
puma (3.4.0) lib/puma/server.rb:569:in `handle_request'
puma (3.4.0) lib/puma/server.rb:406:in `process_client'
puma (3.4.0) lib/puma/server.rb:271:in `block in run'
puma (3.4.0) lib/puma/thread_pool.rb:114:in `call'
puma (3.4.0) lib/puma/thread_pool.rb:114:in `block in spawn_thread'

Solution

  • You seem to wrap event objects with a presenter by calling present method in a view layer, so doing the same thing in controller looks redundant to me. Moreover, that actually was a line resulting in wrong number of arguments, as you wrapped it with a single argument only. Let's remove it:

    # events_controller
    def index
      @events = Event.all
      # we removed redundant EventPresenter.new(event) here
    end
    

    Next step is your view template. As long as @events containts an array of elements (you could check the class of object parameter in your present helper method), you get "#{object.class}Presenter".constantize to end with "ArrayPresenter".constantize, and this results in an error as there is no such class as ArrayPresenter. What you could do here to solve this is to iterate an array first:

    <% @events.each do |event| %>
      <% present event do |event_presenter| %>
    

    Another option could be to iterate a collection inside of your helper method. You might be intrested in some existing solutions like Draper gem to get an idea of how they solve the objects wrapping issues.