I'm trying to build a simple API using Ruby on Rails which returns some statistics about tickets from an OTRS database.
Currently when I call my API for the following call, it is returning the below response.
API Call
http://localhost:3000/api/openvsclosed
Current Response
[[1,1,1],[2,2,2]]
I was wondering how I could get this to appear in the correct format of:
Desired Response
[
{
"Id":1,
"Opened":1,
"Closed":1
},
{
"Id":2,
"Opened":2,
"Closed":2
}
]
Current Controller
def openvsclosed
sql = "SELECT
#ROW := #ROW + 1 AS Id,
COUNT(t.tn) AS Opened,
COUNT(t.tn) AS Closed
FROM
ticket t
CROSS JOIN (SELECT #ROW := 0) AS Row
WHERE
t.create_time > DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP by
DAY(t.create_time)
ORDER by
t.create_time;"
records = ActiveRecord::Base.connection.execute(sql)
render json: records
end
I'm quite new to using Ruby on Rails so I am most likely missing something obvious / big here.
I would recommend checking out jbuilder - you can customize a json template with whatever format you wish for the records you're returning from the controller to the json view.
In this case, you could do something like:
json.array! #records do |json, record|
json.id record.id
json.opened record.opened
json.closed record.closed
end
Alternative is https://github.com/nesquena/rabl, simple to set up, and easy to use
Related
Ok so I have an app that allows users to pull App Store data, specifically top free top paid etc. The various attributes are quite limited, but users can filter by category and country. So obviously this leads to a lot of repeated queries, now normally this wouldn't be a problem, but I also use this data with google api which has a credits system. So What I want to do is save these results in my database if the results are unique. I have this all set up and fine but my only hang up is how I determine if a query has been made before, so my solution is to make a hashtable that stores all queries that have been made before and if not NULL(nil) then I call the api to fetch the data then create a new record.
Issue is the App Store refreshes every day or so(not exactly sure the schedule but will look it up later). I would like to have this Hashtable reference function refresh or reset itself to all NULL at this interval.
What would be the most efficient or simple way to start a refresh for this? Additionally I am kinda new to rails, so where should I place this function? In the helper modules? Controller?
Thanks!
Edit:
ok so here is my HashTable helper module
module MapsHelper
queryHistoryLookUp = {}
i = 0
31.times do |i|
queryTableLookup.merge!(i =>[] )
end
def queryTableLookup(asciiNum, queryString)
if queryTableLookup[asciiNum % 31].size == 0
queryTableLookup[asciiNum % 31].push(queryString)
else
a = queryTableLookup[asciiNum % 31].size
arrayOfQueries = queryTableLookup[asciiNum % 31]
a.times do |i|
if arrayOfQueries[i] == queryString
return true
else
return false
end
end
end
end
end
def queryHash(query)
asciSum = 0
query.each_char do |i|
asciSum += i.sum
end
queryTableLookup(asciSum, query)
end
end
additionally I am kinda new to rails, can I interact with these functions using Javascript, since on the client side I create the string query.
In my opinion, your best bet would be to use the Rails cache system. It provides a method of caching data, with an optional expires_in time.
From the docs:
http://guides.rubyonrails.org/caching_with_rails.html#low-level-caching
class MyModel < ActiveRecord::Base
def self.get_api_data(key)
Rails.cache.fetch("my_model/api_data:#{key}", expires_in: 12.hours) do
SomeService::API.get_data(key)
end
end
end
In your hash (which I think it could exist in a class variable) you can store both the query and the last access datetime:
Suppose you have a hash as class variable to the Foo class with name cache and that the query variable is your current query that you want to check.
if Foo.cache[query].nil? || (DateTime.now - Foo.cache[query].last_fetch).to_i > 0
results = your_method_to_fetch_data_for(query)
Foo.cache[query] = {:results => results, :last_fetch => Datetime.now}
else
results = Foo.cache[query][:results]
end
I have that kind of script.
Search_controller.rb :
def results
#users = #search.cached_users_count.page(params[:page]).per_page(10)
end
Search.rb Model :
users = users.order('current_sign_in_at DESC')
def cached_users_count
Rails.cache.fetch(["user_count", expires_in: 5.minutes]) { users }
end
What i want to do is cache all query because when some user will login after search results are executed, will_paginate replace results on next page - because just logged user go on first position and results are changed for order by current_sign_in_at
Can somebody help me with that ? Right now no cache is made , for every search results theres is sql response.
There are a few things to change in your current implementation to get the behavior you're looking for.
The users object you're starting with is returning a relation, but
only the scope, which means it is not storing results as you expect.
To store the results of the query you'll need to load them using a
query method. Use all if in Rails 3, or load if in Rails 4:
users.order('current_sign_in_at DESC').all #Rails 3
users.order('current_sign_in_at DESC').load #Rails 4, all is deprecated
The syntax for the Rails cache is incorrect if you really want it to
expire. You're passing expires_in as part of the key, which is an
array [] in your current code. You want to just pass normal
parameters, with expires_in as an option.
Rails.cache.fetch("user_count", expires_in: 5.minutes) { users }
See the following for a similar question on SO as well:
Confusion caching Active Record queries with Rails.cache.fetch
I'm trying to extract JSON records from a Rails app via the REST interface. I'm using RABL to create the JSON. I would like records that are greater than a specified created_at.
In the worequests controller, I have this:
def index
if params[:created_at] != nil
#worequests = Worequest.find(params[:created_at])
else
#worequests = Worequest.order(:created_at)
end
If I enter this into the browser:
http://localhost:5000/worequests?created_at=2012-11-28%2016:37:29.253916
I get this:
Couldn't find Worequest with id=2012-11-28 16:37:29.253916
I copied the datetime from the PG table.
Question1
Why couldn't it find that record?
Question2
To use greater than, should I be able to use something like this in the URL?
http://localhost:5000/worequests?created_at>2012-11-28%2016:37:29.253916
Question3
If I get that working, how would I then ask for the JSON?
http://localhost:5000/worequests?created_at>2012-11-28%2016:37:29.253916.json
UPDATE1
Thanks HungryCoder - this now works:
http://localhost:5000/worequests?created_at=2013-01-01
I get an index list of records greater than that date.
But, How do I get the JSON?
I tried this:
http://localhost:5000/worequests?created_at=2013-01-01.json
Answer 1
find method expects the ID of the record.
If you want to filter using created_at field use where or attribute helper methods
#worequests = Worequest.where("created_at = ?", params[:created_at])
or,
#worequests = Worequest.find_by_created_at(params[:created_at])
or,
#worequests = Worequest.find_all_by_created_at(params[:created_at])
Worequest.find is similar to Worequest.find_by_id (assuming id is name of primary key)
Answer 2
You can't use such format in query string. You can put it in separate variable like
http://localhost:5000/worequests?created_at=2012-11-28%2016:37:29.253916&compare=%3E
so, comparing greater than may be like:
if params[:compare] == '>'
#worequests = Worequest.where("created_at > ?", params[:created_at])
end
'%3E' is uri encoded version of >
Answer 3
http://localhost:5000/worequests.json?created_at>2012-11-28%2016:37:29.253916
Is there a way to convert a Rails model into an insert query?
For instance, if I have a model like:
m = Model.new
m.url = "url"
m.header = "header"
How can I get the corresponding SQL query ActiveRecord would generate if I did m.save?
I want to get: "INSERT INTO models(url, header) VALUES('url', 'header')" if possible.
Note: I don't want to actually save the model and get the query back (from log file, etc). I want to get the query IF I chose to save it.
On Rails 4.1, I found the below code snippet working:
record = Post.new(:title => 'Yay', :body => 'This is some insert SQL')
record.class.arel_table.create_insert
.tap { |im| im.insert(record.send(
:arel_attributes_with_values_for_create,
record.attribute_names)) }
.to_sql
Thanks to https://coderwall.com/p/obrxhq/how-to-generate-activerecord-insert-sql
Tested in Rails 3.2.13: I think I got it right this time, it definitely does not persist to the db this time. It also won't fire validations or callbacks so anything they change won't be in the results unless you've called them some other way.
Save this in lib as insert_sqlable.rb and you can then
#in your models or you can send it to ActiveRecord::Base
include InsertSqlable
Then it is model.insert_sql to see it.
#lib/insert_sqlable
module InsertSqlable
def insert_sql
values = arel_attributes_values
primary_key_value = nil
if self.class.primary_key && Hash === values
primary_key_value = values[values.keys.find { |k|
k.name == self.class.primary_key
}]
if !primary_key_value && connection.prefetch_primary_key?(self.class.table_name)
primary_key_value = connection.next_sequence_value(self.class.sequence_name)
values[self.class.arel_table[self.class.primary_key]] = primary_key_value
end
end
im = self.class.arel_table.create_insert
im.into self.class.arel_table
conn = self.class.connection
substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
binds = substitutes.map do |arel_attr, value|
[self.class.columns_hash[arel_attr.name], value]
end
substitutes.each_with_index do |tuple, i|
tuple[1] = conn.substitute_at(binds[i][0], i)
end
if values.empty? # empty insert
im.values = Arel.sql(self.class.connectionconnection.empty_insert_statement_value)
else
im.insert substitutes
end
conn.to_sql(im,binds)
end
end
It turns out the code is in ActiveRecord::Relation and not ActiveRecord::Persistence. The only significant change is the last line which generates the sql instead of performing it.
If you dont want to save the model you call m.destroy when you are done with the object.
You can log the sql query by debugging it like this
Rails.logger.debug "INSERT INTO models(url, header) VALUES(#{m.url}, #{m.header}).inspect
After search a lot over the Internet and forums, I think I found a better solution for your problem: just requires two line of code.
I found a good gem that do exactly what you want, but this gem only works for Rails 3.2 and older. I talked with author and he doesn't want support this gem anymore. So I discovered by myself how to support Rails 4.0 and now I'm maintaining this gem.
Download the "models-to-sql-rails" gem here, supporting Rails 4.0 and older.
With this gem, you can easily do the following. (the examples inside values are just a joke, you will get the correct values when using it in your object).
For objects:
object.to_sql_insert
# INSERT INTO modelName (field1, field2) VALUES ('Wow, amaze gem', 'much doge')
For array of objets:
array_of_objects.to_sql_insert
# INSERT INTO modelName (field1, field2) VALUES ('Awesome doge', "im fucking cop")
# INSERT INTO modelName (field1, field2) VALUES ('much profit', 'much doge')
# (...)
Just see the Github of this project and you'll find how to install and use this wonderful gem.
I have a service I query and I get data I filter through and create a an array of records.
Unless I missed something, ActiveResource::Base does not qualify since the access to the service is not via rest and I can't use the raw data as delivered.
I am displaying the data in a table and use will_paginate to page the data. But I am not currently married to will_paginate.
I do need to sort the columns as well as paginate.
I have found two version of ujs_sort_helper.
https://github.com/pengwynn/ujs_sort_helper
https://github.com/sikachu/ujs_sort_helper
I am trying to understand:
- http://javathehutt.blogspot.com/2009/06/mo-simple-sortable-tables-in-rails.html
What have other done in rails 3? Or is one of the ujs_sort_helper packages just he correct way to go.
In term of data refresh, this is a dashbaord. Multiple data source will address the various DIVs.
Also, I am a Rails noob. But not a programming noob.
You could use meta_search's sort_link if you wish.
I like it because it also does filtering incredibly easy with meta_where.
You can also make the behavior through ajax by adding the data-remote attribute to 'a.sort_link' (i have done that through javascript).
I would welcome the maintainer of ujs_sort_helper to comment. Just a bug here and there in the rails 3 version of the code. Now ujs_sort_helper works, for me.
What I have not done is create ANOTHER branch on this package. I emailed the file to the author.
sort order now compares symbols, instead of symbol to string.
def sort_order(column, initial_order='asc')
#safe since to_sm on a sym is a nil operation. At least for now.
if session[#sort_name][:key].to_sym == column.to_sym
session[#sort_name][:order].downcase == 'asc' ? 'desc' : 'asc'
else
initial_order
end
end
The icon us set via the current order value. The sort clause should be the opposite. So show down arrow for the list being displayed in ascending order, but the 'url' is set to redisplay the table in descending order.
I have no clue what the :q symbol is supposed to be used for.
def sort_header_tag(column, options = {})
options[:initial_order].nil? ? initial_order = "asc" : initial_order = options[:initial_order]
key = session[#sort_name][:key].to_sym
order = sort_order(column, initial_order)
caption = options.delete(:caption) || column.to_s.titleize
url = { :sort_key => column, :sort_order => order, :filter => params[:filter]}
url.merge!({:q => params[:q]}) unless params[:q].nil?
content_tag('th', link_to(caption, url, :class=>session[#sort_name][:order] ), :class => "sort_link #{order if key == column}")
end