0

I tried to learn about presenter and did the following classes

User model with id, first_name, last_name, email

user_controller with the following methods

  def index
    @users = User.all
    render_user_json @users
  end

  def show
    @user = User.find_by_id(params[:id])
    if @user.nil?
      render json: { message: 'User can not be found' }, status: 404
      return
    end

    render_user_json @user
  end

  def render_user_json(user)
    render json: ::Presenters::User::UserPresenter.new(user).generate
  end

UserPresenter class

module Presenters
  module User
    class UserPresenter
      attr_reader :user

      def initialize(user)
        @user = user
      end

      def generate
        {
          id: @user.id,
          first_name: @user.first_name,
          last_name: @user.last_name,
          email: @user.email
        }
      end
    end
  end
end

When I go to localhost:3000/users/id it works well but when I go to localhost:3000/users I get the following error

NoMethodError (undefined method `id' for #<User::ActiveRecord_Relation:0x00007f9952ac4930>
Did you mean?  ids):
  lib/presenters/user/user_presenter.rb:14:in `generate'
  app/controllers/users_controller.rb:49:in `render_user_json'
  app/controllers/users_controller.rb:9:in `index'


  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/actionpack-4.2.11/lib/action_dispatch/middleware/templates/rescues/_source.erb (4.0ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/actionpack-4.2.11/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.0ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/actionpack-4.2.11/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.0ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/actionpack-4.2.11/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (108.3ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/web-console-2.3.0/lib/web_console/templates/_markup.html.erb (0.4ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/web-console-2.3.0/lib/web_console/templates/_inner_console_markup.html.erb within layouts/inlined_string (0.3ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/web-console-2.3.0/lib/web_console/templates/_prompt_box_markup.html.erb within layouts/inlined_string (0.3ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/web-console-2.3.0/lib/web_console/templates/style.css.erb within layouts/inlined_string (0.4ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/web-console-2.3.0/lib/web_console/templates/console.js.erb within layouts/javascript (91.6ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/web-console-2.3.0/lib/web_console/templates/main.js.erb within layouts/javascript (0.7ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/web-console-2.3.0/lib/web_console/templates/error_page.js.erb within layouts/javascript (0.8ms)
  Rendered /Users/noammansur/.rvm/gems/ruby-2.3.8/gems/web-console-2.3.0/lib/web_console/templates/index.html.erb (210.6ms)

It seems like it doesn't passed as single users

Noam Mansur
  • 352
  • 1
  • 2
  • 10

1 Answers1

0

Rather than this:

render_user_json @users

Either make another method render_users_json (note the plural users) or just call the render from the index method directly like this:

  # inside index method
  render json: users.map do |user|
    ::Presenters::User::UserPresenter.new(user).generate
  end
max pleaner
  • 26,189
  • 9
  • 66
  • 118
  • This causes abstractController::DoubleRenderError – Noam Mansur Mar 17 '20 at 19:43
  • It seems like it ignores the presenter since it shows all the fields under user and it doesn't work for the show. Given that the original code: ```render json: user, except: %i[created_at updated_at password_digest token]``` worked fine for both cases I don't get the purpose of the presenter – Noam Mansur Mar 17 '20 at 20:18
  • @NoamMansur sorry I made another mistake, you are passing `user` into the method from show and `users` from 'index' ... The presenter is just a way to get that logic out of your controller ... ANyway, I updated my answer again. – max pleaner Mar 17 '20 at 20:22
  • so bottom line is that you lose the ability to send user and users into the same method? – Noam Mansur Mar 24 '20 at 11:24
  • @NoamMansur it is possible to check in the method whether the argument is a list of users or a single users and change the behavior depending on that. But I'm personally not a big fan of that. I think it's better to make multiple methods in that case. – max pleaner Mar 24 '20 at 17:18