-
Notifications
You must be signed in to change notification settings - Fork 138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Creating arbitrary hash on lonely collection and encapsulating collection items #111
Comments
Just to give a better idea here is a response from my current app that I'm trying to match. ( sensitive data taken out) {
"status": "success",
"message": "Product(s) found",
"count": 1,
"products": [
{
"id": 108527,
"manufacturer_id": 2,
"manufacturer_number": null,
"masterfile_details": {},
"minimum_order_quantity": null,
"retail_sale_amount_cents": 1231,
"stats": {},
"status_id": 1,
"total_stock": 1,
"updated_at": "2014-10-13T20:33:58-05:00",
"created_at": "2012-02-21T20:26:19-06:00",
}
],
"params": {
"q": {
"id_eq": "108527"
},
"action": "search",
"controller": "products",
"format": "json"
}
} |
Nick, hey! Your "problem" is you want to render a full-blown document and not just a collection. This is why you should think "in that document" and not in collections! 😉 What you have to do is use an appropriate representer composition. class ProductsRepresenter < Roar::Decorator
property :status
property :count
collection :products, extend: ProductRepresenter, class: Product
# and so on
end The object you pass to the representer has to expose the correct API. OpenStruct.new(status: :ok, count: products.size, products: products) There's several tricks to simplify this but start playing with it and let me know if it works. |
@apotonick Thanks Nick (hey!) So I tried you suggestios, but I'm a bit confused as to how I would write my respond_with block in the contoller. Here is what I came up with - but I get "null" as my response class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
include Roar::Rails::ControllerAdditions::Render
def index
@q = Product.ransack(params[:q])
@products = @q.result().order(params[:order]).page(params[:page]).per(params[:per])
respond_with(@products) do |format|
format.html {render}
format.json {render json: OpenStruct.new(products: @products, count: @products.total_count), represent_with: ProductsRepresenter}
end
end
end |
If I do this in console: reload!;
ps = Product.page(5);
r = ProductsRepresenter.new(OpenStruct.new(products: ps, count: ps.total_count));
r.represented I can see both attributes (count = 30000, and products containing ActiveRecord::Relation, but for some reason roar doesn't see them ) |
This is because |
Sorry it started as a Roar question, turned into Roar-Rails questions It's getting late for me here. But just for the heck of it I re implemented it just using representable directly. It does exactly what I need in the format that I need . For now I don't need Hypermedia and other Roar features. For posterity here is what I have. ( If you happen to come up with a solution to my rails problem - I'd be happy to try it out) class ProductsRepresentation < Representable::Decorator
include Representable::JSON
property :count
collection :products, class: Product, decorator: ProductRepresentation
end in Rails calling it just like PORO class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
def index
@q = Product.ransack(params[:q])
@products = @q.result().order(params[:order]).page(params[:page]).per(params[:per])
respond_with(@products) do |format|
format.html {render}
format.json {render json: ProductsRepresentation.new(OpenStruct.new(products: @products, count: @products.total_count))}
end
end
|
One more question you might know how it's done since you dealt with both representable and roar and rails. At this point my brain is fried. Here is what I have now: class ProductRepresentation < Representable::Decorator
include Representable::JSON
property :id
property :name
property :category do
property :id
property :name
property :code
end
#......
end I'd like to use category representer instead of inline. I can't seem to get it right: class CategoryRepresentation < Representable::Decorator
include Representable::JSON
property :id
property :name
property :code
property :description
property :type
property :cateogry_id, as: :parent_id
end
class ProductRepresentation < Representable::Decorator
include Representable::JSON
property :id
property :name
property :category_id # <-------- RIGHT HERE, how can I pass this properly to the CategoryRepresentaion?
#......
end category_id is a belong_to style association THANK YOU! |
Right now, this needs to be supported on the model layer. category.category_id #=> 1 You could pass the product model into the class CategoryRepresenter < ..
property :category_id, getter: lambda {|options| options[:product].category_id } Then, invoke all that as follows. ProductRepresenter.prepare(product).to_json(product: product) I want to make this easier in future versions, though, but give it a go! |
I just wrestled with a similar issue for a while. I had a representer like this: class EmailAddressCollectionRepresenter < Roar::Decorator
include Roar::Representer::JSON::HAL
include Representable::JSON::Collection
self.representation_wrap = :email_addresses
items decorator: EmailAddressRepresenter, class: Channel
link :self do |opts|
"#{opts[:path]}/email_addresses"
end
end ...and I was extremely puzzled as to why the link was being omitted when the resource was accessed. It's pretty confusing that |
The @ichthala, why don't you use a normal representer? Try the following class EmailAddressCollectionRepresenter < Roar::Decorator
include Roar::Representer::JSON::HAL
include Representable::JSON::Collection # NO!!! Don't include this - see next comment!
collection: :email_addresses, decorator: EmailAddressRepresenter, class: Channel
link :self do |opts|
"#{opts[:path]}/email_addresses"
end
def email_addresses
represented
end
end |
Thanks for the help! That almost worked, but I had to do this: class EmailAddressCollectionRepresenter < Roar::Decorator
include Roar::Representer::JSON::HAL
# include Representable::JSON::Collection
collection: :email_addresses, decorator: EmailAddressRepresenter, class: Channel, exec_context: :decorator
link :self do |opts|
"#{opts[:path]}/email_addresses"
end
def email_addresses
represented
end
end It looks like if you |
Yeah, you're right! I'm an idiot, I was telling you not to use |
Haha, alright, just making sure. But I'm confused -- is that module only for lonely collections? If so perhaps it could be renamed?
|
This module, yes, is only for lonely collections, and, no, I'm not gonna rename it, as it is well documented here: https://github.com/apotonick/representable/#lonely-collections 😝 Using the |
I didn't think that, I was including the module specifically to use |
Maybe we should note in the README that as soon as you want "more" (e.g. hypermedia) in a lonely collection, you should switch to a non-lonely representer? |
Yeah, I think that would make it easier for people to quickly figure out On Wed, Apr 29, 2015 at 11:48 PM, Nick Sutterer [email protected]
|
Hello.
Trying to figure out how to send some arbitrary data on a lonely collection. I tried every which way and it's either overwriting items or just get ignored
Have something like
This works find and produces basic output when I make call to /products.json
However I would like to add some arbitrary attributes to the collection
so right now I get
I'd like to be able to spit out something like this separate items (products) and add meta attributes:
These are just some examples. The idea being that the API responses I'm writing require some extensive meta data included. Right now I'm doing that just using plain old Rails json responses and templates, but would like to switch to roar.
The text was updated successfully, but these errors were encountered: