jBuilder ignore_nil! site wide? - ruby-on-rails

I'm working on a Rails API using jBuilder and want to exclude null from all my JSON objects.
jBuilder has the following method:
def ignore_nil!(value = true)
#ignore_nil = value
end
How and where can I override this method to be true for everything? This would make much more sense and be more maintainable than going through every json view I have and adding it.

JBuilder doesn't provide one place to specify :ignore_nil option. You can look at JbuilderHandler class in jbuilder_template.rb for more details.

If anyone else stumbles upon this:
JBuilder.ignore_nil true
will set the default value of ignore_nil to true everywhere.
You could (assuming you are using rails) just put this in an initializer.

Related

Rails common method for updating a database field

I am new to rails and I have a task to write a common method that will update a specific database field with a given value. And I should be able to invoke the method from anywhere in the app.(I understand about the security flaw and so on.. But I was asked to do it anyway) In my application controller I tried
def update_my_model_status(model,id,field, value)
#model = model.find(id)
#model.update(field: value)
end
Of course this doesn't work.. How to achieve this? What is the right way to do this? And if it is possible how to pass a model as an argument to a method?
If you're using Rails, why not use Rails?
Compare update_all:
MyModel.where(id: 1).update_all(banned: true)
or maybe update_attribute:
my_model.update_attribute(:banned, true)
to:
update_my_model_status(MyModel, 1, :banned, true)
Notice how, despite being shorter, the first two approaches are significantly more expressive than the last - it is much more obvious what is happening. Not only that, but they are immediately more familiar to any Rails developer off the street, while the custom one has a learning curve. This, combined with the added code from the unnecessary method adds to the maintenance cost of the application. Additionally, the Rails methods are well tested and documented - are you planning to write that, too? Finally, the Rails methods are better thought out - for example, your prototype naively uses attribute validations, but does not check them (which could result in unexpected behavior) and makes more SQL queries than it needs to. It's fine to write custom methods, but let's not write arbitrary wrappers around perfectly fine Rails methods...
Try this:
def update_my_model_status(model,id,field, value)
#model_var = model.capitalize.constantize.find(id)
#model_var.update_attributes(field: value)
end
Instead of just using update you should use update_attributes:
def update_my_model_status(model,id,field, value)
#model_var = model.find(id)
#model.update_attributes(field: value)
end
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update

How to deal with Money in Rails and Mongoid

I know this question has been asked before, but most answers I've found are related to ActiveRecord or old (most cases, both) and I was wondering whether there's a new take on this.
Is short, my Rails app is an API, so please keep this in mind (can't normally use lots of helpful little view related helpers).
I've been reading about this and found the MoneyRails which seems quite neat. The problem I'm having with it is that when I retrieve the data, it returns an object instead of the an usable value:
class MyModel
include Mongoid::Document
...
field :price_GBP, type: Money
...
end
So to create the document I send a number and it created the document fine. Now when I query the same document it returns an object for price_GBP, which is fine, but my main grip is that it return the value fractional as in my_obj.price_GBP[:fractional] as a string rather than a number.
I'd rather not have my client to have to do the conversion fro string to number than to decimal.
I guess I could create a little helper that would convert the value in such circumstances like so (in my Model):
def my_helper
self.price_GBP = BigDecimal(self.price_GBP) # or something along those lines
end
Then in my controller:
#my_model = Model.find(id)
#my_model.price_GBP = #my_model.price_GBP = #my_model.my_helper
render json: #my_model
With the above in mind, would this be the best approach? If yes, what's the point of using the MoneyRails gem then?
Secondly, if not using the MoneyRails gem, should I use BigDecimal or Float as the field type?
When I tried BigDecimal, the data was saved ok, but when I've retrieve it, I got an string rather than a number. Is this the correct behaviour?
When I tried Float it all worked fine, but I read somewhere that Float is not the most accurate.
What are your thoughts?
Avoid using Float if you're planning on performing any type of arithmetic on the currency values. BigDecimal is good or you can also represent the value in cents and store it as an Integer. This is actually how the Money gem works.
My recommendation would be to continue to use the MoneyRails gem and use the built-in helpers to output the values. You mentioned not being able to use the helpers but I don't see what's preventing that - Rails includes jbuilder which allows you to formulate your JSON structure in a view with access to all "helpful little view related helpers" - for example
# app/views/someresource/show.json.jbuilder
# ...other attributes
json.price_GBP = humanized_money(#my_model.price_GBP)

RABL: change default date and time format to iso8601

I'm using rabl 0.11.6 for my API, and I find myself doing the following over and over again for every date or time object:
node :created_at do |article|
article.created_at.iso8601
end
It would save a lot of code duplication, if the format for every date object could be set in one place, so that I just could use the attributes method like this
attributes :created_at
I found an issue on github (https://github.com/ccocchi/rabl-rails/issues/68) where they suggest, overwriting some Oj.default_options = { mode: :compat, time_format: :ruby } in an initializer. But I have no idea how to do a .iso8601.
Then I found this one https://gist.github.com/astevens/b80225d96d8889c946ac. But it looks like a hacky monkey patch solution.
And finally I found this issue https://github.com/nesquena/rabl/issues/336 where they overwrite the as_json method from ActiveSupport::TimeWithZone, also a very monkey-patch solution.
Is there no way to tell RABL what date and time format to use? And if not, what would be the best / least-hacky method to achieve this?
FWIW I fixed this problem in rails 4.2.8, Rabl 0.13.1 and OJ 2.18.5
Add a initializer with the following..
Oj.default_options = {:use_as_json => true}
As crazy as it sounds, this fixes it by changing the JSON serializer:
bundle add oj

ActiveModelSerializer with Sinatra

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

Use underscores instead of dashes with ActiveResource XML (set :dasherize to false)

I am hitting all kinds of walls trying to stop rails from replacing XML underscores with dashes. I'm doing a post to a web service using ActiveResource. I have tried all kinds of variations of fixes for this, with results varying from rails initialization errors to just no effect. The web service I am posting to requires underscores.
Essentially, if I can get the following in place, I should be good:
From http://rubydoc.info/docs/rails/2.3.8/ActiveResource/Base
:dasherize - Boolean option to determine whether or not element names should replace underscores with dashes. Default is true. The default can be set to false by setting the module attribute ActiveSupport.dasherize_xml = false in an initializer.
Can someone provide an example of this? I'm unfortunately on a tight timeline, so if someone can provide assistance that would be a huge help.
Thanks!
Did you attempt to set the module attribute to false in an initializer?
ActiveSupport.dasherize_xml = false
for rails 3+ you can use the following within your response:
render :xml => object.to_xml(:dasherize => false)
See edit history for ugly monkeypatching approach.

Resources