Rails: JSON attribute is handled as a method. No method error - ruby-on-rails

I am having problems accessing the attributes of my JSON data. Instead of accessing the JSON data it thinks it is a function.
#response = HTTParty.get('http://localhost:4000/test')
#json = JSON.parse(#response.body)
#json.each do |pet|
MyModel.create(pet) ! WORKS
puts "my object #{pet}" ! WORKS
puts "my object attribute #{pet.myattribute}" ! DOES NOT WORK
end
With no MethodError myattribute.
Thank you for any help!

You may be used to JavaScript, where both object.some_key and object["some_key"] do the same thing. In Ruby, a hash is just a hash, so you have to access values via object["some_key"]. A Struct in Ruby is similar to a JavaScript object, in that you can access values both ways, but the keys have to be pre-defined.

#json = JSON.parse(#response.body) returns a hash, so you would need to do
puts "my object attributes #{pet['id']}, #{pet['title']}"
you might want to convert to HashWithIndifferentAccess so you can use symbols instead of quoted strings, i.e.
#json = JSON.parse(#response.body).with_indifferent_access
# ...
puts "my object attributes #{pet[:id]}, #{pet[:title]}"

Related

Converting ActiveRecord results to json in transaction script

I've seen a number of posts on this but none of the solutions seem to be working for this application. I have a transaction script, CreateContact, which returns a success object when added to the database:
class CreateContact < TransactionScript
def run(params)
contact = Contact.create(params)
return success(contact: contact)
end
end
Here's my test code:
require 'spec_helper'
describe CreateContact do
it_behaves_like('TransactionScripts')
let(:script) {CreateContact.new}
it "creates a contact" do
contact = CreateContact.run({:name=>'contact1', :email=>'me#email.com', :phoneNum=>'1234567'})
expect(contact.success?).to eq(true)
expect(contact.name).to eq('contact1')
expect(contact.email).to eq('me#email.com')
expect(contact.phoneNum).to eq('1234567')
end
end
I've tried several ways of parsing to a hash or JSON: splitting apart the params hash in Contact.create, adding ".to_json" and "JSON.parse" to the success object value, calling both on the entire success object, and calling '.to_a.map(&:serializable_hash)'. I've also tried converting the test code properties between the '.property', '[:key]', and '['property']' formats. '['property']' is the only one that seems to return anything, but it only returns "property" (instead of a value).
When running the tests I can actually see that the ActiveRecord object is created successfully, and some of these techniques will parse if I call them in binding.pry, but when I try to implement them in the code the tests still turn up nil values. Can anyone see what I'm doing wrong?
To convert an ActiveRecord object to a JSON-like Hash, you can use the as_json method from the Active Model JSON Serializer:
hash = contact.as_json
#=> {"id"=>1, "name"=>"contact1", ...}
You can then access the contents of the hash with hash["attribute"]. However, you will not be able to call hash[:attribute] or hash.attribute:
hash["name"] #=> "contact1"
hash[:name] #=> nil
hash.name #=> NoMethodError: undefined method `name' for {}:Hash
If you want to add that behavior to the hash you can build an OpenStruct from the hash:
hash2 = OpenStruct.new(contact.as_json)
hash2["name"] #=> "contact1"
hash2[:name] #=> "contact1"
hash.name #=> "contact1"
If you just need the JSON as an actual String, use to_json:
json = contact.to_json
#=> "{\"id\":1,\"name\":\"contact1\",...}"

Dynamically creating hash key name in Rails 4

Is it possible to dynamically create key names of a hash? I'm passing the following hash parameters:
params[:store][:store_mon_open(5i)]
params[:store][:store_mon_closed(5i)]
params[:store][:store_tue_open(5i)]
params[:store][:store_tue_closed(5i)]
.
.
.
params[:store][:store_sun_open(5i)]
params[:store][:store_sun_closed(5i)]
To check if each parameter exists, I'm using two arrays:
days_of_week = [:mon, :tue, ..., :sun]
open_or_closed = [:open, :closed]
But, I can't seem to figure out how to dynamically create the params hash (the second key( with the array. Here's what I have so far:
days_of_week.each do |day_of_week|
open_or_closed.each do |store_status|
if !eval("params[:store][:store_#{day_of_week}_#{store_status}(5i)").nil
[DO SOMETHING]
end
end
end
I've tried a bunch of things including the eval method (as listed above) but rails seems to dislike the parentheses around the "5i". Any help is greatly appreciated!
You should be able to do
if params[:store]["store_#{day_of_week}_#{store_status}(5i)".to_sym]
Note that you were missing the ? on .nil? and that !object.nil? can be shortened to just object
Assuming this is a HashWithIndifferentAccess, you should be able to access it via string just as you could with a symbol. Thus:
days_of_week.each do |day_of_week|
open_or_closed.each do |store_status|
key = "store_#{day_of_week}_#{store_status}(5i)"
unless params[:store][key]
# DO SOMETHING
end
end
end
If it's not a HashWithIndifferentAccess then you should just be able to call key.to_sym to turn it into a symbol.

Vaccum hash from xml throws Null pointer in code, but renders fine in json

I am using vaccum to fetch product details from Amazon Product Advertising API.
req = Vacuum.new
req.configure(key: configatron.api.amazon.productAPI.key,
secret: configatron.api.amazon.productAPI.secret,
tag: 'biz-val')
regex = Regexp.new "http://([^/]+)/([\\w-]+/)?(dp|gp/product|exec/obidos/asin)/(\\w+/)?(\\w{10})"
productID=regex.match(#url).captures[4];
host=regex.match(#url).captures[0];
utype=regex.match(#url).captures[2];
#url="http://#{host}/#{utype}/#{productID}"
params = { 'Operation' => 'ItemLookup',
'ItemId' => productID,
'ResponseGroup'=>'Large'
}
res = req.get(:query => params)
hsh=Hash.from_xml(res.body)
#details=hsh
item=hsh[:ItemLookupResponse][:Items][:Item]#Throws an Undefined method [] for nilClass
You can ignore the regex parsing. I have checked it works fine.The hash that is generated from res.body is a valid hash, it shows up fine in the json rendered(#details), but throws a nilClass thing when I try to access it in the code.
I think thi might be becausehsh[:ItemLookupResponse] returns something other than a hash. I am not sure what it is returning though. How do I access :Items ?
If it says you are trying to call [] on a NilClass then it is highly likely that you are. On that particular line you call [] on these three
hsh
hsh[:ItemLookupResponse]
hsh[:ItemLookupResponse][:Items]
So one of them is, again highly likely, to be nil. You might want to use debugger/repl and put a breakpoint right before the erring line and examine hsh. I use pry, with which you woud first require 'pry' and then put binding.pry where you want the breakpoint.

Deserialize ActiveRecord from JSON

I would like to save query result into redis using JSON serialization and query it back.
Getting query results to json is pretty easy:
JSON.generate(Model.all.collect {|item| item.attributes})
However I did not find a proper way to deserialize it back to ActiveRecord. The most straight-forward way:
JSON.parse(#json_string).collect {|item| Model.new.from_json(item)}
Gives me an error:
WARNING: Can't mass-assign protected attributes: id
So id gets empty. I thought of just using OpenStruct for the views instead of ActiveRecord but I am sure there is a better way.
You could instantiate the new object from JSON and then assign the id afterwards. Probably best to create your own method for this:
class Model
def self.from_json_with_id(params = {})
params = JSON.parse(params)
model = new(params.reject {|k,v| k == "id"})
model.id = params["id"]
model
end
end
Or maybe just override the from_json() method.
Why not like this:
JSON.parse(#json_string).each do |item|
item.delete(:id) # I tested it in my case it also works without this line
object=Model.create(item)
end
If the host that created the JSON adds a JSON root you might have to use item[1] instead of item.

How to use two different params hashes in one page (Rails)

Hi
I want to use two params hashes in one page
The job of this page is straightforward, it's an edit page, and I want it to send out notifications to a server once the editing job is done.
def update
#description = Tempdescription.find(params[:id])
#description.update_attributes(params[:tempdescription])
sendnotification
end
def sendnotification
params[:to_ids]="xxxx"
sig = hash_params(params);
params[:sig] = sig
response = RestClient.post "http://api.xxxx.com/restserver.do", params, :content_type => :json, :accept => :json
render :text=>response
end
def hash_params(params)
params = Hash[*params.sort.flatten]
payload = ''
params.sort.each do |pair|
key, value = pair
payload = payload + "#{key}=#{value}"
end
return Digest::MD5.hexdigest(payload + API_SECRET)
end
Not surprisingly the params in sendnotification also includes params used for updating
and the server returns 104 error
Therefore,
I tried
new_params=Hash[]
and use new_params to replace the old params in sendnotification
But then rails complains
undefined method `<=>' for :session_key:Symbol
app/controllers/tempdescriptions_controller.rb:72:in `<=>'
app/controllers/tempdescriptions_controller.rb:72:in `sort'
app/controllers/tempdescriptions_controller.rb:72:in `hash_params'
app/controllers/tempdescriptions_controller.rb:45:in `sendnotification'
So I am thinking if there is any way I can create another params?
Thanks in advance
Ok, having complained about your formatting I suppose I should hazard an attempt at your problem.
This code:
def hash_params(params)
params = Hash[*params.sort.flatten]
payload = ''
params.sort.each do |pair|
key, value = pair
payload = payload + "#{key}=#{value}"
end
return Digest::MD5.hexdigest(payload + API_SECRET)
end
.. appears to accept a hash as its argument and then recreate it with the keys sorted. Presumably this code is targeted at ruby 1.9 otherwise that would be rather pointless. It then sorts again for no reason I can determine before joining the keys and values with = but without separating the pairs with &.
The error is a little mysterious though; I have no trouble sorting symbols with ruby 1.9. Perhaps you're running ruby 1.8?
Ok...after playing with rails console for a while I finally find a solution to this problem.
In sendnotification method I created a new hash
p=Hash[]
but simply putting this will not work, as I mentioned before.
Then I changed all
p[:key]
to
p["key"]
and it works.
Obviously Hash#sort doesn't work with hash[:key] if the hash is newly created but it works with params and that's what puzzled me and made me believe there is a difference between params and normal hash.
I am using Ruby 1.8.7 so I think it might just be a bug of this version.

Resources