0

I am using Rails 4 and got following JSON output from different sources

source1

@something1 =   book.find().to_json

output

"[{\"a\": \"val1\"}]"

source2

@something2 =   Author.where(title: :autitle).pluck(:val2).to_json

Output

"[{\"b\": \"val2\"}]"

source 3

@something3 = Publications.find_by_pub_id(id)

Output

{ 
  "c":"val3",
  "d":" val4"
}

I want the final output like

{
  "a": "val1",
  "b": "val2",
  "c":"val3",
  "d":" val4"
}

I have used merge like

@newval= @something1[0].merge(@something2[0]).merge(@something3)

But, it gives error

undefined method merge!

Those variables are inside index method like

class Test controller < api::controller
  def index
   @something1 = ..
   @something2 = ..
   @something3 = ..
  end
end

Hope it is clear.

6
  • Can you include the complete log/error message? With the provided examples Ursus answer works fine (you can see it in action here), so maybe you are getting different outputs in the @something variables. Commented Aug 8, 2017 at 13:13
  • @Gerry while that example is nice (and functional) maybe we should be clear that the output in the question is inaccurate. JSON is a String and thus the correct output for the first example is actually "[{\"a\":\"val1\"}]". String does not have a merge method which would have been more obvious had the OP posted the full message. e.g. undefined method merge! for "[{\"a\":\"val1\"}]":String editted question for correct output Commented Aug 8, 2017 at 14:44
  • @Khoga remove the to_json calls from the first 2 and add it to the end of the merge chain. See Updated version of @Gerry's repl Commented Aug 8, 2017 at 14:54
  • @engineersmnky You are right, i completely missed (ignored?) the to_json, so now it makes sense. Thank you for claryfing it. Commented Aug 8, 2017 at 15:08
  • @engineersmnky Maybe you should add an answer, yours is the correct solution. Commented Aug 8, 2017 at 15:15

4 Answers 4

2

With no more information this seems enough

@something1[0].merge(@something2[0]).merge(@something3)
{
    :a => "val1",
    :b => "val2",
    :c => "val3",
    :d => " val4"
}
Sign up to request clarification or add additional context in comments.

1 Comment

I have updated my question. Please let me know if you need more info.
1

Your problem here is that JSON is a String thus

@something1 =   book.find().to_json
#=> "[{\"a\": \"val1\"}]"

This will make it far more difficult to deal with when trying to "merge" them together.

The error you are receiving is because String does not have a merge method (Next time please post the full error or at least the object reference) e.g. undefined method merge! for "[{\"a\":\"val1\"}]":String

Luckily the fix is extremely simple just remove to_json from the original 2 calls as such

require 'json'

@something1 = [{"a": "val1"}] # no to_json
@something2 = [{"b": "val2"}] # no to_json
@something3 = { "c": "val3", "d": " val4" } # no to_json

@something1[0].merge(@something2[0]).merge(@something3).to_json
#=> "{\"a\":\"val1\",\"b\":\"val2\",\"c\":\"val3\",\"d\":\" val4\"}"

See Example (based on @Gerry's original commented example)

Since this appears rails like we can probably simplify this whole process if we understood the relation ship between Book, Author and Publication eg.

Book.find().to_json(include: [:author,:publications]) 
# Or 
Book.find().to_json(include: [{author: {only: :name}},:publications])

This will avoid the need to merge as I fear the original example might actually need to be

@something1 =   book.find()
@something2 =   book.author
@something3 =   book.publications

@something1.attributes.merge({author: @something2.attributes,
    publications: @something3.map(&:attributes)}).to_json

Comments

1

You can create a function like:

def mergejson(*args)
  merged = {}
  args.each do |a|
    merged.merge!(a.is_a?(Hash) ? a : a.first)
    # or use .deep_merge! if the hashes can contain nested hashes
  end
  return merged
end

irb(main):025:0> test = mergejson(something1, something2, something3)
=> {:a=>"val1", :b=>"val2", :c=>"val3", :d=>"val4"}

Comments

0

Also worked by:

@something1.first.merge(@something2.first).merge(@something3)

#=>{:a => "val1",:b => "val2",:c => "val3",:d => " val4"}

1 Comment

This is pretty much the same answer as the one provided by Ursus.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.