Is it possible to retrieve json from database? - ruby-on-rails

I have a rails(5.1) application with postgres(9.6) as a DB. In one of tables I have jsonb field, and all that I need is just to retrieve this string and send it to client. Why do i need it? Converting to json takes half of total request time
my_record.my_json_field # returns hash
my_record.read_attribute(:my_json_field) # also returns hash
# even this hack returns hash
MyRecord.select('my_json_field as temp_field').first[:temp_field]
I found two solutions:
# proposed by Sergio Tulentsev
# It's a fastest way. you will receive just a hash with fields that you selected
MyRecord.connection.execute(MyRecord.my_scope.to_sql)
# Another option is to select that data as a text.
# In that case you will receive ActiveRecord objects
MyRecord.select('*', 'my_json_field::text as my_field_as_text').first.my_field_as_text

(porting suggestion from comments, which worked)
Try MyRecord.connection.execute_sql (or what is it called). In all of the examples above you go through the model, which respects your schema and deserializes the hash. You need the raw db connection.

Related

How to create a hash for all records created by a user?

In our Rails app, the user (or we on his behalf) load some data or even insert it manually using a crud.
After this step the user must validate all the configuration (the data) and "accept and agree" that it's all correct.
On a given day, the application will execute some tasks according the configuration.
Today, we already have a "freeze" flag, where we can prevent changes in the data, so the user cannot mess the things up...
But we also would like to do something like hash the data and say something like "your config is frozen and the hash is 34FE00...".
This would give the user a certain that the system is running with the configuration he approved.
How can we do that? There are 7 or 8 tables. The total of records created would be around 2k or 3k.
How to hash the data to detect changes after the approval? How would you do that?
I'm thinking about doing a find_by_user in each table, loop all records and use some fields (or all) to build a string and hash it at the end of the current loop.
After loop all tables, I would have 8 hash strings and would concatenate and hash them in a final hash.
How does it looks like? Any ideas?
Here's a possible implementation. Just define object as an Array of all the stuff you'd like to hash :
require 'digest/md5'
def validation_hash(object, len = 16)
Digest::MD5.hexdigest(object.to_json)[0,len]
end
puts validation_hash([Actor.first,Movie.first(5)])
# => 94eba93c0a8e92f8
# After changing a single character in the first Actors's biography :
# => 35f342d915d6be4e

How to perform #find on an object without Active Model

Here's what's happend: I have gone and pulled a large amount of data from an API. This is nice, but it includes a lot of results.
When I do a result.find(id: api_id) I get all the results like find was never performed. #where does not work either. I'm assuming this is because its not extending from Active Model.
Key Question: How do I find, say, the name of a particular object in an active resource collection?
Object.find(id: api_id) in active resource is essentially doing an api request as in (uri_of_api)/objects/:api_id)
But the :find method on an array is a different aninmal. You can look up the array 'find' method here... http://www.ruby-doc.org/core-2.1.1/Enumerable.html#method-i-find
The correct format would be...
result.find{|rec| rec.id == api_id}

Rails, Soulmate, Redis remove record

I use Soulmate to autocomplete search results, however I want to be able to delete records after a while so they don't show up in the searchfield again. To reload the list with Soulmate seems a bit hacky and unnecessary.
I have used json to load and I have a unique record "id"
{"id":1547,"term":"Foo Baar, Baaz","score":85}
How can I delete that record from redis so it wont show up in the search results again?
It is not trivial to do it directly from Redis, using redis-cli commands.
Looking at soulmate code, the data structure is as follows:
a soulmate-index:[type] set containing all the prefixes
a soulmate-data:[type] hash object containing the association between the id and the json object.
per prefix, a soulmate-index:[type]:[prefix] sorted set (with score and id)
So to delete an item, you need to:
Retrieve the json object from its id (you already did it) -> id 1547
HDEL soulmate-data:[type] 1547
Generate all the possible prefixes from "Foo Baar, Baaz"
For each prefix:
SREM soulmate-data:[type] [prefix]
ZREM soulmate-index:[type]:[prefix] 1547
Probably it would be easier to directly call the remove method provided in the Soulmate.Loader class from a Ruby script, which automates everything for you.
https://github.com/seatgeek/soulmate/blob/master/lib/soulmate/loader.rb

rails using .send( ) with a serialized column to add element to hash

I'm serializing many attributes on a model Page as hashes.
Because of the high number of attributes, I've taken a meta-programming approach and want to use .send() to iterate through a collection of attributes (such that I don't have to type out an update action for each attribute.
I've done something like this:
insights.each do |ins|
self.send("#{ins.name}=", {(Time.now) => ins.values[1]['value'].to_f})
self.save
end
The problem is that this obviously overwrites the whole serialized column, whereas I wish to add this as an element to the serialized hash.
Tried something like this:
insights.each do |ins|
self.send("#{ins.name}[#{Time.now}]=", ins.values[1]['value'].to_f)
self.save
end
But get a NoMethodError: undefined method page_fan_adds_unique[Mon Aug 13 13:31:58 -0400 2012]=
In the console I'm able to do Page.find(5).page_fan_adds_unique[Time.now]= 12345 and save it as an additional element to the hash as expected.
So how can I use .send() to save an additional element to a serialized hash? Or is there some other approach? Such as using update_attribute or another method? Writing my own? Any help is appreciated, even if the advice is that I shouldn't be using serialization for this.
I'd do :
self.ins.name.send(:[]=, key, value)

Ruby on Rails - passing hashes

I have a piece of controller code where some values are calculated. The result is in the form of an array of hashes. This needs to get into a partial form somehow so that it may be retrieved later during commit (which is through the Submit button).
The questions is how do we pass the array of hashes?
thanks.
Is there a reason it has to be through the form? This is the type of thing I usually use the session for.
I can't really think of a nice way to do what you're asking with forms. I guess you could create hidden fields for each key in your hash in the form with hidden_field_tag as an alternative. Then you run into problems translating it (what if a key's value is an array or another hash?).
You could easily store the hash in the session and then on each page load, check to see if there is a hash where you expect it. On calculating values:
session[:expected_info] = results
And each page load, something like this:
if session.has_key?(:expected_info)
results = session.delete(:expected_info)
# you already calculated the results, just grab them and
# do what you need to do
else
# you don't have the expected info
end
You should be able to pass it as a string to your partial:
[{}].inspect
and eval it when it is submitted back through the form:
eval("[{}]"))
but that would be really dirty…

Resources