ActiveModelSerializer with Sinatra - ruby-on-rails

Can I use active_model_serializers with Sinatra? If not, is there any better way for json output in Sinatra for building a web service?

Yes, you can. However, the design and architecture of AMS is strongly focuses on ActiveModel instances, therefore if you don't use an ActiveModel-based library (such as Mongoid, ActiveRecord, etc) the choice may be overkill.
Still, the approach reflects the common Presenter pattern applied to JSON serialization. You can easily create your own simple library to extract the attributes you define from an object you pass.
Sinatra also provides some JSON serialization extensions. What they do by default, is to call as_json. That's not the best approach, it is not extremely flexible, but you can combine those two elements to create your own solution, or start from scratch.

You can, includes a json.rb inside the lib folder with the following piece of code and do require this file on your application.rb .
# lib/json.rb
module Sinatra
module JSON
def json(object, options={})
serializer = ActiveModel::Serializer.serializer_for(object, options)
if serializer
serializer.new(object, options).to_json
else
object.to_json(options)
end
end
end
end
To use just do
get '/foo' do
json Foo.find(params[:id])
end
get '/bar' do
json Bar.find(params[:id]), { scope: self }
end

I used to_json to return JSON output from Sinatra API's. It turns out that there are dozens of JSON gems for Ruby, of varying efficiency.
One approach is to create list of attributes for each object that you want to render to JSON. For example, if your User has an image that you don't want to render, you could create a blacklist for the User class:
JSON_BLACKLIST = [ 'image' ]
Then, when you render the JSON, you can call:
user.attributes.reject{|a| JSON_BLACKLIST.include?( a )}.to_json

Related

Rails Neo4j.rb Serializers?

In Active node how we can implement JSON serializers like active modal
http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html
Or any other way to send customized API response?
Right now I am doing it by making custom method in controller in which response is made after iterations (no. of records)
posts.map{|x| serialize_post(x) }
def serialize_post (post)
{
id: post.id,
name: post.name
}
end
The ActiveNode gem is based off of ActiveModel, so you should be able to simply call to_json on it with all of the arguments that that supports. You should also be able to define as_json and from_json methods:
http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html
Separately, I'm also a big fan of the JSON API standard, so for that you might want to check out the jsonapi-serializers gem
Edit:
Active model serilaizer Gem also fulfill the purpose
https://github.com/rails-api/active_model_serializers

When and how is it useful to dynamically add a method to a Ruby object?

I have been trying to learn Ruby from 'The Well-grounded Rubyist' and I came across the idea of adding methods to an object at run-time:
obj = Object.new
obj.respond_to? "hello" # Returns false
def obj.hello
puts "something"
end
obj.respond_to? "hello" # Returns true
obj.hello() # Output is "something"
I have a background in Python and Java, and I cannot imagine any way for me to use this new idea. So, how is this useful? How does it fit into the spirit of object-oriented programming? Is it expensive to do this at run-time?
There's always a long list of things you can do in any language but shouldn't do without a good reason and extending a single object is certainly high on that list.
Normally you wouldn't define individual methods, but you might include a bunch of them:
module Extensions
def is_special?
true
end
end
obj = Object.new
obj.send(:extend, Extensions)
obj.is_special?
# => true
ActiveRecord from Rails does this to dynamically create methods for models based on whatever the schema is at the time the Rails instance is launched, so each column gets an associated method. This sort of dynamic programming can be used to make the code adapt seamlessly to a changing environment.
There's a lot of cases where you'll want to spell this out explicitly so your methods are well documented, but for cases where it doesn't matter and responding dynamically is better than maintaining two things, like schema and the associated methods in your code, then it could be the best option.

Serialize/De-serialize objects via HTTP, Ruby (no ROR)

There is already similar question to this but I am not satisfied with answers since I am trying to do something more complex.
I have web service which provides list/single objects. Objects are Users, Categories, etc. Here is example of object:
<UserObject name="foo" description="bar" category=<Category name="cat1" description="bar"> locations=[<Location id=1>, <Location id=2>] >
In other words objects are somewhat complex and can be arrays of those objects. I am looking for a way to:
Serialize these object to JSON or Hash string
Send them over HTTP
Deserialize them to OpenStruct objects
Service that is serializing objects is not ROR.
App that is receiving and deserializing objects is ROR.
There must be some generic way to do this, I tried using to_json and JSON.parse but it only de-serializes object to one level. So for example above I would get:
<OpenStruct name="foo" description="bar" category="{\"name\"... JSON STRING}" locations="JSON STRING">
Instead of JSON STRINGs I would like to get objects inside object as it was in original.
Ruby: 1.9.3
Thanks
Take a look at the oj gem. It allows you to serialize and deserialize ruby objects to and from json. It also has the benefit of being very fast.
After looking into oj gem and contacting it's creator Peter Ohler, who was very nice and helped, I was able to get desired effect.
require 'oj'
# user instance is nested instance
json_string = Oj.dump user
# send over http
# de-serialize without domain classes (classes created by Oj gem)
user = Oj.load(json_string, { :auto_define => true })
Thanks to #josh-voigts for letting me know about the gem.

