Ruby on Rails - how to parse this object - ruby-on-rails

I am making a call to a REST API and I get back a bunch of values. I am trying to figure out how to parse them.
Here are the values:
#<User _id: 4f8de8c40a5dcd0d1d00004c, agency_requested: [], encrypted_password: "$2a$10$FPVJDLkkD6AXd5SY/hL6KeuC6QR6vfU3OKI3oGCPxrTiEnAwvGOOu", avatar_file_size: nil, avatar_file_name: nil, agreed_to_terms: ["v1"], location: nil, last_name_first_initial: "Genadinik, A.", first_initial_last_name: "A. Genadinik", legacy_blogger_id: nil, created_at: Tue Apr 17 22:03:50 UTC 2012, active_advertiser_id: nil, avatar_source: :default, agency_roles: [], last_sign_in_ip: "127.0.0.1", confirmation_sent_at: Tue Apr 17 22:03:50 UTC 2012, created_via: "CMPLY-WEB", deleted_at: nil, updated_at: Fri May 11 16:37:16 UTC 2012, last_sign_in_at: Thu May 10 20:48:53 UTC 2012, display_welcome_help: true, program_influencers: [], agency_rep: true, account_type: :influencer, legacy_user_id: nil, sign_in_count: 44, _type: nil, avatar_content_type: nil, programs: [], active_agency_id: nil, account_status: :active, admin_roles: [], legacy_password: nil, gets_newsletter: false, full_name: "Alex Genadinik", last_name: "Genadinik", reset_password_token: nil, current_sign_in_ip: "127.0.0.1", authentication_token: "ViQ5q89n39zyyVUT3wLp", user_name: "me_n0_like_scrennames", time_zone: "Chihuahua", bio: nil, reset_password_sent_at: nil, current_sign_in_at: Fri May 11 16:37:16 UTC 2012, confirmation_token: nil, avatar_updated_at: nil, last_name_first_name: "Genadinik, Alex", agency_id: nil, first_name: "Alex", confirmed_at: Tue Apr 17 22:49:28 UTC 2012, email: "alex#cmp.ly">
How would a parser look like? I am pretty new to Ruby and the stuff returned is kind of difficult to make sense of, so I am not certain how/where to start.
So far I have something like:
begin
// But not sure how to loop through this stuff and extract the values.
end
rescue Exception => ex
# Do something
end
Thanks in advance for the suggestions.

In a rails app, once you have the JSON, you can just do:
decoded_json = ActiveSupport::JSON.decode(json)
decoded_json will be a hash, and you can access the values using the keys from the json, for example:
decoded_json["_id"]
decoded_json["location"]
You could also consider using something like HTTParty to deal with your communications with the RESTful API, as described here:
http://mike.bailey.net.au/2011/02/json-with-ruby-and-rails/

Related

merge 2 array of hashes based on different keys in rails

