Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 4 - Remove "created_at" and "updated_at" from render

When I want to remove these datas from one resource I do:

@teams = Team.all

render json: @teams, :except => [:created_at, :updated_at],

My doubt is when I have many includes like these:

@teams = Team.all

render json: @teams, :include => [:stadiums, :scores, :links, :rounds]

How do I remove from all of them?

like image 833
Seralto Avatar asked Jul 22 '14 18:07

Seralto


2 Answers

Correction: You can do something like

render json: @teams.to_json(:except => [:created_at, :updated_at], :include => { :stadiums => { :except => [:created_at, :updated_at]}, ... })

There is no simple way of doing this without iterating over the relevant models, obtaining the attributes hash and selecting the desired attributes.

Such use cases are often solved elegantly using json templating DSLs like jbuilder or rabl.

To illustrate this using jbuilder:

Jbuilder.encode do |json|
  json.array! @teams do |team|
    json.name team.name
    json.stadiums team.stadiums do |stadium|
      json.name stadium.name
      # Other relevant attributes from stadium
    end
    # Likewise for scores, links, rounds
  end
end

Which would produce the output as:

[{
  name: "someteamname",
  stadiums: {
    name: "stadiumname"
  },
  ...
}, {...},...]

If you find this too verbose for your use case, as @liamneesonsarmsauce has pointed out in the comments another solution is to use ActiveModel Serializers

Using this approach you can specify a serializer class for each of your models, listing the allowed attributes which would become a part of json response. For example

class TeamSerializer  < ActiveModel::Serializer
  attributes :id, :name # Whitelisted attributes

  has_many :stadiums
  has_many :scores
  has_many :links
  has_many :rounds
end

You can define similar serializers for associated models as well.

Since associations are seamlessly handled in a way that is already familiar to rails developers, unless you require much customization of the generated json response, this is a more succinct approach.

like image 118
lorefnon Avatar answered Nov 14 '22 13:11

lorefnon


How 'bout adding to models/application_record.rb

# Ignore created_at and updated_at by default in JSONs 
# and when needed add them to :include
def serializable_hash(options={})
  options[:except] ||= []
  options[:except] << :created_at unless (options[:include] == :created_at) || (options[:include].kind_of?(Array) && (options[:include].include? :created_at))
  options[:except] << :updated_at unless (options[:include] == :updated_at) || (options[:include].kind_of?(Array) && (options[:include].include? :updated_at))

  options.delete(:include) if options[:include] == :created_at
  options.delete(:include) if options[:include] == :updated_at
  options[:include] -= [:created_at, :updated_at] if options[:include].kind_of?(Array)

  super(options)
end

then use it like

render json: @user
# all except timestamps :created_at and :updated_at

render json: @user, include: :created_at
# all except :updated_at

render json: @user, include: [:created_at, :updated_at]
# all attribs

render json: @user, only: [:id, :created_at]
# as mentioned

render json: @user, include: :posts
# hurray, no :created_at and :updated_at in users and in posts inside users

render json: @user, include: { posts: { include: :created_at }}
# only posts have created_at timestamp

So in your case, your code remains the same

@teams = Team.all
render json: @teams, :include => [:stadiums, :scores, :links, :rounds]

and yeah, you get them all without :created_at and :updated_at. No need to tell rails to exclude that in every single model, hence keeping the code real DRY.

like image 27
Saravanabalagi Ramachandran Avatar answered Nov 14 '22 12:11

Saravanabalagi Ramachandran