Is there an ActiveRecord setting that will allow me to remove null values before serializing ActiveRecord objects into json?
If not, what's the best way to do this?
Thanks
You can override serializable_hash method inside your model
def serializable_hash(options)
super(options).select { |_, v| v }
end
By the way, if you are going to use include (e.g. Project.all.as_json(include: :tasks)) then you need to override serializable_hash in both models.
UPDATE: Version 0.10+
def serializable_hash(adapter_options = nil, options = {}, adapter_instance = self.class.serialization_adapter_instance)
super(adapter_options, options, adapter_instance).select { |_, v| v }
end
Maybe
#instance.attributes.delete_if { |k, v| v.nil? }.to_json
Related
I have an array of nested hashes that looks something like this:
[{"month"=>1,
"percentiles"=>{"25"=>768.06, "50"=>1868.5, "75"=>3043.79, "90"=>4161.6},
"total_revenue"=>1308620.0,
"year"=>2017},
{"month"=>2,
"percentiles"=>{"25"=>922.63, "50"=>2074.31, "75"=>3048.87, "90"=>4018.6},
"total_revenue"=>1105860.0,
"year"=>2017}]
That I would like to flatten into this:
[{"month"=>1,
"25"=>768.06, "50"=>1868.5, "75"=>3043.79, "90"=>4161.6,
"total_revenue"=>1308620.0,
"year"=>2017},
{"month"=>2,
"25"=>922.63, "50"=>2074.31, "75"=>3048.87, "90"=>4018.6,
"total_revenue"=>1105860.0,
"year"=>2017}]
I have been looking and testing different methods with no luck. Any ideas on how to accomplish this? The end goal is to mass update/insert these into a database, so if there is a better way to accomplish that, I would like to see a different approach.
If you don't mind modifying the array in-place then you could say:
array.each { |h| h.merge!(h.delete('percentiles')) }
If you're not sure that all the hashes have 'percentiles' keys then you could say:
# Explicitly check
array.each { |h| h.merge!(h.delete('percentiles')) if(h.has_key?('percentiles')) }
# Convert possible `nil`s to `{ }`
array.each { |h| h.merge!(h.delete('percentiles').to_h) }
# Filter before merging
array.select { |h| h.has_key?('percentiles') }.each { |h| h.merge!(h.delete('percentiles')) }
If you want to flatten all hash values then you can do things like this:
array.each do |h|
h.keys.each do |k|
if(h[k].is_a?(Hash))
h.merge!(h.delete(k))
end
end
end
If you don't want to modify the hashes inside the array then variations on:
flat = array.map(&:dup).each { |h| h.merge!(h.delete('percentiles')) }
flat = array.map do |e|
e.each_with_object({}) do |(k, v), h|
if(v.is_a?(Hash))
h.merge!(v)
else
h[k] = v
end
end
end
I face a problem, I don't know how to arrange the serialize format in rails.
I have models call MissionSet, QuestionSet, Group
The MissionSet will return like this
I want it to become like this, it's really a challenge to me, because I am not familiar with handling this format.
Here's something that will get you started:
x = {}
inp.each do |h|
h['assignments'].each do |k, _|
x[k] ||= []
x[k] << h['question_set_id']
end
end
out = x.map do |key, value|
{
group_id: key,
question_sets: value.map { |v| { id: v} }
}
end
puts out.inspect
This code will first group your questions by the ids in assignments and then format it as you wanted.
def job_ids
{
job_id: r.job_id,
job_2_id: r.job_2_id,
job_3_id: r.job_3_id
}
end
def available_job_id
job_ids.find { |_k, v| v.nil? }[0].to_s
end
im checking which key has the first value of nil,and then i convert it to string.
what's the best way to do it?
This seems to be dirty?
job_ids.find { |_k, v| v.nil? }[0].to_s
UPDATE:
here's the desired output so far...
[79] pry(main)> job_ids.find{|k, v| v.nil?}[0].to_s
=> "job_2_id"
Try this
job_ids.key(nil).to_s
You can just use key
job_ids.key(nil).to_s
#=> "job_2_id"
I have a hash object with the following structure:
{"action1"=>
{"2014-08-20"=>0,
"2014-07-26"=>1,
"2014-07-31"=>1
},
"action2"=>
{"2014-08-01"=>2,
"2014-08-20"=>2,
"2014-07-25"=>2,
"2014-08-06"=>1,
"2014-08-21"=>1
}
"action3"=>
{"2014-07-30"=>2,
"2014-07-31"=>1,
"2014-07-22"=>1,
}
}
I want to sort the hash based on the date and return back a Hash(Not array). The final result should be:
{"action1"=>
{"2014-07-26"=>1,
"2014-07-31"=>1,
"2014-08-20"=>0
},
"action2"=>
{"2014-07-25"=>2,
"2014-08-01"=>2,
"2014-08-06"=>2,
"2014-08-20"=>1,
"2014-08-21"=>1
}
"action3"=>
{"2014-07-22"=>1,
"2014-07-30"=>2,
"2014-07-31"=>1
}
}
Iterate over the hash, and for each value, sort.
h = {"action1"=>
{"2014-08-20"=>0,
"2014-07-26"=>1,
"2014-07-31"=>1
},
"action2"=>
{"2014-08-01"=>2,
"2014-08-20"=>2,
"2014-07-25"=>2,
"2014-08-06"=>1,
"2014-08-21"=>1
},
"action3"=>
{"2014-07-30"=>2,
"2014-07-31"=>1,
"2014-07-22"=>1,
}
}
h.each do |k, v|
h[k] = Hash[v.sort]
end
Here you need to iterate your hash and fetch the value than you need to apply sort_by function on each value so you will get your result
hashName.each do |key, hash|
Hash[hashName.sort_by{|k,v| k}]
end
This is all you need:
h.each { |k,v| h[k] = v.sort.to_h }
#=> {"action1"=>{"2014-07-26"=>1, "2014-07-31"=>1, "2014-08-20"=>0},
# "action2"=>{"2014-07-25"=>2, "2014-08-01"=>2, "2014-08-06"=>1,
# "2014-08-20"=>2, "2014-08-21"=>1},
# "action3"=>{"2014-07-22"=>1, "2014-07-30"=>2, "2014-07-31"=>1}}
Hash#to_h appeared in Ruby 2.0. For earlier versions, use the class method Hash::[]: i.e., replace v.sort.to_h with Hash[v.sort].
I've got paramerers which are sent by a form like:
{ "mac"=>{"0"=>["111", "222"], "1"=>["333", "444"]} }
How can I permit them in a proper way, because I've found just an ugly solution:
params.permit(mac: Hash[(0..100).map { |i| [i.to_s, []] }])
Fetch the keys out of the :mac key and then permit them.
mac_keys = params.fetch(:mac, {}).keys
params.permit(mac: mac_keys)
will you consider the hash's keep_if method, as params is just a hash.
params[:mac].keep_if {|k, v| k.to_i >= 0 and k.to_i <= 100}