I have 2 query results one of them is an array of hashes like this
[{"user_id"=>"1", "latlng"=>[#<BigDecimal:7fc67f8412d0,'0.43653226E2',18(36)>, #<BigDecimal:7fc67f840560,'-0.793831843E2',18(36)>], "loc"=>["Toronto", "Ontario", "Canada"]}, {"user_id"=>"2", "latlng"=>[#<BigDecimal:7fc67f84a8f8,'0.43653226E2',18(36)>, #<BigDecimal:7fc67f849d18,'-0.793831843E2',18(36)>], "loc"=>["Toronto", "Ontario", "Canada"]}, {"user_id"=>"3", "latlng"=>[#<BigDecimal:7fc67f848828,'0.43653226E2',18(36)>, #<BigDecimal:7fc67f848210,'-0.793831843E2',18(36)>], "loc"=>["Toronto", "Ontario", "Canada"]}, {"user_id"=>"4", "latlng"=>[#<BigDecimal:7fc67f852620,'0.43653226E2',18(36)>, #<BigDecimal:7fc67f851b30,'-0.793831843E2',18(36)>], "loc"=>["Toronto", "Ontario", "Canada"]}, {"user_id"=>"5", "latlng"=>[#<BigDecimal:7fc67f85ae88,'0.43653226E2',18(36)>, #<BigDecimal:7fc67f85a9b0,'-0.793831843E2',18(36)>], "loc"=>["Toronto", "Ontario", "Canada"]}]
the second is an active record relations object of users,
<ActiveRecord::Relation [#<User id: 4, email: "hello.misc#gmail.com", username: "steve", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 13, current_sign_in_at: "2017-02-18 21:16:17", last_sign_in_at: "2017-01-14 20:32:57", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", confirmed_at: "2016-12-13 01:42:57", confirmation_sent_at: "2016-12-13 01:42:55", unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: "2016-12-13 01:42:55", updated_at: "2017-02-18 22:03:46", slug: "user2", uuid: "xdn5n5z3fmr4", impressions_count: 1, likers_count: 3, lat: #<BigDecimal:7fc67fc39130,'0.0',9(27)>, lng: #<BigDecimal:7fc67fc38c30,'0.0',9(27)>, currently_online: false, status: "unverified", deleted_at: nil>, #<User id: 5, email: "jack#gmail.com", username: "user21", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2017-02-17 02:49:07", last_sign_in_at: "2017-02-17 02:49:07", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", confirmed_at: "2017-02-17 02:49:10", confirmation_sent_at: "2017-02-17 02:49:07", unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: "2017-02-17 02:49:07", updated_at: "2017-02-17 02:49:43", slug: "user21", uuid: "xtffdh2ajnp7", impressions_count: 1, likers_count: 0, lat: #<BigDecimal:7fc67fca6758,'0.0',9(27)>, lng: #<BigDecimal:7fc67fca5ec0,'0.0',9(27)>, currently_online: false, status: "unverified", deleted_at: nil>]>
What I want to do, is to merge the first array of hashes into the activerecord relations based on the foreign key of the first array,
so if the first array has an user_id of 3, i want to insert that hash into that active record of the user with an ID of 3 on the active record object.
I came up up with this
index = a1.group_by{|entry| entry["id"]}
i2= a2.map{|entry| (index[entry.id] || []).reduce(entry, :merge) }
but its not merging them together at all.. what am I doing wrong?
edit: Not all of the first array is relevent, I only want to selectively get the item from the first array based on whats returned in the active record collection of the second query
edit2: I am not looking to save the data back, I just want to merge the data set to display it back in a view template.
If you use Array#map or collect on the collection, you're going to end up with an array instead of an ActiveRecord collection, which may not be what you want.
You could add virtual attributes to the User model and then iterate over the collection:
# app/models/user.rb
attr_accessor :latlon, :loc
users.each do |user|
if location = location_array[user.id.to_s]
user.latlon = location['latlng']
user.loc = location['loc']
end
end
This probably won't be very efficient, but for a small paginated dataset it might not be a big deal.
Another option would be to use a decorator pattern, which acts like a wrapper around your user object. In this case you would add your location attributes to the decorator rather than injecting them into the collection. Have a look at the Draper gem for a good overview.
If I understood you correctly, you can do something like this:
# users is an array of ActiveRecord::Relation
# extra_data is the hash
users.each do |user|
# .detect basically will return an object (first appearance) or nil
data = extra_data.detect{|d| d["user_id"].to_i == user.id}
if data.present?
user.lat = data["latlng"][0]
user.lng = data["latlng"][1]
# if you want to attach "loc", add a attr_accesor :loc in your Use model
# user.loc = data["loc"]
end
end
If you want to know more about detect method, read the docs.

Duplicate found queries on Json data - postgress

am having issues in running queries on data which i have been provided,
if i do Camera.first get the results as
#<Camera id: 6, created_at: "2013-12-12 17:30:32", updated_at: "2015-11-19 10:19:33", exid: "dublin-rememberance-floor2", owner_id: 4, is_public: true, config: {"snapshots"=>{"jpg"=>"/onvif/snapshot"}, "external_http_port"=>8105, "external_host"=>"89.101.225.158", "auth"=>{"basic"=>{"username"=>"admin", "password"=>"mehcam"}}}, name: "My Camera", last_polled_at: "2015-11-27 15:01:51", is_online: false, timezone: nil, last_online_at: "2014-05-01 09:45:39", location: "0101000020E6100000875341A08E0A19C0D6BB896BC6AC4A40", mac_address: nil, model_id: 6, discoverable: false, preview: nil, thumbnail_url: nil>
I am totally unaware about how to get the query run CONFIG object.
example: I want to select all the Cameras list which have same
"external_http_port"=>8105, "external_host"=>"89.101.225.158"
but they are in Config Object.
You can write query like following for json data fetch:
Camere.where("config->> 'external_http_port' = ? and config->> 'external_host' = ?", 8105, '9.101.225.158')

How to change the object view in paper_trail

I have used paper_trail gem for auditing in the application i am developing. I am able to manage most of its features and i was able to display the data in versions table to the user. In doing so the data in object attribute of the versions table is some what unreadable. How can i make it be readable?
Here is my sample output of the object attribute:
version.object retrieves in the following format in a single cell:
--- budget_year: '2014' name: bbb reference_number: j789789 requesting_unit: '798789' quarter: II source_of_fund: Government budget_type: Recurrent procurement_method: Open Bidding procurement_level: National estimated_cost: 4455.0 currency: '4545' purchase_request_id: start_at: 2014-07-30 end_at: 2014-07-31 created_at: 2014-07-24 08:29:38.000000000 Z updated_at: 2014-07-24 08:29:38.000000000 Z id: 1
You could use reify method to see your data like,
> i=Invoice.last.versions.last
=> <PaperTrail::Version id: 158, item_type: "Invoice", item_id: 115, event: "update", whodunnit: "3", object: "---\nid: 115\ncreated_at: 2015-02-05 06:43:17.278448...">
:038 > i.object
=> "---\nid: 115\ncreated_at: 2015-02-05 06:43:17.278448000 Z\nupdated_at: 2015-02-05 06:43:17.278448000 Z\nentity_type: Site\nentity_id: 928\ninvoice_id: WS/14\nuser_id: \nperson_id: \nstatus: 0\nperson_email:\nentity_value:\naddress: ''\nprice: '666'\ndetails: '{\"domain\"=>\"\", \"package\"=>\"23\", \"site_id\"=>\"928\", \"user_id\"=>\"394\", \"years\"=>\"1\"}'\norder_id: '464'\nnorder_type: \nyear: 1\npayment_type: cash\naccount_type: \ncheque_name: ''\ncomment: \ntax: \ncomments: 'Customer made payment by cash with receipt Nos: 041 & 042.'\ncheque_number: \nchequenumber: ''\npayment_level: \ninvoice_type: \n"
> i.reify
=> <Invoice id: 115, created_at: "2015-02-05 06:43:17", updated_at: "2015-02-05 06:43:17", entity_type: "Site", entity_id: 928, invoice_id: "WS/14-15/D-2119", user_id: nil, person_id: nil, status: 0, address: "Near So...", price: "4999", details: "{\"domain\"=>\"\", \"package\"=>\"23\", \"site_id\"=>\"928\", ...", order_id: "464", order_type: nil, year: 1, payment_type: "cash", account_type: nil, cheque_name: "", comment: nil, tax: nil,, cheque_number: nil, chequenumber: "", payment_level: nil, invoice_type: nil>
or
> PaperTrail.serializer.load(i.object)
=> {"id"=>115, "created_at"=>2015-02-05 06:43:17 UTC, "updated_at"=>2015-02-05 06:43:17 UTC, "entity_type"=>"Site", "entity_id"=>928, "invoice_id"=>"W", "user_id"=>nil, "person_id"=>nil, "status"=>0, "person_email"=>"rium#gmail.com", "entity_value"=>"u.com", "address"=>"li ", "price"=>"4999", "details"=>"{}", "orr_id"=>"655", "processed_by"=>"", "order_type"=>nil, "year"=>1, "payment_type"=>"cash", "account_type"=>nil, "cheque_name"=>"", "comment"=>nil, "tax"=>nil, "comments"=>"Customer made payment by cash with receipt Nos: 041 & 042.", "cheque_number"=>nil, "chequenumber"=>"", "payment_level"=>nil, "invoice_type"=>nil}
second way will give the form of hash.

Ruby on Rails: more verbose tests

This test keeps failing and I don't know why:
test "correctly formatted profile_name2" do
user = User.new(first_name: 'Jim', last_name: 'Johnson', email: 'jim#teamtreehouse.com', password: 'awfawwf', profile_name: "jimmy")
puts user.errors.inspect
assert user.valid?
end
I tried to find out by that puts user.errors.inspect statement, but I get back an array (I think) that simply lists database input rather than precisely what's failing.
For clarification:
<ActiveModel::Errors:0x00000103c8ad30 #base=#<User id: nil, first_name: "Jim", last_name: "Johnson", profile_name: "jimmy", email: "jim#teamtreehouse.com", encrypted_password: "$2a$04$LTOb5O.gG0DEITsb/HDOb.fPLP83LaXzKlEerwCDE1og...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, authentication_token: nil, created_at: nil, updated_at: nil>, #messages={}>
In future tests, what statements are used in tests to print to screen explicitly what's going wrong?
Instead of outputting more verbose information within your tests, it might also help to set the TESTOPTS argument to get verbose output when you run your tests.
For example you would set it like this:
rake test TESTOPTS="-v"

Attributes of an Object

There is function of attributes_name in Active record by which I can check the keys of an object but I can check the blank keys for of an object which is of MongoID not of ActiveRecord,
When I try this I got the following response
ruby-1.9.2-p290 :001 > u = User.new
=> #<User _id: 4e684f7771393161cc000001, _type: nil, username: nil, first_name: nil, last_name: nil, email: nil, password: nil, password_salt: nil, password_hash: nil, profile_picture: nil, facebook_id: nil, facebook_enabled: nil, facebook_access_token: nil, twitter_id: nil, twitter_enabled: nil, twitter_access_token: nil, twitter_access_secret: nil, points: nil, remember_token: nil, remember_token_expires_at: nil, active: false, activation_code: nil, activated_at: nil>
ruby-1.9.2-p290 :002 > u.attributes.keys
=> ["active", "_id"]
It only show the attributes which are not nill , How can I check all the attributes even which are nil ?
I actually wanted to make function which needs to use user.attributes.keys.include?('name')
Probably you want fields. Attributes is more or less related to what you got from db, fields is what you defined in your model. Following works for me:
User.fields.keys
User.first.fields.keys
User.attributes.keys
worked with me but you can try columns
User.columns.map(&:name)
To get the keys in the same order as the columns in the db I used this on Rails 3.2 Ruby 1.8.7:
User.content_columns.collect{|c| c.send(:name)}
my particular use was achieved from a variable with an array of objects
#objects.first.class.content_columns.collect{|c| c.send(:name)}

Resources