Rails: disable root in JSON only for specific controller actions?

I know how to disable the root element globally, aa Rails 3.1 include_root_in_json or using ActiveRecord::Base.include_root_in_json = false , but I want to do this only for a few JSON (not globally).

So far I have done it like this:

 @donuts = Donut.where(:jelly => true) @coffees = Coffee.all @breakfast_sandwiches = Sandwich.where(:breakfast => true) dunkin_donuts_order = {} dunkin_donuts_order[:donuts] = @donuts dunkin_donuts_order[:libations] = @coffees dunkin_donuts_order[:non_donut_food] = @breakfast_sandwiches Donut.include_root_in_json = false Coffee.include_root_in_json = false render :json => dunkin_donuts_order Donut.include_root_in_json = true Coffee.include_root_in_json = true 

There are about 5 cases where I have to do this, sometimes with more than one model, and it does not feel clean. I tried putting this in around_filter s, but exceptions upset the flow and it also got hairy.

There must be a better way!

+6
source share
2 answers

The answer, unfortunately, is yes and no.

Yes, what you have done above may perhaps be done better. No, Rails will not allow you to add a root for each action. JSON rendering just wasn't built with that kind of flexibility in mind.

Saying this is what I will do:

  • Set include_root_in_json to false for those models that have a root depending on the action (for example, Donut and Coffee above).
  • Override as_json to provide more flexibility. Here is an example:

     # in model.rb def as_json(options = nil) hash = serializable_hash(options) if options && options[:root] hash = { options[:root] => hash } else hash = hash end end 

    In this example, this is done so that you can optionally pass root, but by default it does not have a root. You can alternatively write this in another way.

  • Since you overloaded as_json , you will have to modify the rendering calls accordingly. So for Donut you would do render :json => @donut.to_json .

Hope this helps!

+2
source

You can set include_root_in_json for each model instance , and this will not affect the class (see class_attribute in the rails api for a description of this behavior). That way, you can set a reasonable default value at the class level, and then set a different value for each instance in the respective controllers.

Example:

 @donuts = Donut.where(:jelly => true).each {|d| d.include_root_in_json = false } 

For convenience, you can create a utility method that takes an array of model instances and sets a value for all of them.

+1
source

Source: https://habr.com/ru/post/896263/


All Articles