Render a sum attribute with Active Model Serializer or as JSON - ruby-on-rails

The default code I have is Lab.all and it renders perfect json when I just Lab.all.to_json like so
{"id":1,"lab_id":1,"test_id":2,"price_cents":20000,"duration":null,"created_at":"2016-02-26T14:40:40.825Z","updated_at":"2016-02-26T14:40:40.825Z"}
I have the following scope:
#lab_tests = LabTest.group(:lab).sum(:price_cents) and it returns the following as json :
{"#\u003cLab:0x007f8e0a44afa8\u003e":20000}
How can I make it render json like so:
{"id":1,"lab_id":1,"test_id":2,"price_cents":20000,"duration":null,"created_at":"2016-02-26T14:40:40.825Z","updated_at":"2016-02-26T14:40:40.825Z", "price_cents":200000 }
I've tried added a .select parameter to my scope, but even that does not change anything.

Related

#<FastJsonapi::MandatoryField: id is a mandatory field in the jsonapi spec>

When trying to pass an enum object to serializer I get the following error:
#<FastJsonapi::MandatoryField: id is a mandatory field in the jsonapi spec>
#drop_down_values = Organisation.ownerships
where #drop_down_values has the enum values from ownership column.
render json: DropDownValueSerializer.new(#drop_down_values).serialized_json
I figured out that FastJsonAPI expects object id by default. Hence, when passing object to serializer it expects id to be present in the object passed.
'https://github.com/Netflix/fast_jsonapi/issues/100' this has been logged as an issue in FastJsonAPI.
The below works properly:
render json: DropDownValueSerializer.new(Organisation.first).serialized_json

How to always return a JSON array for single result in Ruby On Rails?

What is the easiest or anticipated way to always return a JSON array from a API controller in Ruby On Rails?
Let's say I've the following controller action:
def index
render json: Entry.all.includes(:user).to_json(include: :user) if current_user.has_role?(:administrator)
render json: Entry.find_by(user: current_user).to_json(include: :user)
end
A list of entries is returned. Sometimes the result is only one entry, so to_json() doesn't create a JSON array but a JSON object instead.
This complicates everything like API documentation and implementation in the clients, because we have to test for empty results, single results and array results.
How is it possible to always return a JSON array here?
Stack: Ruby 2.5.3; Rails 5.2.2
Try changing this
render json: Entry.find_by(user: current_user).to_json(include: :user)
to
render json: Entry.where(user: current_user).to_json(include: :user)
find_by returns an object, whereas where an ActiveRecord::Relation

Convert field from integer to string in one rails Active Record relation before sending json

In my Rails 4 app, I actually send an active record relation in JSON with:
[...]
wine['varietals'] = record.varietals
#wines << wine
format.json { render :json => { :success => "OK", :items => #wines } }
[...]
wine['varietals'] is an array of AR relations. My problem is the varietal model contains a field named grape_id that is an integer. I need to send it in string for my WS. I don't want to make a custom conversion to JSON just for this field.
How to force this field to be string before the automatic JSON conversion ? If possible I don't want to make an array of hashes and keep the AR style with dot: model.field
wine['varietals'].each do |varietal|
varietal.grape_id.to_s
end
Of course this doesn't work.
All Rails models have an as_json method that gets called when rednering the model to JSON. You can override this method within your models to set up custom JSON formatting. In your case, you may want to add something like this to your Wine model:
def as_json(opts = {})
json = super(opts)
json["grape_id"] = self.grape_id.to_s
json
end
The method gives you the default model JSON when you call the super method and set it to the json variable, then stringifies grape_id and sets it in the JSON, and finally returns the updated JSON.
Now, any time a controller returns a JSON version of single Wine model, or an association of multiple Wine models, the JSON will be formatted through this updated method and the grape_id will be stringified every time.

rails: how to add custom json to json output

Whats the easiest way of adding custom json output when you render json? I've seen people override as_json or to_json but they usually exclude attributes or include associations. Is there a way of including plain text?
in my view:
def show_json
show_id = URI.decode(params[:id])
show_id = show_id.gsub(/\s*$/,'')
logger.debug "\nshow json: #{show_id}\n"
#qtls = Qtl.find_by_sql("select * from qtls where qtl_name like '%#{show_id}%' or qtl_symbol in (select qtl_symbol from obs_traits where qtl_symbol like '%#{show_id}%' or trait_name like '%#{show_id}%');")
render :json => #qtls
end
this returns something like:
[{qtl: {...qtl attributes..}},{... more qtls }]
and I would like to add a a specific field for each qtl. Whats best way to do that?
override as_json or use some gem to provide many json templates for example https://github.com/fabrik42/acts_as_api

Deserialize ActiveRecord from JSON

I would like to save query result into redis using JSON serialization and query it back.
Getting query results to json is pretty easy:
JSON.generate(Model.all.collect {|item| item.attributes})
However I did not find a proper way to deserialize it back to ActiveRecord. The most straight-forward way:
JSON.parse(#json_string).collect {|item| Model.new.from_json(item)}
Gives me an error:
WARNING: Can't mass-assign protected attributes: id
So id gets empty. I thought of just using OpenStruct for the views instead of ActiveRecord but I am sure there is a better way.
You could instantiate the new object from JSON and then assign the id afterwards. Probably best to create your own method for this:
class Model
def self.from_json_with_id(params = {})
params = JSON.parse(params)
model = new(params.reject {|k,v| k == "id"})
model.id = params["id"]
model
end
end
Or maybe just override the from_json() method.
Why not like this:
JSON.parse(#json_string).each do |item|
item.delete(:id) # I tested it in my case it also works without this line
object=Model.create(item)
end
If the host that created the JSON adds a JSON root you might have to use item[1] instead of item.

Resources