ruby-grape / grape-roar Goto Github PK
View Code? Open in Web Editor NEWUse Roar with Grape.
License: MIT License
Use Roar with Grape.
License: MIT License
Grape exposures give you entity_name
, exposures
and documentation
. We can add those for out-of-the-box support for https://github.com/tim-vandecasteele/grape-swagger.
module Grape
module Roar
module Representer
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def entity_name
self.name.split('::').last.gsub(/Presenter$/, '')
end
def exposures
{}
end
def documentation
Hash[representable_attrs.map do |attribute|
property_name = attribute[:as].evaluate nil, nil
next if property_name == '_links'
[ property_name, { desc: attribute[:desc], type: attribute[:type] }]
end.compact]
end
end
end
end
end
I'm having nested representers as following:
notifications_representers
** notification_representers
**** comment_representers
****** post_representers
******** image_representers
When I render a list of notifications with a type of comment and post title and post's image. But I see there are a few records that have image's attributes override to whole post attributes. Please tell me any wrong?
Hi there,
In advance: Please let me know if this is the wrong place to report this issue, it might be better to report at the representable gem or grape gem.
The issue: Since the update of the grape gem from v0.11.0 (still works) to v0.12.0 (doesn't work) I am unable to represent values from a hash using Grape-Roar, eg:
Gems:
module API
module V1
module Representers
module SomeRepresenter
include Roar::JSON
include Roar::Hypermedia
include Grape::Roar::Representer
property :some_property
end
end
end
end
Throws:
> undefined method `some_property' for #<Hash:0x007f9f5b281318>
representable (2.2.3) lib/representable/binding.rb, line 98
-----------------------------------------------------------
ruby
93 evaluate_option(:parse_filter, value, doc) { value }
94 end
95
96 def get
97 evaluate_option(:getter) do
> 98 exec_context.send(getter)
99 end
100 end
101
102 def set(value)
103 evaluate_option(:setter, value) do
App backtrace
-------------
Full backtrace
--------------
- representable (2.2.3) lib/representable/binding.rb:98:in `block in get'
- representable (2.2.3) lib/representable/binding.rb:120:in `evaluate_option'
- representable (2.2.3) lib/representable/binding.rb:97:in `get'
- representable (2.2.3) lib/representable/binding.rb:56:in `block in compile_fragment'
- representable (2.2.3) lib/representable/binding.rb:120:in `evaluate_option'
- representable (2.2.3) lib/representable/binding.rb:55:in `compile_fragment'
- representable (2.2.3) lib/representable/mapper.rb:73:in `compile_fragment'
- representable (2.2.3) lib/representable/mapper.rb:33:in `serialize_property'
- representable (2.2.3) lib/representable/mapper.rb:25:in `block in serialize'
- representable (2.2.3) lib/representable/mapper.rb:24:in `serialize'
- representable (2.2.3) lib/representable.rb:48:in `create_representation_with'
- representable (2.2.3) lib/representable/hash.rb:35:in `to_hash'
- representable (2.2.3) lib/representable/json.rb:35:in `to_json'
- grape-roar (0.3.0) lib/grape/roar/formatter.rb:6:in `call'
- grape (0.12.0) lib/grape/middleware/formatter.rb:34:in `block in after'
- grape (0.12.0) lib/grape/middleware/formatter.rb:33:in `after'
- grape (0.12.0) lib/grape/middleware/base.rb:25:in `call!'
- grape (0.12.0) lib/grape/middleware/base.rb:18:in `call'
- grape (0.12.0) lib/grape/middleware/base.rb:24:in `call!'
- grape (0.12.0) lib/grape/middleware/base.rb:18:in `call'
- grape (0.12.0) lib/grape/middleware/error.rb:27:in `block in call!'
- grape (0.12.0) lib/grape/middleware/error.rb:26:in `call!'
- grape (0.12.0) lib/grape/middleware/base.rb:18:in `call'
- rack (1.6.4) lib/rack/head.rb:13:in `call'
- rack (1.6.4) lib/rack/builder.rb:153:in `call'
- grape (0.12.0) lib/grape/endpoint.rb:196:in `call!'
- grape (0.12.0) lib/grape/endpoint.rb:184:in `call'
- rack-mount (0.8.3) lib/rack/mount/route_set.rb:152:in `block in call'
- rack-mount (0.8.3) lib/rack/mount/code_generation.rb:96:in `block in recognize'
- rack-mount (0.8.3) lib/rack/mount/code_generation.rb:68:in `optimized_each'
- rack-mount (0.8.3) lib/rack/mount/code_generation.rb:95:in `recognize'
- rack-mount (0.8.3) lib/rack/mount/route_set.rb:141:in `call'
- grape (0.12.0) lib/grape/api.rb:98:in `call'
- grape (0.12.0) lib/grape/api.rb:33:in `call!'
- grape (0.12.0) lib/grape/api.rb:29:in `call'
- actionpack (4.2.0) lib/action_dispatch/routing/mapper.rb:51: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'
- omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!'
- omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call'
- omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!'
- omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call'
- omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!'
- omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call'
- omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!'
- omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call'
- omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!'
- omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call'
- omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!'
- omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call'
- warden (1.2.3) lib/warden/manager.rb:35:in `block in call'
- warden (1.2.3) lib/warden/manager.rb:34:in `call'
- rack-cors (0.4.0) lib/rack/cors.rb:80:in `call'
- rack (1.6.4) lib/rack/etag.rb:24:in `call'
- rack (1.6.4) lib/rack/conditionalget.rb:25:in `call'
- rack (1.6.4) lib/rack/head.rb:13:in `call'
- actionpack (4.2.0) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
- actionpack (4.2.0) lib/action_dispatch/middleware/flash.rb:260:in `call'
- rack (1.6.4) lib/rack/session/abstract/id.rb:225:in `context'
- rack (1.6.4) lib/rack/session/abstract/id.rb:220:in `call'
- actionpack (4.2.0) lib/action_dispatch/middleware/cookies.rb:560:in `call'
- activerecord (4.2.0) lib/active_record/query_cache.rb:36:in `call'
- activerecord (4.2.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:647:in `call'
- activerecord (4.2.0) lib/active_record/migration.rb:378: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'
- actionpack (4.2.0) lib/action_dispatch/middleware/reloader.rb:73:in `call'
- actionpack (4.2.0) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
- better_errors (2.1.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
- better_errors (2.1.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
- better_errors (2.1.1) lib/better_errors/middleware.rb:57:in `call'
- actionpack (4.2.0) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
- web-console (2.1.3) lib/web_console/middleware.rb:37:in `call'
- actionpack (4.2.0) lib/action_dispatch/middleware/show_exceptions.rb:30: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'
- actionpack (4.2.0) lib/action_dispatch/middleware/request_id.rb:21:in `call'
- rack (1.6.4) lib/rack/methodoverride.rb:22:in `call'
- rack (1.6.4) lib/rack/runtime.rb:18:in `call'
- activesupport (4.2.0) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
- rack (1.6.4) lib/rack/lock.rb:17:in `call'
- actionpack (4.2.0) lib/action_dispatch/middleware/static.rb:113:in `call'
- rack (1.6.4) lib/rack/sendfile.rb:113:in `call'
- utf8-cleaner (0.0.9) lib/utf8-cleaner/middleware.rb:18:in `call'
- railties (4.2.0) lib/rails/engine.rb:518:in `call'
- railties (4.2.0) lib/rails/application.rb:164:in `call'
- thin (1.6.3) lib/thin/connection.rb:86:in `block in pre_process'
- thin (1.6.3) lib/thin/connection.rb:84:in `pre_process'
- thin (1.6.3) lib/thin/connection.rb:53:in `process'
- thin (1.6.3) lib/thin/connection.rb:39:in `receive_data'
- eventmachine (1.0.7) lib/eventmachine.rb:187:in `run'
- thin (1.6.3) lib/thin/backends/base.rb:73:in `start'
- thin (1.6.3) lib/thin/server.rb:162:in `start'
- thin (1.6.3) lib/thin/controllers/controller.rb:87:in `start'
- thin (1.6.3) lib/thin/runner.rb:200:in `run_command'
- thin (1.6.3) lib/thin/runner.rb:156:in `run!'
- thin (1.6.3) bin/thin:6:in `<top (required)>'
I often find myself writing code like:
::FullActivityRepresenter.prepare(full_activity).to_json(student: current_student)
or..
AttemptRepresenter.prepare(attempt).to_json(wrap: :attempt)
This gem looks great, but I can't seem to figure out an easy way to send data to the to_json
method.
I would imagine some changes would need to happen here and here
Any ideas - if this is already possible - to how I can get this working?
See https://github.com/apotonick/roar/blob/master/lib/roar/representer.rb, will conflict with something like this:
message: "class or module required",
backtrace: [
"/Users/dblock/.rvm/gems/ruby-2.0.0-p353/gems/representable-2.0.0.rc2/lib/representable/represent.rb:4:in `is_a?'",
"/Users/dblock/.rvm/gems/ruby-2.0.0-p353/gems/representable-2.0.0.rc2/lib/representable/represent.rb:4:in `represent'",
"/Users/dblock/.rvm/gems/ruby-2.0.0-p353/bundler/gems/grape-4efcc0b88545/lib/grape/endpoint.rb:358:in `present'",
"/Users/dblock/source/gravity/dblock/app/api/v2/status_endpoint.rb:10:in `block (2 levels) in <class:StatusEndpoint>'",
"/Users/dblock/.rvm/gems/ruby-2.0.0-p353/bundler/gems/grape-4efcc0b88545/lib/grape/endpoint.rb:43:in `call'",
"/Users/dblock/.rvm/gems/ruby-2.0.0-p353/bundler/gems/grape-4efcc0b88545/lib/grape/endpoint.rb:43:in `block in generate_api_method'",
Guys, I have some trouble with this gem.
I have such error caught error of type NoMethodError in after callback inside Grape::Middleware::Formatter : undefined method `entries' for #<Message
When i present conversations.
This is my code.
api/v1/conversations
api/v1/conversations/id/messages
conversations.rb
present conversations, with: App::API::ConversationsCollection
messages.rb
present messages, with: App::API::MessagesCollection
presenters/conversations/collection.rb
class App::API::ConversationsCollection < App::API::Collection
collection :entries, extend: App::API::ConversationsSingle, as: :conversations
end
presenters/conversations/single.rb
class App::API::ConversationsSingle < App::API::Single
properties :id
property :user, exec_context: :decorator
def user
App::API::Users.new(represented.user).to_hash
end
end
presenters/messages/collection
class App::API::MessagesCollection < App::API::Collection
collection :entries, extend: App::API::MessagesSingle, as: :messages
end
presenters/messages/single
class App::API::MessagesSingle < App::API::Single
properties :id
property :user, exec_context: :decorator
def user
App::API::Users.new(represented.user).to_hash
end
end
collection.rb
require 'roar/decorator'
require 'roar/json'
class App::API::Collection < Grape::Roar::Decorator
include Roar::JSON
end
single.rb
require 'roar/decorator'
require 'roar/json'
class App::API::Single < Grape::Roar::Decorator
include Roar::JSON
class << self
def properties(*props)
props.each { |prop| property prop }
end
end
end
decorator.rb
require 'roar/decorator'
require 'roar/json'
class App::API::Decorator < Grape::Roar::Decorator
include Roar::JSON
include Roar::Hypermedia
include Grape::Roar::Representer
end
See https://github.com/dblock/grape-with-roar/blob/765b6fc0c117e70546161ced37da86cc0e18a8d4/api/extensions/crud_extension.rb, a simple CRUD extension that lets you write API crud in a much more elegant way.
spline = create Acme::Models::Spline, with: Acme::Api::Presenters::SplinePresenter, from: params[:spline]
present spline, with: Acme::Api::Presenters::SplinePresenter
spline = Acme::Models::Spline.find(params[:uuid])
update spline, with: Acme::Api::Presenters::SplinePresenter, from: params[:spline]
spline = Acme::Models::Spline.find(params[:uuid])
delete spline, with: Acme::Api::Presenters::SplinePresenter
In https://github.com/dblock/grape-roar/blob/master/lib/grape/roar/formatter.rb#L6, I think MultiJson.dump
should also pass env
as the second parameter.
The code causing this behavior is https://github.com/ruby-grape/grape-roar/blob/master/lib/grape/roar/representer.rb#L10
Example
user = User.find_by(email: '[email protected]')
# user => nil
present user, with: User::Representer
# User::Representer.ancestors => [..., Grape::Roar::Representer, ...]
Obviously there's a bug in this application code, but the result is that, since nil
is a singleton, now every time the application asks for nil
, it gets it, but with all kinds of fun stuff mixed in, like a custom #to_hash
that, for instance, mucks with the instantiation of ActionController::Parameters
and causes completely unrelated pages in an app to blow up
Thoughts? I'd be happy to submit a PR, but i only have a cursory understanding of all the interplay between grape, roar, grape-roar, representable, etc. and just tossing in a nil
check might not be the best approach
Would you consider adding support for automatically extending object
with the appropriate representer and releasing this as a gem?
Say something along these lines of:
def call(object, env)
representer_name = "#{object.class}Representer"
if Object.const_definied?(representer_name)
representer_class = Object.const_get()
object.extend(representer_class)
end
Grape::Formatter::Json.call object, env
end
See ruby-grape/grape#827, we want to be able to write:
requires :spline, type: Acme::Api::Presenters::SplinePresenter
If you put present instance, with: Presenter
inside a cache block, it cannot be serialized. That is because its implementation looks like this:
def represent(object, options = {})
object.extend self
object
end
The objects gets serialized, but not its class definition with includes the extended methods.
A solution is to roll out a presenter that looks like this:
module Grape
module Roar
module Representer
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def represent(object, options = {})
object.extend self
object.as_json(options) # usually cannot be `to_json` because Grape formatter would re-encode this
end
end
end
end
end
Maybe this should just be a class called Grape::Roar::Representer::JSON
?
After bumping Roar from 1.0.1
to 1.0.4
, having issues with accessing options in link
method block.
representable
gem was also bumped from 2.1.8
to 3.0.0
by virtue of me upgrading reform
from 1.2.6
to 2.1.0
.
No longer works:
class ClientsPresenter
link :self do |options|
options => nil ???
end
end
With this calling present
method:
resource :clients do
get do
present clients, with: ClientsPresenter
end
end
I certainly do not have complete understanding of interplay between Roar ~ Representable ~ Grape libraries, but any thoughts/discussion would be really appreciated!
Thanks!
Hello,
A question on how to use nested attributes in either decorators/representers. In either way I get an error undefined method
link' for #Class:0x007f8b441382c0`
module TupApi
module Presenters
class ItemPresenterV2D20141223 < Grape::Roar::Decorator
include Roar::Representer::JSON
include Roar::Representer::Feature::Hypermedia
include Grape::Roar::Representer
nested :images do
link 'images:large_url' do
"link"
end
end
end
end
end
get ":id" do
TupApi::Presenters::ItemPresenterV2D20141223.new(Item.find(params[:id]))
end
I'm using version 0.2.0 with Grape 0.9.0.
Thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.