I have model called location with one enum location _type. My model implemented like below
class Location < ActiveRecord::Base
enum location_type: [:Offshore, :Onsite]
end
This work correctly for mapping insertion and display. But now i want an action to give the enum as json for binding to the drop down in the client side. Please help me to do this
Edit:
Now i read this articles expected like this only. But i just copt and created Enum class and LocationType class in the lib directory (with out any module nmae). But how i do this in controller action. I got NameError. My controller is
class Api::V1::LocationsController < Api::V1::BaseController
def get_location_types
Rails.logger.warn(LocationType.values)
#respond_with Location.location_types.to_json
end
Related
I want to modify existing data class, by moving one of its parameters into second data class and I wonder what's the best way to handle it, without loosing the data already stored using the old data class. Data is stored using Json serializer and app has mechanisms for updating data stored in databases on app's update.
Here's example:
Currently used data class
#Serializable
#Parcelize
data class AlarmInfo (
val volume: Int
(...)//other fields
) : Parcelable
Data classes to be used after app's update
#Serializable
#Parcelize
data class AlarmInfo (
val ringtoneInfo: RingtoneInfo
(...)//other fields
) : Parcelable
#Serializable
#Parcelize
data class RingtoneInfo (
val volume: Int
(...)//other fields
) : Parcelable
Is there a way to retrieve AlarmInfo.volume stored value, when AlarmInfo class after update doesn't have this field anymore?
I know I can do it ugly way, by keeping the AlarmInfo.volume in the new class and copy its value to the RingtoneInfo.volume on app's update, but it doesn't feel right to keep this field forever after this one update.
Any suggestions?
Is there maybe some annotation I could see to have the volume field deserialized, but named differently in the class? Something like:
#CleverAnnotation(name="volume") val dontUse: Int?
I am not aware of any annotation that would do that for you, except GSON's (and other parsers' equivalent) #SerializedName
E.g.:
#SerializedName("name")
var userName: String
Keep in mind if you use Proguard, you need to tell it to keep the model class, or it may be obfuscated into something else. Of course, that's only a GSON annotation for the purpose of serialization and deserialization.
Other than that, you could hide the field behind a function or get() like
#Deprecated(
message = "This field is deprecated and will be removed in future versions",
replaceWith = ReplaceWith("newField"),
level = DeprecationLevel.WARNING
)
var oldField: String? = null
var newField get() = oldField
(all pseudo code, you get the idea).
Or similar ideas...
I am trying to build a generic CRUD interface that receives an element, searches for an implicit CRUD implementation from an evidence and also serialize the necessary object based on the parametrized type.
The code goes as follow:
private def createElement[T <: AnyRef](element: String)
(implicit ev: ResourceManager[T], m: Manifest[T]): Response = Try {
val e = Serializer.fromJson(element, m.runtimeClass)
ev.create(e, persistence)
ResponseBuilder.newBuilder().status(202).build()
}.getOrElse(ResponseBuilder.newBuilder().status(412).build())
As you can see. I receive a String, an evidence of a ResourceManager that implements the create method and a Manifest. When trying to serialize i make sure that the T type is of AnyRef but that is not the issue.
The problem is that m.runtimeClass returns Class[_] instead of Class[T].
My question is, if manifest does do what i want, how can i do this without explicitly passing the class name or whatever?
Thank you!
The problem is as follows: I want to handle a POST request with JSON body. The body consists of an array of JSON Objects, without further nesting, i.e. simple HashMaps. All of these objects represent JSON-serialized domain classes from an Android Application, which will have their counterpart in my Grails app. I am thinking of parsing the JSON body, iterating through every element and saving each node as its corresponding domain class instance.
a) How should I save the instance? I am quite new to Grails/Groovy so please excuse any huge mistakes. Code so far is
public static Object JSONArray2Instances(String json, Class type) {
def slurper = new JsonSlurper()
def result = slurper.parseText(json)
//we only want to parse JSON Arrays
if (!(result instanceof JSONArray))
return null
result.each {
def instance = it.asType(type)
// now I need to save to domain class!
}
}
b) where do I place the corresponding code? Currently it is in /grails-app/src/groovy. Where do the tests go? (Since it is not a 'real' Grails component)
c) Is an intermediate command object more appropriate?
Your code should go in to the controller which is handling the request. Please take a look at
gson-grails plugin which has examples of how to serialize and deserialze objects and map them to domain objects. Please take a look at the grails basics where they talk about the conventions used in the grails application and the layout. There are good examples at grails site. Hope this helps
I solved my problem as follows, based on help provided by the comment from allthenutsandbolts. : (Grails-Gson plugin was not needed)
Let N2696AdminAction be the name of a Domain Class
in my controller:
class N2696AdminActionController extends RestfulController{
static responseFormats = ['json', 'xml']
def JSONHandlerService
N2696AdminActionController() {
super(N2696AdminAction)
}
#Override
#Transactional
def save(){
if (request!=null)
JSONHandlerService.instancesfromJSON(request.JSON)
}
}
then I delegate persisting to my service as follows
class JSONHandlerService {
def instancesfromJSON(Object request){
//we only want to parse JSON Arrays
if (!(request instanceof JSONArray))
return null
request.each {
def domainClass = Class.forName("${it.type}",
true, Thread.currentThread().getContextClassLoader())
def newDomainObject = domainClass.newInstance(it)
newDomainObject.save(failOnError:true, flush:true, insert: true)
}
}
}
type is a Json attribute which holds the full (package inclusive) name for my class. This way, I can save to multiple Domain Classes with the same POST request.
I'm scala newbie and come from a Ruby background so and am having trouble rendering json response in my web service for which I use scalatra, mongodb with liftweb mongo record and argonaut for JSon serialisation and deserialisation.
However based on the examples given at http://argonaut.io/ I'm unable to figure out how this would work when using the net.liftweb.mongo.record library.
On compiling this i get a error which says a type mismatch. The error description follows the code snippet.
package firstscalatraapp
import org.scalatra
import net.liftweb.mongodb._
import net.liftweb.mongodb.record.MongoRecord
import net.liftweb.mongodb.record.field.ObjectIdPk
import net.liftweb.record.field.StringField
import net.liftweb.record.field.IntField
import net.liftweb.record.field.PasswordField
import net.liftweb.record.field.DateTimeField
import net.liftweb.mongodb.record.MongoMetaRecord
import argonaut._
import Argonaut._
case class Person private extends MongoRecord[Person] with ObjectIdPk[Person] {
def meta = Person
object age extends IntField(this, 3)
object name extends StringField(this, 29)
object created_at extends DateTimeField(this)
object password extends PasswordField(this)
}
object Person extends Person with MongoMetaRecord[Person] {
implicit def PersonCodecJson: CodecJson[Person] =
casecodec3(Person.apply, Person.unapply)("name", "age", "things")
}
The Error i get is
[error] found : () => firstscalatraapp.Person
[error] required: (?, ?, ?) => ?
[error] casecodec3(Person.apply, Person.unapply)("name", "age", "things")
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
which seems logical because the constructor does not accept any parameters and the mongo library seems to be generating the val for the fields that i need for the class (I still don't fully understand what the lift mongo wrapper does yet).
So how do i define the implicit to be able to find serialise an object of type person.
Also how do I define serialisation capabilities when i'm dealing with collections. For instance when I have a List[Person].
Thanks in advance. I would really appreciate any help i can get on this.
I'm just about to start using Argonaut so I'm no expert on that but with that said your initial problem seems obvious.
casecodec3 needs a constructor and a deconstructor for the class you're defining the codec for. In the examples of Argonaut they're using case classes and these have automatically generated companion objects with apply/unapply for the fields defined. Which for casecodec3 needs to be 3. In your case, the case class is of zero-arity - you have no case class fields at all. The fields of the record are defined as inner objects with their own apply-methods (very imperative stuff). That's just the way lifts records are defined. So your apply method is just () => Person.
casecodec3 wants a function from a 3-tuple to Person and from Person to a 3-tuple. I would suggest skipping the case definition if you're going to use lift record. And create functions on the side instead. Something like:
object Person extends Person with MongoMetaRecord[Person] {
implicit def PersonCodecJson: CodecJson[Person] =
casecodec3(parse, serialize)("name", "age", "things")
// Something like
def parse(name: String, age: Int, things: Something) = {
val p = Person.createRecord
p.name(name)
...
}
def serialize(p: Person) = (p.name.get, p.age.get, p.things.get)
}
As for your other questions I think you can head back to argonaut.io again. Their documentation seems quite alright - maybe it was worse when you posted this question as it is kind of old?
I'm going to try to replace all my serialization from lift-json to argonaut right now so if you're still stuck (probably not) I might be able to answer better in a bit.
I have a class that is not an ActiveRecord object and im trying to create a AM serializer for it. I can return the proper json, but its not including a root
in have this in my controller
format.json { render json: #current_user, root: "current_user" }
and my class looks like this
class CurrentUser
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :first_name, :last_name, :user_type, :user_id
end
Ive also tried adding this in the controller
def default_serializer_options
{root: true}
end
But still my json object does not have the root which I need for Ember Model
return object
{"first_name":"Luke","last_name":"Skywalker","user_type":"Padawan","user_id":12}
and I need
{current_user: {"first_name":"Luke","last_name":"Skywalker","user_type":"Padawan","user_id":12} }
For anyone in the future who may come across this same problem,
when using ActiveModelSerializers 0.10.x, just add to an existing initializer or create a new one and add this to include the root node in your responses:
config/initializers/serializer.rb:
ActiveModel::Serializer.config.adapter = :json
AMS documentation states that this is not backwards compatible for versions 0.9.x and 0.8.x.
If using default_serializer_options inside your controller doesn't work, maybe you should have a look into config/initializers/wrap_parameters.rb for include_root_in_json option.
If you are curious, concerned source code for that option can be found here.