Permitting JSON Array Parameters in Rails - ruby-on-rails

Having a bit of trouble, im trying to permit array parameters and i've seen example of that...however I haven't seen an example where the array is an array of objects and the top level array is one of the main params being pulled in.
Sample JSON:
{
"message_json": {
"device": {
"deviceid": "002"
},
"measurements":
[
{
"temp": 71.45,
"humidity": 31.5
},
{
"temp": 75.34,
"humidity": 35.9
}
]
}
}
Functions for permitting:
def device_params
params[:message_json].fetch(:device, {}).permit(:deviceid)
end
def measurement_params
params[:message_json].fetch(:measurements, {}).permit(:temp,:humidity)
end
So the measurement_params does not work, and I know normally you'd do something like array_obj: [] but this arrays object is already the measurements param thats getting fetched? How would I go about permitting these items?

Did you try something like this:
def measurement_params
params.require(:message_json).permit(measurements: [:temp, :humidity])
end
I am unable test this right now. But I was dealt with this problem and solved with this way.

Related

Rails 4 and returning JSON response: how to correctly append extra data?

I have a SQL query returns some data, here is some sample output:
[
{
"AccountCode": "111123456",
"AccountID": 123456,
"BalanceCurrent": "-8.0",
"Phone": "123456888",
}
]
This is a Hash with an array. There are times when there will be multiple hashes within the array. Just one in this example though.
As stated, this data comes directly from the database.
I have a lookup_phone method in my Customer model that runs the SQL query and then executed in the customer_controller.rb file like so:
customer_phone = Customer.lookup_phone(params[:Phone])
Now, I need to append some extra data to these hash(es) that do not come from the database, like so:
data = [
:match_found => true,
:transfer_flag => false,
:confirm_id => 2
]
This data variable needs to be WITHIN each hash object, not a separate hash object on its own.
Using a simple array concat or + always makes the data a separate hash object. I've come across some good posts saying to use reduce along with merge, but those are Hash methods, not Array methods.
If I try to set data as a Hash instead of an array, I get
no implicit conversion of Hash into Array when I try to do
customer_phone.reduce({}, :merge)
after running customer_phone += data
What is the proper way to append data to an existing Hash object?
maybe combine each and merge
base = [
{
"AccountCode": "111123456",
"AccountID": 123456,
"BalanceCurrent": "-8.0",
"Phone": "123456888",
}
]
data = {:match_found=>true, :transfer_flag=>false, :confirm_id=>2}
base.each { |el| el.merge!(data) }
#=> [{:AccountCode=>"111123456", :AccountID=>123456, :BalanceCurrent=>"-8.0", :Phone=>"123456888", :match_found=>true, :transfer_flag=>false, :confirm_id=>2}]
You can add attr_accessor to your Customer model like this
class Customer
attr_accessor :data
end
With your data array:
data_array = [
:match_found => true,
:transfer_flag => false,
:confirm_id => 2
]
Then, you can execute the query combined with each function:
customer_phone = Customer.lookup_phone(params[:Phone]).each {|e| e.data = data_array}
Access it:
customer_phone.first.data
To render json:
render json: customer_phone, methods: [:data]

Whats the proper logic and way to save JSON data that has a nested array

I figured this out the answer is below
So say I have something like this JSON POST coming in:
{
"contact":{
"first_name": "Bill",
"last_name": "Clinton",
"phone_numbers":[
{
"name": "blah",
"number": "555-555-5555"
},
{
"name": "blah2",
"number": "555-555-5555"
}
]
}
}
Forgive me for the crappy formatting of the JSON.
Anyway, I want to save this into my DB. The Rails controller will be taking care of this. Now
I am a bit tired but I am unsure how to handle this since there is a nested array.
Please Help.
So I have a contacts table which a has a phone_number_id field. phone_number table has name and number fields
Current attempt until I realized I have a nested array:
#phone_number = Phone_Number.new
#phone_number.contact_id = #contact.id
#phone_number.name = #params[:phone_number_name]
Here is The solution I came up with
if #contact.save
#params[:phone_numbers].each do |counter|
#phone = PhoneNumber.new
#phone.contact_id = #contact.id
#phone.name = counter[:name]
#phone.number = counter[:number]
#phone.save
end

