trailblazer / roar-rails

Use Roar's representers in Rails.
http://roar.apotomo.de
MIT License
235 stars 65 forks source link

API Versioning and Roar #106

Open chadwtaylor opened 9 years ago

chadwtaylor commented 9 years ago

Everything worked great for a model. When it came to an array/collection of models, this is where I'm stuck and I wonder if it has to do with the fact my Rails API project is versioned (ie: v1, v2)?

The error message I'm getting when trying to load a collection:

uninitialized constant Api::V2::PeopleRepresenter (and I already instructed the render to use represent_items_with: Api::V2::PersonRepresenter). I wonder if it has to do with modules/namespacing things?

Here's what my set up looks like...

app/api/v2/api_controller

require 'roar'

module V2
  class Api::V2::ApiController < ActionController::API

    include Roar::Rails::ControllerAdditions
    include Roar::Rails::ControllerAdditions::Render

    respond_to :json
    ...
  end
end

app/api/v2/people_controller

class Api::V2::PeopleController < Api::V2::ApiController

  # GET /people
  def index
    people = Person.find([8,18])
    render json: people, represent_items_with: Api::V2::PersonRepresenter
  end

  ...

end

app/representers/api/v2/person_representer

module Api
  module V2
    class PersonRepresenter < Roar::Decorator
      include Roar::JSON::JSONAPI

      type :people

      property :id
      property :first_name
      property :last_name
      property :full_name

    end
  end
end
apotonick commented 9 years ago

Have you looked into the ::represents class method, yet? https://github.com/apotonick/roar-rails#represents-configuration

chadwtaylor commented 9 years ago

Since each method will vary in which model will be rendered (ie: most of the time a person model, rarely will be an invoice model). So putting it on the class level may not be favorable in my situation? I gave it a try though and got another error: undefined method 'id' for #<Array:0x007fde1099e670>

I'm hoping I can create one PersonRepresenter that will deal with collections as well, hence the represent_items_with at the method level.

Thanks for your invaluable help!

apotonick commented 9 years ago

I'm still wondering, though, why the :represent_items_with option doesn't kick in?

chadwtaylor commented 9 years ago

What else do you need to see from my end to narrow down the issue?

chadwtaylor commented 9 years ago

I even tried to change from render json: people, represent_items_with:Api::V2::PersonRepresenter to respond_with people, represent_items_with:Api::V2::PersonRepresenter and got the following error:

ActionController::UnknownFormat

Am hitting a wall here but going to try few more things and hopefully get the collections to work (emphasis: The single model worked nicely).

apotonick commented 9 years ago

Ah, I got it! The :represent_items_with option doesn't work with render! If you use respond_with you gotta call respond_to on the controller level (that's Rails, not roar-rails!)!

chadwtaylor commented 9 years ago

I switched to respond_with with the respond_to on the controller level (see my codes below) -- and got this error:

ActionController::UnknownFormat

The only thing working for me is using render (on a single model). Any ideas?

# app/api/v2/people_controller.rb

class Api::V2::PeopleController < Api::V2::ApiController
  include Roar::Rails::ControllerAdditions
  respond_to :json

  def index
    p = Person.first
    respond_with p #=> This resulted in ActionController::UnknownFormat
  end

end

# app/representers/api/v2/person_representer.rb

module Api
  module V2
    module PersonRepresenter 
      include Roar::JSON::JSONAPI

      type :people

      property :id
      property :first_name
      property :last_name
      property :full_name

    end
  end
end
apotonick commented 9 years ago

Can you paste the server output or the test line for that failling request? It must be something in Rails, we don't throw UnknownFormat anywhere! Thanks!

chadwtaylor commented 9 years ago
Started GET "/v2/people" for 127.0.0.1 at 2015-02-03 14:15:35 -0800
Processing by Api::V2::PeopleController#index as HTML
  Person Load (0.5ms)  SELECT  "people".* FROM "people"  ORDER BY "people"."id" ASC LIMIT 1
Completed 406 Not Acceptable in 3ms

