Rails JSON API - json doesn't contain errors - ruby-on-rails

I am rendering an array of ActiveRecord items. Each of them has passed through valid? method - so the errors are already defined.
I render the array like this:
render json: array_of_objects
I have ActiveModelSerializers.config.adapter = :json_api set.
But the outcome json lacks errors - it contains only the data of objects.
How can I retrieve json (of each one by one or all at once) items with the errors included?

The JSON API specification is very fuzzy when it comes to how validation errors should be handled:
A server MAY choose to stop processing as soon as a problem is
encountered, or it MAY continue processing and encounter multiple
problems. For instance, a server might process multiple attributes and
then return multiple validation problems in a single response.
When a server encounters multiple problems for a single request, the
most generally applicable HTTP error code SHOULD be used in the
response. For instance, 400 Bad Request might be appropriate for
multiple 4xx errors or 500 Internal Server Error might be appropriate
for multiple 5xx errors.
Error objects can be included - but they should be included at the top level of the document:
Error objects provide additional information about problems
encountered while performing an operation. Error objects MUST be
returned as an array keyed by errors in the top level of a JSON API
document.
ActiveModel::Serializers JSON API Adapter does not provide error object handling as it would be far to complex to handle the various use cases.
Especially your case as you seem to be creating/modifying several records at once. In the case of creating its especially tricky since you need to link the error to the attribute in the input that caused the error since there is no id to point to.
You can possibly roll your own serializer:
class PostSerializer < ActiveModel::Serializer
attributes :title, :body, :errors
def errors
object.errors.full_messages if object.errors.any?
end
end

Related

Rails: Serialization of custom class for flash messages

I can't seem to figure out how flash messages in RoR insist on being serialized for the next page view. When setting a simple type to e.g. flash[:notice], all is well to get it across to the next page view. When I however try and set the value of flash[:notice] to a custom class, it serializes only the properties:
flash[:notice] = Info.notice("Content...", "Title")
... equates to ...
{"type"=>"notice", "content"=>"Content...", "title"=>"Title"}
... which has no knowledge of the class it serialized. One solution I found was to use .to_yaml before doing a redirect, and then use YAML.load at the later step, but I don't find that viable.
So my question is, how would I be able to make sure that it automatically serialize this object, to properly be deserialized at a later stage?
Rails: 4.2.5.1,
Ruby: 2.2.4p230
Thanks

Not showing data with react.rb

I'm just trying to use ReactRB with reactive-record.
So the deal is in render part I think. When I'm setting param :user, type: User in React Component class, I can't see any data in my table. Of course Model User in public folder, as this requirement in ReactRB.
Well, in console I see that server is fetching nothing, but right data returned.
What I'm missing? Thanks for the help!
The key for answer is in this screenshot
The details are that the data comes back from the server as a json blob
reactive-record decodes it, but counts on the fact that if you try to json parse a simple string, it raises an error.
opal 0.10 no longer raises standard error, so the whole thing just hangs up.
Just thinking about this... there is a known problem in Opal https://github.com/opal/opal/issues/1545 and this causes a problem in reactive-record. Please make sure that you are not using opal 0.10
One thing to keep in mind is that reactive-record lazy loads records, and attributes. So unless someplace in your render, you access a particular record/attribute that attribute will not show up on the client.
Its hard to tell more without a bit more of your code posted, but here is some help:
Lets say your component looks like this:
class Foo < React::Component::Base
param :user, type: User
def render
"user.name = #{user.name}"
end
end
and someplace either in a controller or in a layout you do this:
render_component '::Foo', {user: User.first}
You might try something very simple like this, just to get familiar with how things work.
What happens should be this: You will render your view and a placeholder for the first User will be sent to the component, during rendering the component looks for that user's name attribute, which it does not have, so that is queued up to fetch from the server. Rendering will complete, and eventually the data will come down from the server, the local model's data will be updated, and components displaying that data will be rerendered.
During prerendering all the above happens internal to the server, and when the component has been rendered the final html is delivered along with all the model data that was used in rendering the component. So on first load if all is working you will not see any fetches from the server.
So if you try out the above small example, and then go into your javascript console you can say things like this:
Opal.User.$first()
and you will see the underlying model data structure returned (I am translating from JS into ruby above... ruby methods all start with $)
You can then do this:
Opal.User.$first().$name()
And you can even do this (assuming there are at least 2 user models):
Opal.User.$find(2).$name()
You should have something like "DummyValue" returned, but then there will be a server fetch cycle in the console, then if you repeat the above command you will get back the actual value!!!
This may not be the best forum for more details, if you need to drop by https://gitter.im/reactrb/chat for more help