Stripe_ruby Unable to store card_last4 and card_type after successful customer creation

After creating a customer successfully, I can inspect the object with:
Rails.logger.debug("single card object has: #{customer.cards.data.card.inspect}")
which returns a json like this:
#<Stripe: : Customer: 0x2801284>JSON: {
"id": "cus_2WXxmvhBJgSmNY",
"object": "customer",
"cards": {
"object": "list",
"data": [
{
"id": "card_2WXxcCsdY0Jjav",
"object": "card",
"last4": "4242",
"type": "Visa",
"exp_month": 1,
"exp_year": 2014,
}
]
},
"default_card": "card_2WXxcCsdY0Jjav"
}
But I will do Customer.cards.data.last4 it gives a NOMethodError.
If I remove the last4 and just call Customer.cards.data, it gives
#<Stripe: : Card: 0x1ed7dc0>JSON: {
"id": "card_2Wmd80yQ76XZKH",
"object": "card",
"last4": "4242",
"type": "Visa",
"exp_month": 1,
"exp_year": 2015,
}
Now I seem to have the direct card object but if I do
card = Customer.cards.data
self.last4 = card.last4
I still get a noMethodError
Here is shortened version of my model:
class Payment < ActiveRecord::Base
def create_customer_in_stripe(params)
if self.user.stripe_card_token.blank?
user_email = self.user.email
customer = Stripe::Customer.create(email: user_email, card: params[:token])
card = customer.cards.data
self.card_last4 = card.last4
self.card_type = card.type
self.card_exp_month = card.exp_month
self.card_exp_year = card.exp_year
self.user.save
end
self.save!
end
end
customer.cards, as the name implies, returns multiple cards in an array.
You can't call card accessor methods because you don't have a Stripe::Card object; you have an array of Stripe::Card objects. You need to either call customer.cards.first (the most likely answer) or iterate over the array for a specific card you're looking for.
Once you have a Stripe::Card object, all the accessor methods will work correctly.
cself.card_last4 = card.last4 should be self.card_last4 = card["last4"] as the gem itself doesn't have a last4 method when searching on github. I know i have to use Hash syntax.
I have a feeling that all of your methods on card will need this syntax.
EDit:
So it sounds like your model's last4 column is an integer, do card["last4"].to_i or change the migration to a string column in the DB.
card = Customer.cards.data
self.last4 = card[0].last4
how do you get the default active card in
rails "default_card": "card_2WXxcCsdY0Jjav" in the list of customer.cards?
is there a better way rather than to loop thru customer.cards to get it or even easier way?
Any pointers?
Hope this help someone who is wondering as well :- )
default_active_card = customer.cards.data.detect{|obj| obj[:id] == customer.default_card}

Merge two JSON with a matching ID in Rails

I got two JSON that are structured like this. First one comes from an API:
[
{
"course_code":"Basic 101 - 0913",
"name":"Basic 101",
"start_at":"2013-09-16T00:00:00+02:00",
"end_at":"2013-10-13T23:55:00+02:00",
"workflow_state":"available"
},
{"course_code":"Medium 201 - 0913",
"name":"Medium 201",
"start_at":"2013-08-06T16:55:25+02:00",
"end_at":null,
"workflow_state":"available"
}
]
The second one is a JSON export from my database:
[
{
"id":1,
"course_id":"Basic 101",
"name":"Basic Level",
"description":"blablabla",
"discipline_id":"1",
"duration":"28",
"created_at":null,
"updated_at":null
},
{
"id":2,
"course_id":"Medium 201",
"name":"Medium Level",
"description":"blablabla",
"discipline_id":"1",
"duration":"28",
"created_at":null,
"updated_at":null
}
]
I would like to merge these two JSON into one, with matched :name in the first JSON and :course_id in the second one.
If you know good tutorials on using JSON in Rails, I'm really interested.
This isn't really a JSON issue.
When parsing JSON data it returns arrays and hashes.
One way of merging it in this case would be to loop through the data and check for the parameters you want/need to match. Once you find a match you can either manually create a new Hash with the needed data or you could use
hash1.merge(hash2)
http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-merge
which would return a hash consisting of both Hashes - attributes with the same name would be overwritten in the first hash.
Just a quick answer, to let you know where to go. Assuming first json is in json1 and second is in json2 variables, this code:
require 'json'
arr1 = JSON.parse(json1)
arr2 = JSON.parse(json2)
mrg = []
arr1.each do |el1|
arr2.each do |el2|
if el2['course_id'] == el1['name']
mrg.push(el1.merge(el2))
end
end
end
p mrg
Will print:
[
{
"course_code"=>"Basic 101 - 0913",
"name"=>"Basic Level",
"start_at"=>"2013-09-16T00:00:00+02:00",
"end_at"=>"2013-10-13T23:55:00+02:00",
"workflow_state"=>"available",
"id"=>1,
"course_id"=>"Basic 101",
"description"=>"blablabla",
"discipline_id"=>"1",
"duration"=>"28",
"created_at"=>nil,
"updated_at"=>nil
},
{
"course_code"=>"Medium 201 - 0913",
"name"=>"Medium Level",
"start_at"=>"2013-08-06T16:55:25+02:00",
"end_at"=>nil,
"workflow_state"=>"available",
"id"=>2,
"course_id"=>"Medium 201",
"description"=>"blablabla",
"discipline_id"=>"1",
"duration"=>"28",
"created_at"=>nil,
"updated_at"=>nil
}
]

rails extract data from simple json response

I need to extract some data from a JSON response i'm serving up from curb.
Previously I wasn't calling symbolize_keys, but i thought that would make my attempt work.
The controller action:
http = Curl.get("http://api.foobar.com/thing/thing_name/catalog_items.json?per_page=1&page=1") do|http|
http.headers['X-Api-Key'] = 'georgeBushSucks'
end
pre_keys = http.body_str
#foobar = ActiveSupport::JSON.decode(pre_keys).symbolize_keys
In the view (getting undefined method `current_price' )
#foobar.current_price
I also tried #foobar.data[0]['current_price'] with the same result
JSON response from action:
{
"data": {
"catalog_items": [
{
"current_price": "9999.0",
"close_date": "2013-05-14T16:08:00-04:00",
"open_date": "2013-04-24T11:00:00-04:00",
"stuff_count": 82,
"minimum_price": "590000.0",
"id": 337478,
"estimated_price": "50000.0",
"name": "This is a really cool name",
"current_winner_id": 696969,
"images": [
{
"thumb_url": "http://foobar.com/images/93695/thumb.png?1365714300",
"detail_url": "http://foobar.com/images/93695/detail.png?1365714300",
"position": 1
},
{
"thumb_url": "http://foobar.com/images/95090/thumb.jpg?1366813823",
"detail_url": "http://foobar.com/images/95090/detail.jpg?1366813823",
"position": 2
}
]
}
]
},
"pagination": {
"per_page": 1,
"page": 1,
"total_pages": 131,
"total_objects": 131
}
}
Please note that accessing hash's element in Rails work in models. To use it on hash, you have to use OpenStruct object. It's part of standard library in rails.
Considering, #foobar has decoded JSON as you have.
obj = OpenStruct.new(#foobar)
obj.data
#=> Hash
But, note that, obj.data.catalog_items willn't work, because that is an hash, and again not an OpenStruct object. To aid this, we have recursive-open-struct, which will do the job for you.
Alternative solution [1]:
#foobar[:data]['catalog_items'].first['current_price']
But, ugly.
Alternative solution [2]:
Open Hash class, use method_missing ability as :
class Hash
def method_missing(key)
self[key.to_s]
end
end
Hope it helps. :)

Resources