ActionController::UnknownFormat - ActionController::UnknownFormat:
  responders (2.1.0) lib/action_controller/respond_with.rb:205:in `respond_with'
  app/controllers/api/v2/people_controller.rb:12:in `index'
  actionpack (4.2.0) lib/abstract_controller/base.rb:198:in `process_action'
  actionpack (4.2.0) lib/action_controller/metal/rendering.rb:10:in `process_action'
  actionpack (4.2.0) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
  activesupport (4.2.0) lib/active_support/callbacks.rb:117:in `call'
  activesupport (4.2.0) lib/active_support/callbacks.rb:169:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:169:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:92:in `_run_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:734:in `_run_process_action_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.0) lib/abstract_controller/callbacks.rb:19:in `process_action'
  actionpack (4.2.0) lib/action_controller/metal/rescue.rb:29:in `process_action'
  actionpack (4.2.0) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
  activesupport (4.2.0) lib/active_support/notifications.rb:164:in `block in instrument'
  activesupport (4.2.0) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  activesupport (4.2.0) lib/active_support/notifications.rb:164:in `instrument'
  actionpack (4.2.0) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
  activerecord (4.2.0) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
  actionpack (4.2.0) lib/abstract_controller/base.rb:137:in `process'
  actionview (4.2.0) lib/action_view/rendering.rb:30:in `process'
  actionpack (4.2.0) lib/action_controller/metal.rb:195:in `dispatch'
  actionpack (4.2.0) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
  actionpack (4.2.0) lib/action_controller/metal.rb:236:in `block in action'
  actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:73:in `dispatch'
  actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:42:in `serve'
  actionpack (4.2.0) lib/action_dispatch/journey/router.rb:43:in `block in serve'
  actionpack (4.2.0) lib/action_dispatch/journey/router.rb:30:in `serve'
  actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:802:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/rack/agent_hooks.rb:26:in `traced_call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:55:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/rack/browser_monitoring.rb:23:in `traced_call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:55:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/rack/developer_mode.rb:56:in `traced_call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:55:in `call'
  rack (1.6.0) lib/rack/etag.rb:24:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack (1.6.0) lib/rack/conditionalget.rb:25:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack (1.6.0) lib/rack/head.rb:13:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  activerecord (4.2.0) lib/active_record/query_cache.rb:36:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  activerecord (4.2.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:647:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  activerecord (4.2.0) lib/active_record/migration.rb:378:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
  activesupport (4.2.0) lib/active_support/callbacks.rb:88:in `_run_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:734:in `_run_call_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.0) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/reloader.rb:73:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  appsignal (0.11.0) lib/appsignal/rack/listener.rb:13:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  airbrake (4.1.0) lib/airbrake/rails/middleware.rb:13:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  better_errors (2.0.0) lib/better_errors/middleware.rb:84:in `protected_app_call'
  better_errors (2.0.0) lib/better_errors/middleware.rb:79:in `better_errors_call'
  better_errors (2.0.0) lib/better_errors/middleware.rb:57:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  railties (4.2.0) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.2.0) lib/rails/rack/logger.rb:20:in `block in call'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in `tagged'
  railties (4.2.0) lib/rails/rack/logger.rb:20:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack (1.6.0) lib/rack/runtime.rb:18:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rocket_pants (1.10.0) lib/rocket_pants/cache_middleware.rb:21:in `_call'
  rocket_pants (1.10.0) lib/rocket_pants/cache_middleware.rb:12:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  activesupport (4.2.0) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack (1.6.0) lib/rack/lock.rb:17:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/static.rb:113:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack-cors (0.3.1) lib/rack/cors.rb:72:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  airbrake (4.1.0) lib/airbrake/user_informer.rb:16:in `_call'
  airbrake (4.1.0) lib/airbrake/user_informer.rb:12:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  hirefire-resource (0.3.4) lib/hirefire/middleware.rb:29:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  railties (4.2.0) lib/rails/engine.rb:518:in `call'
  railties (4.2.0) lib/rails/application.rb:164:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack (1.6.0) lib/rack/content_length.rb:15:in `call'
  puma (2.9.2) lib/puma/server.rb:490:in `handle_request'
  puma (2.9.2) lib/puma/server.rb:361:in `process_client'
  puma (2.9.2) lib/puma/server.rb:254:in `block in run'
  puma (2.9.2) lib/puma/thread_pool.rb:92:in `block in spawn_thread'
