I need to store json data to database, data being fetched from 3rd party api.
sample of json:
[{ "name"=>"test", "number"=>"1234", "email"=>"test#t.com"},
{ "name"=>"user", "number"=>"5678", "email"=>"yser#t.com"}]
Model contains: username, number_phone, y_email
I want to store name in username and number in number_phone.
Fetching the data:
rdb = RestdbApi.new
body = rdb.call
Updated
Need store all data json not first element only
Data json change continuously need save continuously
As per the description shared if I am assuming it right, you need to fetch values from json and save it in the respective columns in database.
For the same, suppose you have a json(let's name it as result_json), as mentioned in the post:
rdb = RestdbApi.new
body = rdb.call # [{ "name"=>"test", "number"=>"1234", "email"=>"test#t.com"}]
result_json = JSON.parse(body)
Now suppose you have a user class which is mapped to the db for saving respective values, then
user = User.new
user.username = result_json[0]["name"]
user.number_phone = result_json[0]["number"]
user.save # note that this line will map the records in the User instance to the database.
I'd do something like this
rest_db_api = RestdbApi.new
user_records_from_api = JSON.parse(rest_db_api.call)
(I will assume that user_records_from_api will now contain an array of hashes, as follows:
[{ "name"=>"test", "number"=>"1234", "email"=>"test#t.com"},{ "name"=>"user", "number"=>"5678", "email"=>"yser#t.com"}]
you can then just iterate over this hash and create a record for each (I am assuming that your model is called User)
user_records_from_api.map(&:with_indifferent_access).each do |attribues|
User.create!(
username: attributes[:name],
number_phone: attributes[:number],
y_email: attributes[:email]
)
end
note: the with_indifferent_access method that I used is just a handy thing provided by the rails framework that allows you to have a hash with string keys, and access them using symbols (or vice-versa) - ActionController::Parameters (in rails) uses this
If you already have everything setup to get your response you can do something like this:
response = [{ "name"=>"test", "number"=>"1234", "email"=>"test#t.com"}]
YourModel.create(
username: response[0]["name"],
number_phone: response[0]["number"],
y_email: response[0]["email"]
)
The above shows you how to access an index for the response that you displayed, then creating your object with the response attributes. If you are expecting to have multiple in the response, you should use a loop and do something similar:
response = [{ "name"=>"test", "number"=>"1234", "email"=>"test#t.com"}, { "name"=>"test", "number"=>"1234", "email"=>"test#t.com"}]
response.each_with_index do |_, i|
YourModel.create(
username: response[i]["name"],
number_phone: response[i]["number"],
y_email: response[i]["email"]
)
end
Hope this helps!
You can use .find_or_create_by, to not duplicate the data. LINK
rdb = RestdbApi.new
body = rdb.call
body.each do |data|
# YourModel: make sure to change to yr own model name
YourModel.find_or_create_by(email: data["y_email"])(
username: data["name"],
number_phone: data["number"],
y_email: data["email"]
)
end
Related
Rails newbie here.
I have an integration with stripe where users can update the billing address on their card, however, stripe doesn't accept empty strings, only nil values, and it's possible that users won't need to fill in the second address line for example.
How would I go about iterating through params received from a form and convert empty strings into nil?
I have a Stripe Tool module that handles stripe related tasks.
In my controller i have:
def add_billing_address
account_id = current_user.account_id
account = Account.find_by(id: account_id)
stripe_id = account.stripe_customer_id
# convert params empty strings to nil here
StripeTool.add_billing_address(stripe_id: stripe_id,
stripe_token: params[:stripeToken],
address_line1: params[:address_line1],
address_line2: params[:address_line2],
address_city: params[:address_city],
address_state: params[:address_state],
address_zip: params[:address_zip]
)
# redirects and error handling happens after this
You can call .map .each on the params hash in the controller like this:
params.each do |key, value|
params[key] = nil if value === ''
end
But it's probably better to let your form return a nil value when a field contains no data.
I would recommend to avoid modifying the values in the params object, cause it is not good practice to change them in place. It is better to create a new object the has the values you want to use.
stripe_params = params.select { |_,v| v.present? }
This will create a new object without any of the blank attributes. I'm guessing that if an attribute is nil, you might as well not pass it at all.
I'm having problems with weird behaviour in RoR. I'm having a Hash that i'm converting to json using to_json() like so:
data = Hash.new
# ...
data = data.to_json()
This code appears inside a model class. Basically, I'm converting the hash to JSON when saving to database. The problem is, the string gets saved to database with its surrounding quotes. For example, saving an empty hash results in: "{}". This quoted string fails to parse when loading from the database.
How do I get rid of the quotes?
The code is:
def do_before_save
#_data = self.data
self.data = self.data.to_json()
end
EDIT:
Due to confusions, I'm showing my entire model class
require 'json'
class User::User < ActiveRecord::Base
after_find { |user|
user.data = JSON.parse(user.data)
}
after_initialize { |user|
self.data = Hash.new unless self.data
}
before_save :do_before_save
after_save :do_after_save
private
def do_before_save
#_data = self.data
self.data = self.data.to_json()
end
def do_after_save
self.data = #_data
end
end
The data field is TEXT in mysql.
I'm willing to bet money that this is the result of you calling .to_json on the same data twice (without parsing it in between). I've had a fair share of these problems before I devised a rule: "don't mutate data in a lossy way like this".
If your original data was {}, then first .to_json would produce "{}". But if you were to jsonify it again, you'd get "\"{}\"" because a string is a valid json data type.
I suggest that you put a breakpoint in your before_save filter and see who's calling it the second time and why.
Update
"call .to_json twice" is a general description and can also mean that there are two subsequent saves on the same object, and since self.data is reassigned, this leads to data corruption. (thanks, #mudasobwa)
It depends on your model's database field type.
If the field is string type (like VARCHAR or TEXT) it should be stored as string (no need to get rid of the quotes - they are fine). Make sure calling to_json once.
If the field is Postgres JSON type, then you can just assign a hash to the model's field, no need to call to_json at all.
If you are saving hash as a JSON string in a varchar column you can use serialize to handle marshalling/unmarshaling the data:
class Thing < ActiveRecord::Base
serialize :foo, JSON
end
Knowing exactly when to convert the data in the lifecycle of a record is actually quite a bit harder than your naive implementation. So don't reinvent the wheel.
However a huge drawback is that the data cannot be queried in the DB*. If you are using Postgres or MySQL you can instead use a JSON or JSONB (postgres only) column type which allows querying. This example is from the Rails guide docs:
# db/migrate/20131220144913_create_events.rb
create_table :events do |t|
t.json 'payload'
end
# app/models/event.rb
class Event < ApplicationRecord
end
# Usage
Event.create(payload: { kind: "user_renamed", change: ["jack", "john"]})
event = Event.first
event.payload # => {"kind"=>"user_renamed", "change"=>["jack", "john"]}
## Query based on JSON document
# The -> operator returns the original JSON type (which might be an object), whereas ->> returns text
Event.where("payload->>'kind' = ?", "user_renamed")
use {}.as_json instead of {}.to_json
ex:
a = {}
a.as_json # => {}
a.to_json # => "{}"
http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json
I am using Angular in frontend and I am trying to send object such as:
obj = {
"foo" : "1",
"bar" : 2,
"baz" : 3
}
And when Rails recives this object, it should send back data from database depending on these parameters. This is my current method to create API:
def index
#tickets = Ticket.select(
'id',
'departure_date',
'departure_country',
'departure_country_tag'
)
render status:200, json: { tickets: #tickets}
end
However this fetches all data from database. I only want to fetch data that matches parameters from the object.
Any suggestion on how to do this properly?
Select allows you to specify the attributes to be returned. You need to add a clause to that query with the values from the front end.
#tickets = Ticket.select(
'id',
'departure_date',
'departure_country',
'departure_country_tag'
).where(foo: obj["foo"], bar: obj["bar"], baz: obj["baz"])
If you look in the console you'll see how the data is being passed and you can amend the active record query accordingly.
How would I incorporate the index in a variable name so that I could access the different group objects?
This is my db/seeds.rb file:
u = User.create( email: "yeah#foo.com", password: "yeah", password_confirmation: "yeah")
groups_list = ["Math Club", "Science Class", "Economics Class"]
groups_list.each_with_index do |name, index|
"g#{index}" = u.groups.create(name: name)
end
When you start needing dynamically defined local variables you have a code smell and you know you should reconsider what you're doing.
It looks like you would be better served with a map call, converting the groups_list from an array of strings into an array of Group objects belonging to u:
groups_list.map { |name| u.groups.create name: name }
#=> [<Group name="Math Club">, …]
Then you can iterate through the groups or pass them into another method as an array, no trickery involved.
How can I read everything inside a JSON document and create another one with new names?
I can't find something that will help me create a new JSON file in an easy way.
Edit:
I am retrieving a ton of data in JSON format from a MongoDB database (as an array [{"xxx": "zz"}, ... ]). What I need is to cycle trough each document, each field and create a new JSON document using those fields.
thanks
Here's the gist of what you want:
#keys = {
"old" => "new",
"foo" => "bar"
}
def rename_key(pair)
old_key = pair.keys.first
{ #keys[old_key] => pair[old_key] }
end
pairs = ActiveSupport::JSON.decode(json)
pairs.map! { |pair| rename_key(pair) }
new_json = pairs.to_json
Obviously, you'd want to turn this into a class or two. Note that I made the assumption that all data from Mongo was in the form of simple key => value pairs, based on your description.