How can I get YAML::load to call const_missing?

I am serializing an object to a database field using ActiveRecord's :serialize functionality in Ruby on Rails
class DrawElement < ActiveRecord::Base
...
serialize :content
end
The reason I'm serializing the objects is that I'm dynamically loading the types from disk using const_missing, so I don't have to setup database tables for them.
def DrawElement.const_missing(const)
require File.join('draw_elements',const.to_s)
draw_class = const_get(const)
return draw_class if draw_class
raise "Draw Element not found #{const.to_s}"
end
So when I want to add a draw element, I do something like this in irb
draw_element.content = DrawElement::Text.new
Everything here works fine
The problem is that when I try to load the object from the database in a fresh session, YAML::load never calls const_missing to require the class definition before loading the file. So all my #content objects come back as YAML::Object
Is there a better way to do this? I'm trying to be able to add new types without having to change the database, or have a has_many_polymorph relationship between DrawElements and a Document.
Ruby on Rails v.2.3.8, Ruby v. 1.8.7
From my experience YAML::load returns a hash. It's up to me to walk through the hash and do something with its contents. Neither load or load_file accept a block to get inside them and influence how the YAML document is parsed.
You could try messing with load_documents or each_document though, because they take a block, but I don't know if you could add additional hash elements that way.

Generate ruby classes from json document

Consuming a ruby json API, I want to save me some work and generate ruby objects off the bat. Any way to do this?
so you could transform this:
{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}
to this:
class Menu
attr_accessor :id
attr_accessor :file
attr_accessor :popup
end
If you're looking to turn a JSON string into a Ruby Hash you can do
my_hash = JSON.parse('{"foo":"bar"}')
puts my_hash['foo']
There is a wonderful gem for doing this. https://github.com/apotonick/representable/
Here's what your representable would look like
module MenuRepresenter
include Representable::JSON
property :id
property :value
property :popup
end
Create your model
class Menu
attr_accessor :id, :value, :popup
end
menu = Menu.new.extend(MenuRepresenter).from_json(json)
# You can convert it back into json via .to_json
# expect(menu.to_json).to eq(json)
The example above shows only the basic implementation, you would want to create another class for the menu item, take a look at the documentation at the github repo for more detailed information.
If you want "methodized" hashes which use accessor methods (not a bad idea at all!)
require "ostruct"
object_like_hash = OpenStruct.new(some_hash_with_string_or_symbol_keys)
object_like_hash.foo #=> same as some_hash["foo"]
Nonexistent keys will return nil and not raise unfortunately.
I think you are a little bit confused. In the question, you ask how to turn a JSON document into classes. In the comments, you say you want a JSON version of the RXSD XML tool, which however, turns XML schemas into Ruby classes.
Turning JSON documents into classes doesn't really make sense. If you compare the world of document markup to programming, documents correspond to objects and schemas correspond to classes (well, types, actually, but since we're talking about Ruby, let's not open that can of worms and stick with classes).
So, it makes sense to generate Ruby objects from JSON documents and it makes sense to generate Ruby classes from JSON schemas, but it doesn't make sense to generate Ruby classes from JSON documents. The bad news is of course that in order to be able to automatically generate Ruby classes from JSON schema is that in order for that to work, the JSON schema has to be in an automatically processable (IOW machine-readable) format.
Unfortunately, there is no such thing as a JSON schema, and thus JSON schemas tend to generally not be machine-readable, but rather are just a blurb of human-oriented English text on the API documentation page of the web service provider. If you're lucky. More often than not, there is no documentation at all about the JSON schema.
So, since there is no standardized way of describing JSON schemas, there cannot be a standardized tool for processing JSON schemas. Unlike XML, where there is a limited number of standardized schemas (DTD, XSD, RelaxNG).
Note that what I wrote above is not strictly true: there are specifications for JSON schemas (e.g. JSON-Schema) and there are Ruby implementations of those (e.g. Ruby/JSONSchema, validation only, doesn't generate classes), but nobody is using them, so they might just as well not exist.

Resources