chadwtaylor commented 9 years ago

(want to say how much I appreciate your help here!)

apotonick commented 9 years ago

"No worries, mate!" as they say in Australia! :wink:

This is your problem: Processing by Api::V2::PeopleController#index as HTML

Your request is not a JSON request! That's why Rails complains, it doesn't know how to handle a generic HTML request.

chadwtaylor commented 9 years ago

Ah, so I appended .json to the url like so: http://localhost:3001/v2/people.json and a new error came up:

Started GET "/v2/people.json" for 127.0.0.1 at 2015-02-03 14:25:17 -0800
Processing by Api::V2::PeopleController#index as JSON
  Person Load (0.3ms)  SELECT  "people".* FROM "people"  ORDER BY "people"."id" ASC LIMIT 1
Completed 500 Internal Server Error in 18ms

NoMethodError - undefined method `default_render' for #<Api::V2::PeopleController:0x007fdf3bb770d8>:
  responders (2.1.0) lib/action_controller/responder.rb:236:in `default_render'
  responders (2.1.0) lib/action_controller/responder.rb:186:in `to_format'
  responders (2.1.0) lib/action_controller/responder.rb:163:in `respond'
  responders (2.1.0) lib/action_controller/responder.rb:156:in `call'
  responders (2.1.0) lib/action_controller/respond_with.rb:203:in `respond_with'
  app/controllers/api/v2/people_controller.rb:12:in `index'
  actionpack (4.2.0) lib/abstract_controller/base.rb:198:in `process_action'
  actionpack (4.2.0) lib/action_controller/metal/rendering.rb:10:in `process_action'
  actionpack (4.2.0) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
  activesupport (4.2.0) lib/active_support/callbacks.rb:117:in `call'
  activesupport (4.2.0) lib/active_support/callbacks.rb:169:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:169:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:92:in `_run_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:734:in `_run_process_action_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.0) lib/abstract_controller/callbacks.rb:19:in `process_action'
  actionpack (4.2.0) lib/action_controller/metal/rescue.rb:29:in `process_action'
  actionpack (4.2.0) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
  activesupport (4.2.0) lib/active_support/notifications.rb:164:in `block in instrument'
  activesupport (4.2.0) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  activesupport (4.2.0) lib/active_support/notifications.rb:164:in `instrument'
  actionpack (4.2.0) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
  activerecord (4.2.0) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
  actionpack (4.2.0) lib/abstract_controller/base.rb:137:in `process'
  actionview (4.2.0) lib/action_view/rendering.rb:30:in `process'
  actionpack (4.2.0) lib/action_controller/metal.rb:195:in `dispatch'
  actionpack (4.2.0) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
  actionpack (4.2.0) lib/action_controller/metal.rb:236:in `block in action'
  actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:73:in `dispatch'
  actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:42:in `serve'
  actionpack (4.2.0) lib/action_dispatch/journey/router.rb:43:in `block in serve'
  actionpack (4.2.0) lib/action_dispatch/journey/router.rb:30:in `serve'
  actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:802:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/rack/agent_hooks.rb:26:in `traced_call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:55:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/rack/browser_monitoring.rb:23:in `traced_call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:55:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/rack/developer_mode.rb:56:in `traced_call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:55:in `call'
  rack (1.6.0) lib/rack/etag.rb:24:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack (1.6.0) lib/rack/conditionalget.rb:25:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack (1.6.0) lib/rack/head.rb:13:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  activerecord (4.2.0) lib/active_record/query_cache.rb:36:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  activerecord (4.2.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:647:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  activerecord (4.2.0) lib/active_record/migration.rb:378:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
  activesupport (4.2.0) lib/active_support/callbacks.rb:88:in `_run_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:734:in `_run_call_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.0) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/reloader.rb:73:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  appsignal (0.11.0) lib/appsignal/rack/listener.rb:13:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  airbrake (4.1.0) lib/airbrake/rails/middleware.rb:13:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  better_errors (2.0.0) lib/better_errors/middleware.rb:84:in `protected_app_call'
  better_errors (2.0.0) lib/better_errors/middleware.rb:79:in `better_errors_call'
  better_errors (2.0.0) lib/better_errors/middleware.rb:57:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  railties (4.2.0) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.2.0) lib/rails/rack/logger.rb:20:in `block in call'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in `tagged'
  railties (4.2.0) lib/rails/rack/logger.rb:20:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack (1.6.0) lib/rack/runtime.rb:18:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rocket_pants (1.10.0) lib/rocket_pants/cache_middleware.rb:21:in `_call'
  rocket_pants (1.10.0) lib/rocket_pants/cache_middleware.rb:12:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  activesupport (4.2.0) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack (1.6.0) lib/rack/lock.rb:17:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/static.rb:113:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack-cors (0.3.1) lib/rack/cors.rb:72:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  airbrake (4.1.0) lib/airbrake/user_informer.rb:16:in `_call'
  airbrake (4.1.0) lib/airbrake/user_informer.rb:12:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  hirefire-resource (0.3.4) lib/hirefire/middleware.rb:29:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  railties (4.2.0) lib/rails/engine.rb:518:in `call'
  railties (4.2.0) lib/rails/application.rb:164:in `call'
  newrelic_rpm (3.9.7.266) lib/new_relic/agent/instrumentation/middleware_tracing.rb:57:in `call'
  rack (1.6.0) lib/rack/content_length.rb:15:in `call'
  puma (2.9.2) lib/puma/server.rb:490:in `handle_request'
  puma (2.9.2) lib/puma/server.rb:361:in `process_client'
  puma (2.9.2) lib/puma/server.rb:254:in `block in run'
  puma (2.9.2) lib/puma/thread_pool.rb:92:in `block in spawn_thread'
apotonick commented 9 years ago

I hate Rails.

apotonick commented 9 years ago

What roar-rails version are you on?

chadwtaylor commented 9 years ago

roar 1.0.0 roar-rails 1.0.1 rails 4.2.0

I love Rails. :)

apotonick commented 9 years ago

That's because you haven't seen how simple things can be with less Rails: https://leanpub.com/trailblazer

chadwtaylor commented 9 years ago

I'm pretty sure -- the thing is we're knee-deep into a Rails project... so we can't switch boats just yet. :(

apotonick commented 9 years ago

I hear ya! :stuck_out_tongue_winking_eye:

Trailblazer is Rails, just less coupling to the actual framework and less weirdness going on in controllers and models.

I really have no idea what's going on on your side - I checked an tests pass with Rails 4.2 and roar-rails. Are you using rails-api?

apotonick commented 9 years ago

AH, I know what's your problem.

You got a file app/views/v2/peoples/index.html.haml and that makes it try to call render_default and this is exactly why I hate Rails.

Explanation: Rails and its responders use exceptions to find out whether or not a template is present and then base further behavior on that. And that is just wrong as it is completely hidden semantic, but, hey, magic, yeah, FTW! :stuck_out_tongue:

chadwtaylor commented 9 years ago

Correct, am using rails-api and the file index.html.haml doesn't even exist... this is so weird. Yea, FTW, will continue to play around and get something going! :)

Thanks!

apotonick commented 9 years ago

Are there any files in your app/views? See, this is where the wrong flow starts: https://github.com/plataformatec/responders/blob/master/lib/action_controller/responder.rb#L190

Wait, what was your actual problem in the first place? We can make that work and you keep using render ?

chadwtaylor commented 9 years ago

Yes, I have views but they're for mailers only (ie: app/view/person_mailer).

My issue was trying to keep one representer for each models (rather than creating two for each model like PersonRepresenter and PeopleRepresenter).

I even created a PeopleRepresenter and used render, it found the PeopleRepresenter file but I got this error: undefined method 'id' for #<Array:0x007fe3277c3ac8>

I wonder though if the people_representer.rb is supposed to have a certain implementation? I basically copied-pasted-renamed from person_representer.rb to people_representer.rb.

apotonick commented 9 years ago

