I've got a bunch of serializers. Now I'd like to turn the JSON back into the original objects for testing. I don't see a way to do that with ActiveModel::Serializers. Looks like there used to be an from_json method that was deprecated. How are you supposed to do this?
Basically I want to test the round tripping like this:
json = WidgetSerializer.new(#widget).to_json
testw = Widget.new
testw.from_json(json) #from_json doesn't exist in ActiveModel::Serializers
#widget.should == testw
But the "from_json" method on the model doesn't properly read the json from the serializer because its not in the expected format
The best I can think of is using either Widget.find() or Widget.find_by(), depending on the attributes you pass to your serializer (and especially if one of them is a unique attribute)
For example if your serializer includes id (the simplest in your case) :
json = WidgetSerializer.new(#widget).to_json
target_id = JSON.parse(json)[:id]
test_widget = Widget.find(target_id)
#widget.should == test_widget
Related
On an individual Active Model Serializer you can specify the cache key within your serializer, i.e.
Caching a single object using AMS
class OrgSerializer < ActiveModel::Serializer
cached
delegate :cache_key, to: :object
end
Array caching
I need to deliver an array of these objects:
array_json = ActiveModel::ArraySerializer.new(Org.all.limit(50)).to_json
Rather than do 50 cache hits to construct the array I want to do a single cache hit and expire it when any of the array elements expires.
How to cache the array (and construct the key)?
I therefore want a cache key for the array that is made up of the individual object IDs and their last-updated at date like this:
def cache_key_for_collection collection
keys = collection.collect{|element| "#{element.id}#{element.updated_at}" }
keys.join ""
end
How can you do this with AMS (0.8)?
Does the AMS array serializer allow for this or is it something that needs to just be done manually? Is there a way to declare that you want caching and how the key should be constructed?
If it doesn't do it then what would be the neatest way to manually construct the cache/key?
It works very similarly to standard Serializers. You will create a custom ArraySerializer that looks something like this:
class BaseArraySerializer < ActiveModel::ArraySerializer
cached
def cache_key
keys = object.map{|obj| "#{obj.id}-#{obj.updated_at.to_s(:number)}" }
keys.join "/"
end
end
The one thing to note is that you are still doing object.map instead of objects, but this is purely how AMS 0.8.0 is implemented.
Then to deliver the json the only change you would have to make is:
array_json = ActiveModel::ArraySerializer.new(Org.all.limit(50)).to_json
I am using an API and receiving a array of hashes. Lets say:
array = client.getObjects(123) //where 123 is some collection of object ID
I want to add some additional attributes to the array to use later in my view, like:
<%= array.getRequestor %> // return a string
What is the easiest way to do this? I was thinking about creating a new class that extends array but I wanted to know can I just add a string "requestor" attribute a lot easier?
Thanks
Extending a core class is not a good idea in general, especially when the additional responsibilities you want to add in are specific to your functional domain.
6 months down the line, somebody (perhaps yourself) will be trying to debug the code and wondering why does Array expose a random custom method.
It would be better to explicitly define your custom view object, perhaps by using a Struct, eg:
# my_view_object.rb
class MyViewObject < Struct.new(:hash)
def getRequestor
# manipulate / return specific hash data
end
end
# controller
#view_obj = MyViewObject.new(client.getObjects(123))
# view
#view_obj.hash # original hash
#view_obj.getRequestor # your custom attribute
Note that the intent of a Struct is to represent a custom data structure, not behaviour. If your custom method needs to do unrelated work, you might want to use a PORO (Plain Old Ruby Object) instead.
I'd say that extending Array sounds like a really bad idea. I would suggest you instead wrap the array in hash of your own. For example
my_hash = {getRequestor: ?, array: array}
and then use it like
<%= my_hash.getRequestor %>
as in your example code.
I'm trying to dynamically append a relational object to it's associated object using the send method. For example:
car = Car.first
tire = Tire.first
car.send('tires<<', tire)
But I always get method undefined. I realize in this simple example it's not necessary to use send, but in my case it is. Any help appreciated, thanks.
There is no tires<< method, there is a << method defined on object returned by tires. Try:
car.send('tires') << tire
I am using ASP.Net Web API with JSON.Net to serialize. I had to configure the serializer to handle ISO dates properly like this:
var iso = new IsoDateTimeConverter {
DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffK"
};
GlobalConfiguration.Configuration.Formatters.JsonFormatter
.SerializerSettings.Converters.Add(iso);
This works fine when I am passing my objects down via the WebAPI. My problem, however, is that I have another place where I want to explicitly call the serialization:
#Html.Raw(JsonConvert.SerializeObject(Model));
In this case, it doesn't use the configuration I set up. I am aware that I can pass the iso converter into the SerializeObject call, but I prefer to avoid this and get a hold of a configured serialzer for obvious reasons.
Any ideas?
If you're going to do JSON serialization yourself, you have to pass the settings you want explicitly. There's no way around it. The best I can think of if you want to reuse the same serializer settings is to do something like this:
JsonConvert.SerializeObject(Model, GlobalConfiguration.Configuration.Formatters.
JsonFormatter.SerializerSettings)
I have a Rails application with the backbone-rails gem. Which works out fine but Backbone tries to send a request with all the attributes of the model. Is there a way I can filter out some of the attributes that will be POST'd on an update/new? This would work great for those virtual attributes and attributes that can't be mass assigned.
There is no harm in posting attributes that cannot be mass assigned. You will see a warning, but everything will work.
There are basically two ways of actually removing unwanted attributes. The first is to customize the Model's toJSON(). For example:
myModel = Backbone.Model.extend({
function: toJSON() {
var json = _.clone(this.attributes);
delete json.somethingIdontWant
delete json.somethingElse
return json
}
})
The second, and less clean way, is to explicitly pass the data in your call to Model.save(). If you are using the default Backbone.sync() method, then this data will be used instead. For example:
mything.save({
data: {just: "the stuff", that: "i want to post"}
})
You can probably figure out a way to generalize either of those approaches, depending on which one works for you.