JSON date string parse error in Rails

I've got a large data model in a Rails application that I'm trying to make serializable and output to JSON. I defined the #serializable_hash method on the model and blacklisted a few attributes. My goal is to whitelist attributes on the controller layer to accept back that same structure and simply ignore values that I don't want "accessible".
One such attribute is giving me trouble when I PUT update with the aforementioned JSON. I get an error while parsing request parameters:
SyntaxError (/Users/brad/.rvm/gems/ruby-1.9.3-p194#project-rails32/gems/actionpack-3.2.13/lib/action_dispatch/http/request.rb:261: syntax error, unexpected tINTEGER, expecting $end
...02933", "software_date"=>"09/05/14", "software_version"=>"10...
... ^):
# stack trace...
As far as Rails is concerned, this is just a string right? Why is it expecting an end of input here? For the record, taking this attribute out before submitting my request results in a successful update, so I'm sure this is what's causing the issue.
Turns out I'm the unluckiest guy in the world.
Familiarize yourself with Ruby's %Q() method, and you'll understand where I'm at.
Under my very very specific case, when Rails is parsing params for a request:
in JSON format
which has a key mapping to an Array
and any value under that Array contains a '/'
the parse will fail. Why?
My version of Rails (3.2.13) uses the AwesomePrint library version 0.3.2 when parsing out parameters for the params hash. The #grep method for that version of the gem evaluates matches using:
%Q/#{match}/
Simply because the specified delimiter is a '/', the evaluation fails and parsing crashes. DO NOT LET THIS HAPPEN TO YOU.

Mongoid: getting mongo error code from Moped::Errors

I'm building a Rails server with the model stored in MongoDB using Mongoid.
There are cases where a user can attempt to add a document to the mongo database with a duplicate index value. Is there a way to retrieve the MongoDB error code (in this case 11000) without parsing the error message so that I can make my exception handling more robust?
EDIT: Title had Mongoid::Errors instead of Moped::Errors
I developed the mongoid_token gem and encountered this exact problem, since the core functionality of this gem relies on being able to identify if a particular field (in this case, the token) is the cause of the key duplication.
If all you're after is the error code, the yes - you can get this. However, if you need more precise details (such as the field name), you will need parse the error description.
Also, if you're testing for duplicate keys, I think you'll need to check for both error codes 11000 and 11001 (duplicate key on update). A partial list of the mongoDB error codes is here.
I've paraphrased some of the code from the gem below:
begin
#... do whatever
rescue Moped::Errors::OperationFailure => e
description = e.details['err']
if [11000, 11001].include?(e.details['code'])
# Duplicate key error
end
end

Delayed Job object not properly deserialized

I'm having a hard time believing what I'm seeing, but it sure looks like DJ is failing to deserialize an object properly. I look at the DJ record in mongo and I see in the YAML that the object has its text field set, but when the code runs, the text field is not set. Here is some minimal repro code:
class Board
include Mongoid::Document
field :text, type: String
def process_text_field
if not self.text
raise "Text field is blank"
end
# Text field gets processed
end
end
# in a controller
def start_doing_something_slow
board = Board.find(params[:id])
board.text = "Text field is set"
board.save!
raise "Text disappeared!" unless board.text
board.delay.process_text_field
render json: {:result=>'ok'}
end
I invoke the controller method with the browser, and check the DJ record directly in mongo. I see in the YAML that the Board object has the text field correctly set. But when it executes in DJ, it raises the Text field is blank exception.
Somehow it's not deserializing the object properly.
Well this took me about a week to figure out, so I'm posting it here to help others who fall into this trap. Turns out this is a known bug in delayed_job_mongoid. And it's had a simple fix listed right there in the bug report for 10 months.
The problem arises if you use the identity map in mongoid, which acts as an in-process caching layer to the database. For normal web requests, the cache gets cleared between each request, so your controller methods don't use stale versions of the objects. But delayed_job_mongoid doesn't clear the cache between jobs without this patch (which I just put together): https://github.com/collectiveidea/delayed_job_mongoid/pull/38
The result is your delayed jobs are sometimes using old versions of the objects, depending on what ran before them, which creates truly bizarre, mysterious failures that are extremely difficult to track down until you understand what's happening.

Resources