It sounds like your representers for singular models are ok. However, you need to define a representer for collections, too (or use represent_items_with, which isn't implemented for render, YET cough wink).

chadwtaylor commented 9 years ago

Do you have a sample of what a representer for collections should look like?

Yea, represent_items_with for render would be awesome… one day! :)

apotonick commented 9 years ago

Tons of examples in issues, check Lonely Collections. Or buy my book and wait a few weeks until we get to the document API parts. _cough_ _COUGH_*

chadwtaylor commented 9 years ago

:)

Ah, thanks for the Lonely Collection tip -- I overlooked that!

Now things are rendering for collections high five and there's a but... Here's what the result looked like:

[
  {
    "people":{
      "id":8,
      "first_name":"Jane",
      "last_name":"Doe",
      "full_name":"Jane Doe",
    }
  },
  {
    "people":{
      "id":18,
      "first_name":"John",
      "last_name":"Doe",
      "full_name":"John Doe",
    }
  }
]

I would think it should look like this...

{
  people: [
    {
      id: 8,
      first_name: "Jane",
      last_name: "Doe",
      full_name: "Jane Doe",
    },
    {
      id: 18,
      first_name: "John",
      last_name: "Doe",
      full_name: "John Doe",
    }
  ] 
}

Here's what my PeopleRepresenter looks like:

module Api
  module V2
    class PeopleRepresenter < Roar::Decorator
      include Representable::JSON::Collection
      items extend:Api::V2::PersonRepresenter, class:Person
    end
  end
end
apotonick commented 9 years ago

Your PersonRepresenter must have a representation_wrap set?

chadwtaylor commented 9 years ago

Ah, thanks... just added self.represenation_wrap = :people and we are so close... Here's the new JSON payload:

{
  people: [
    {
      "people":{
        "id":8,
        "first_name":"Jane",
        "last_name":"Doe",
        "full_name":"Jane Doe",
      }
    },
    {
      "people":{
        "id":18,
        "first_name":"John",
        "last_name":"Doe",
        "full_name":"John Doe",
      }
    }
  ]
}
apotonick commented 9 years ago

Haha, no, I am saying Api::V2::PersonRepresenter should NOT have a representation wrap set, otherwise it will add it for every item. Paste Api::V2::PersonRepresenter.

chadwtaylor commented 9 years ago

(will paste soon; BTW just bought your book....)

apotonick commented 9 years ago

Good man, thanks! I promise lots of content about Roar, soon!

chadwtaylor commented 9 years ago

I commented out type :people in PersonRepresenter and now the collection is rendering the JSON payload correctly.

However, I need to keep type :people for a single JSON payload, what to do?

Here's the person_representer.rb content:

module Api
  module V2
    class PersonRepresenter < Roar::Decorator
      include Roar::JSON::JSONAPI

      # type :people # commented that line to make PeopleRepresenter wrap correctly; but need this for a single model, what to do?

      property :id
      property :first_name
      property :last_name
      property :full_name

    end
  end
end
chadwtaylor commented 9 years ago

We are almost there... the current issue is that the type has to be in PersonRepresenter for single models to show:

{
  people: {
    id: 8,
    first_name: "Jane",
    ...
  }
}

Am I making sense?

So close; and then I'll be able to continue my merry way in building an Ember.js frontend.

Thanks so much for your patience and support!

chadwtaylor commented 9 years ago

Update: As a temporary unfavorable workaround was implementing three files:

PersonRepresenter - this has type :people PersonUnwrapRepresenter - a copy of PersonRepresenter sans type PeopleRepresenter - will call PersonUnwrapRepresenter instead.

Obviously not a good practice but that's something I could get some work done while waiting to see what you have to say.

BTW, loved your intro in your book -- the Rails date! I first used it in 2008 so you're two years ahead of me.

chadwtaylor commented 9 years ago

Just in case, I'm sharing my current implementations:

PersonRepresenter:

module Api
  module V2

    class PersonRepresenter < Roar::Decorator 
      include Roar::JSON::JSONAPI

      type :people

      property :uuid, as: :id
      property :first_name
      property :last_name
      property :full_name

    end

  end
end

PersonUnwrapRepresenter:

module Api
  module V2

    class PersonRepresenter < Roar::Decorator 
      include Roar::JSON::JSONAPI

      property :uuid, as: :id
      property :first_name
      property :last_name
      property :full_name

    end

  end
end

PeopleRepresenter:

module Api
  module V2
    class PeopleRepresenter < Roar::Decorator 
      include Representable::JSON::Collection
      self.representation_wrap = :people
      items extend: Api::V2::PersonUnwrapRepresenter, class:Person
    end
  end
end

Api::V2::PeopleController:

module V2
  class Api::V2::PeopleController < Api::V2::ApiController
    include Roar::Rails::ControllerAdditions
    include Roar::Rails::ControllerAdditions::Render

    # GET /people
    def index
      p = Person.first # single model
      # p = Person.find([8,18]) # collection model
      render json:p
    end

  end
end
apotonick commented 9 years ago

Maaan I didn't realize me you're using JSONAPI - would have helped! :laughing:

Note that you need only ONE representer for both singular and collection. Please, check out if rendering works manually as documented here.

Then, we need to extend roar-rails to do the same. Rendering/parsing collection is not implemented, yet.

chadwtaylor commented 9 years ago

So the manual rendering worked! See my irb output below:

irb(main):006:0> Api::V2::PersonRepresenter.prepare(Person.first).to_json
  Person Load (0.3ms)  SELECT  "people".* FROM "people"  ORDER BY "people"."id" ASC LIMIT 1
=> "{\"people\":{\"id\":\"dab4e5e6-ba50-42b4-9633-50a952d2e811\",\"first_name\":\"Chad\",\"last_name\":\"Taylor\",\"full_name\":\"Chad Taylor\"}}"

irb(main):008:0* Api::V2::PersonRepresenter.for_collection.prepare([Person.first, Person.last]).to_json
  Person Load (0.5ms)  SELECT  "people".* FROM "people"  ORDER BY "people"."id" ASC LIMIT 1
  Person Load (0.9ms)  SELECT  "people".* FROM "people"  ORDER BY "people"."id" DESC LIMIT 1
=> "[{\"people\":{\"id\":\"dab4e5e6-ba50-42b4-9633-50a952d2e811\",\"first_name\":\"Chad\",\"last_name\":\"Taylor\",\"full_name\":\"Chad Taylor\"}},{\"people\":{\"id\":\"265abc1c-ef97-485b-b43d-13231108f4ab\",\"first_name\":\"\",\"last_name\":\"John Doe\",\"full_name\":\" John Doe\"}}]"

What do I need to do next? Extending roar-rails; how? Or is it something you need to do an update within the gem before it can function properly?

apotonick commented 9 years ago

Ha of course manual rendering works! :stuck_out_tongue:

So far, roar-rails doesn't know about the ::for_collection method, we have to implement that. Do we have tests for JSONAPI, yet? Let me have a look.

chadwtaylor commented 9 years ago

Cool, let me know what I can do next if anything?

apotonick commented 9 years ago

Check out this test: https://github.com/apotonick/roar-rails/blob/master/test/json_api_renderer_test.rb

You could add a test to render a collection here. This will fail, then we can easily fix it in roar-rails and people all over the world are gonna love you.

chadwtaylor commented 9 years ago

So this is the first time I have done a test (I know, I know, my peers have lectured me about that already).

Here's what I have:

require 'test_helper'

class HalRendererTest < ActionController::TestCase
  include Roar::Rails::TestCase

  class PeopleController < ActionController::Base
    module JsonApiPersonRepresenter
      include Roar::JSON::JSONAPI
      type :people
      property :first_name
    end

    include Roar::Rails::ControllerAdditions

    represents :json_api, :entity => JsonApiPersonRepresenter

    def show
      person = Person.find 1
      respond_with person
    end

    def index
      people = Person.find([1,2])
      respond_with people
    end

  end

  tests PeopleController

  test "should render single model correctly in response to a application/vnd.api+json" do
    get :show, :id => "1", :format => :json_api
    assert_body '{"people":{"first_name":"Chad"}}'
  end

  test "should have a content_type of application/vnd.api+json for a single model" do
    get :show, :id => "bumi", :format => :json_api
    assert_equal response.content_type, 'application/vnd.api+json'
  end

  test "should render collection of models correctly in response to a application/vnd.api+json" do
    get :index, :format => :json_api
    assert_body '{"people":[{"first_name":"Chad"},{"first_name":"Fremont"}]}'
  end

  test "should have a content_type of application/vnd.api+json for a collection of models" do
    get :index, :format => :json_api
    assert_equal response.content_type, 'application/vnd.api+json'
  end

end

I have already added this to config/initializers/mime_types.rb:

ActionController::Renderers.add :json_api do |obj, options|
  self.content_type ||= Mime[:json_api]
  obj
end

Running the test gave us errors:

Finished in 0.077660s, 51.5066 runs/s, 0.0000 assertions/s.

  1) Error:
HalRendererTest#test_should_have_a_content_type_of_application/vnd.api+json_for_a_collection_of_models:
NameError: uninitialized constant Mime::JSON_API
    test/models/json_api_renderer_test.rb:24:in `index'
    test/models/json_api_renderer_test.rb:47:in `block in <class:HalRendererTest>'

  2) Error:
HalRendererTest#test_should_have_a_content_type_of_application/vnd.api+json_for_a_single_model:
NameError: uninitialized constant Mime::JSON_API
    test/models/json_api_renderer_test.rb:19:in `show'
    test/models/json_api_renderer_test.rb:37:in `block in <class:HalRendererTest>'

  3) Error:
HalRendererTest#test_should_render_collection_of_models_correctly_in_response_to_a_application/vnd.api+json:
NameError: uninitialized constant Mime::JSON_API
    test/models/json_api_renderer_test.rb:24:in `index'
    test/models/json_api_renderer_test.rb:42:in `block in <class:HalRendererTest>'

  4) Error:
HalRendererTest#test_should_render_single_model_correctly_in_response_to_a_application/vnd.api+json:
NameError: uninitialized constant Mime::JSON_API
    test/models/json_api_renderer_test.rb:19:in `show'
    test/models/json_api_renderer_test.rb:32:in `block in <class:HalRendererTest>'

4 runs, 0 assertions, 0 failures, 4 errors, 0 skips

Error seems to be around Mime; any ideas?

chadwtaylor commented 9 years ago

My bad, I forgot to add that line Mime::Type.register 'application/vnd.api+json', :json_api to the mime_types.rb file; oops!

Running the test, brb...

chadwtaylor commented 9 years ago

New test result with mime type fixed:

Finished in 0.110748s, 36.1180 runs/s, 9.0295 assertions/s.

  1) Error:
HalRendererTest#test_should_have_a_content_type_of_application/vnd.api+json_for_a_collection_of_models:
NameError: uninitialized constant HalRendererTest::PeopleRepresenter
    test/models/json_api_renderer_test.rb:24:in `index'
    test/models/json_api_renderer_test.rb:47:in `block in <class:HalRendererTest>'

  2) Error:
HalRendererTest#test_should_render_collection_of_models_correctly_in_response_to_a_application/vnd.api+json:
NameError: uninitialized constant HalRendererTest::PeopleRepresenter
    test/models/json_api_renderer_test.rb:24:in `index'
    test/models/json_api_renderer_test.rb:42:in `block in <class:HalRendererTest>'

  3) Error:
HalRendererTest#test_should_render_single_model_correctly_in_response_to_a_application/vnd.api+json:
NoMethodError: undefined method `assert_body' for #<HalRendererTest:0x007fb7ab559028>
    test/models/json_api_renderer_test.rb:33:in `block in <class:HalRendererTest>'

4 runs, 1 assertions, 0 failures, 3 errors, 0 skips
chadwtaylor commented 9 years ago

Sorry for bombing the thread here, I was able to fix the test and remembered you telling me about represent_items_with couple of days ago:

Here's the new test results:

Finished in 0.115252s, 34.7066 runs/s, 17.3533 assertions/s.

  1) Error:
HalRendererTest#test_should_render_collection_of_models_correctly_in_response_to_a_application/vnd.api+json:
NoMethodError: undefined method `assert_body' for #<HalRendererTest:0x007fd764db81c8>
    test/models/json_api_renderer_test.rb:43:in `block in <class:HalRendererTest>'

  2) Error:
HalRendererTest#test_should_render_single_model_correctly_in_response_to_a_application/vnd.api+json:
NoMethodError: undefined method `assert_body' for #<HalRendererTest:0x007fd764d2b458>
    test/models/json_api_renderer_test.rb:33:in `block in <class:HalRendererTest>'

4 runs, 2 assertions, 0 failures, 2 errors, 0 skips

The corrected test file:

require 'test_helper'

class HalRendererTest < ActionController::TestCase
  include Roar::Rails::TestCase

  class PeopleController < ActionController::Base
    module PersonRepresenter
      include Roar::JSON::JSONAPI
      type :people
      property :first_name
    end

    include Roar::Rails::ControllerAdditions

    represents :json_api, :entity => PersonRepresenter

    def show
      person = Person.find 1
      respond_with person
    end

    def index
      people = Person.find([1,2])
      respond_with people, represent_items_with:PersonRepresenter
    end

  end

  tests PeopleController

  test "should render single model correctly in response to a application/vnd.api+json" do
    get :show, :id => "1", :format => :json_api
    assert_body '{"people":{"first_name":"Chad"}}'
  end

  test "should have a content_type of application/vnd.api+json for a single model" do
    get :show, :id => "bumi", :format => :json_api
    assert_equal response.content_type, 'application/vnd.api+json'
  end

  test "should render collection of models correctly in response to a application/vnd.api+json" do
    get :index, :format => :json_api
    assert_body '{"people":[{"first_name":"Chad"},{"first_name":"Fremont"}]}'
  end

  test "should have a content_type of application/vnd.api+json for a collection of models" do
    get :index, :format => :json_api
    assert_equal response.content_type, 'application/vnd.api+json'
  end

end
chadwtaylor commented 9 years ago

So it didn't look like it liked "assert_body" as was in the original test file you sent me. So I adjusted it:

  test "should render single model correctly in response to a application/vnd.api+json" do
    get :show, :id => "1", :format => :json_api
    # assert_body '{"people":{"first_name":"Chad"}}'
    assert_equal response.body, '{"people":{"first_name":"Chad"}}'
  end

  test "should render collection of models correctly in response to a application/vnd.api+json" do
    get :index, :format => :json_api
    # assert_body '{"people":[{"first_name":"Chad"},{"first_name":"Fremont"}]}'
    assert_equal response.body, '{"people":[{"first_name":"Chad"},{"first_name":"Fremont"}]}'
  end

And the new error is:

Finished in 0.113740s, 35.1679 runs/s, 35.1679 assertions/s.

  1) Failure:
HalRendererTest#test_should_render_collection_of_models_correctly_in_response_to_a_application/vnd.api+json [/Users/chadwtaylor/Dropbox/web_projects/honey/linguabee-api/test/models/json_api_renderer_test.rb:46]:
--- expected
+++ actual
@@ -1 +1 @@
-"{\"people\"=>{\"first_name\"=>\"Chad\"}}{\"people\"=>{\"first_name\"=>\"Fremont\"}}"
+"{\"people\":[{\"first_name\":\"Chad\"},{\"first_name\":\"Fremont\"}]}"

4 runs, 4 assertions, 1 failures, 0 errors, 0 skips

I'm hoping that is the specific failure you wanted to see? :)

apotonick commented 9 years ago

Any chance I could see a PR so I can diff? Thanks brother, legend!

chadwtaylor commented 9 years ago

Pardon my ignorance as I have never become a contributor for any projects -- so you wanted a PR on my test file?

chadwtaylor commented 9 years ago

Sent you a PR of my test; hoping I got this right...

chadwtaylor commented 9 years ago

Let me know what I can do for you. Would love to help!

Friendly reminder... I can only use render as respond_with throws a undefined method 'default_render' error as discussed way above in this comment thread (am using the rails-api gem).

apotonick commented 9 years ago

Friendly reminder: add test here: https://github.com/apotonick/roar-rails/blob/master/test/render_test.rb

Thanks for your help!