How can I do this update query in ruby with sinatra? - ruby

I have table blogs and I want to add one to column views when user enter to the blog page .
DB[:blogs].where(:id => params[:id]).update(:views => :views + 1)
but it gave me error when I enter to the blog page in +
undefined method `+' for :views:Symbol
I'm do this :
blog = DB[:blogs].where(:id => params[:id]).first
views = blog[:views] + 1
DB[:blogs].where(:id => params[:id]).update(:views => views)
but this is add 3 or 5 or 1 or 4 not 1 only

(The question has nothing about Sinatra, just Sequel, which is not a part of Sinatra, but rather standalone library.)
You can do this:
DB[:blogs].where(:id => params[:id]).
update(Sequel.expr(:views) => Sequel.expr(:views) + 1)
Or just this:
DB[:blogs].where(:id => params[:id]).
update('views = views + 1')

Rails is mostly syntactic sugar, not a woodoo magic. In your case the most efficient way to perform a task is:
DB[:blogs].update_all("views = views + 1", ["id = ?", params[:id]])
This would generate the query (say id = 1):
UPDATE "blogs" SET views = views + 1 WHERE (id = 1)

Related

Add 1 millisecond to a Time/DateTime object

Is there a way to add 1 millisecond to a Time/DateTime object in Ruby?
For an Webservice Request i need a time scoping with milliseconds:
irb(main):034:0> time_start = Date.today.to_time.utc.iso8601(3)
=> "2016-09-27T22:00:00.000Z"
irb(main):035:0> time_end = ((Date.today + 1).to_time).utc.iso8601(3)
=> "2016-09-28T22:00:00.000Z"
-- or --
irb(main):036:0> time_end = ((Date.today + 1).to_time - 1).utc.iso8601(3)
=> "2016-09-28T21:59:59.000Z"
So I'm near my prefered solution, but time_end should be 2016-09-28T21:59:59.999Z.
I didn't find solutions that Ruby can handle calculating with milliseconds. I only did it with strftime, but it would be great if there is a possibility to calculate.
-- This works, but hard coded --
time_end = ((Date.today + 1).to_time - 1).utc.strftime("%Y-%m-%dT%H:%M:%S.999Z")
=> "2016-09-28T21:59:59.999Z"
FYI: I'm on plain Ruby, no Rails.
Ok i found a solution. With real calculation i looks like.
time_end = ((Date.today + 1).to_time - 1/1001).utc.iso8601(3)
=> "2016-09-28T21:59:59.999Z"
EXAMPLE
Formatting in iso8601(3) is only to show behavior.
irb(main):055:0> Date.today.to_time.iso8601(3)
=> "2016-09-28T00:00:00.000+02:00
Adding a millisecond"
irb(main):058:0> (Date.today.to_time + 1/1000.0).iso8601(3)
=> "2016-09-28T00:00:00.001+02:00"
Subtract a millisecond
!DONT USE, see result with subtracted 2 milliseconds!
irb(main):060:0> (Date.today.to_time - 1/1000.0).iso8601(3)
=> "2016-09-27T23:59:59.998+02:00"
USE
irb(main):061:0> (Date.today.to_time - 1/1001.0).iso8601(3)
=> "2016-09-27T23:59:59.999+02:00"

How to retrieve entire cost for a SoftLayer machine, including any extra costs such as bandwidth overages?

I've been retrieving monthly invoice cost information on our SoftLayer accounts for quite some time using the Ruby softlayer gem. However, there is a concern in the team that we may be missing certain costs, such as any overages on network utilization. I'd like to have some piece of mind that what I'm doing is correctly gathering all costs and we are not missing anything. Here is my code/query:
account = SoftLayer::Service.new("SoftLayer_Account",:username => user, :api_key => api_key, :timeout => 999999999)
softlayer_client = SoftLayer::Client.new(:username => user, :api_key => api_key, :timeout => 999999999)
billing_invoice_service = softlayer_client.service_named("Billing_Invoice")
object_filter = SoftLayer::ObjectFilter.new
object_filter.set_criteria_for_key_path('invoices.createDate', 'operation' => 'betweenDate', 'options' => [{'name' => 'startDate', 'value' => ["#{startTime}"]}, {'name' => 'endDate', 'value' => ["#{endTime}"]}])
# Set startDate and endDate around the beginning of the month in search of the "Recurring" invoice that should appear on the 1st.
invoices = account.result_limit(0,10000).object_filter(object_filter).object_mask("mask[id,typeCode,itemCount,invoiceTotalAmount,closedDate,createDate]").getInvoices
invoices.each do | invoice |
if invoice["typeCode"] == "RECURRING"
invoice_reference = billing_invoice_service.object_with_id(invoice["id"])
invoice_object = invoice_reference.object_mask("mask[itemCount]").getObject
billing_items_count = invoice_object["itemCount"]
billing_machines_map = Hash.new
all_billing_items = Array.new
# Search for billing items containing a hostName value.
# The corresponding billing item ID will become the key of a new hash.
# Child costs will be added to the existing costs.
billing_items_retrieval_operation = proc {
for i in 0..(billing_items_count/8000.0).ceil - 1
billing_items = invoice_reference.result_limit(i*8000, 8000).object_mask("mask[id,resourceTableId,billingItemId,parentId,categoryCode,hostName,domainName,hourlyRecurringFee,laborFee,oneTimeFee,recurringFee,recurringTaxAmount,setupFee,setupTaxAmount,location[name]]").getItems()
billing_items.each do | billing_item |
if billing_item["hostName"]
billing_machines_map[billing_item["id"]] = billing_item
end
end
all_billing_items.concat(billing_items)
end
}
# Look for items with parentIds or resourceTableIds.
# Both Ids represent a "parent" of the item.
# Give higher importance to parentId.
billing_items_retrieval_callback = proc {
cost_of_billing_items_without_parent = BigDecimal.new("0.00")
all_billing_items.each do | billing_item |
if billing_item["parentId"] != ""
parent_billing_machine = billing_machines_map[billing_item["parentId"]]
if parent_billing_machine parent_billing_machine["recurringFee"] = (BigDecimal.new(parent_billing_machine["recurringFee"]) + BigDecimal.new(billing_item["recurringFee"])).to_s('F')
parent_billing_machine["setupFee"] = (BigDecimal.new(parent_billing_machine["setupFee"]) + BigDecimal.new(billing_item["setupFee"])).to_s('F')
parent_billing_machine["laborFee"] = (BigDecimal.new(parent_billing_machine["laborFee"]) + BigDecimal.new(billing_item["laborFee"])).to_s('F')
parent_billing_machine["oneTimeFee"] = (BigDecimal.new(parent_billing_machine["oneTimeFee"]) + BigDecimal.new(billing_item["oneTimeFee"])).to_s('F')
end
elsif billing_item["resourceTableId"] != ""
parent_billing_machine = billing_machines_map[billing_item["resourceTableId"]]
if parent_billing_machine
parent_billing_machine["recurringFee"] = (BigDecimal.new(parent_billing_machine["recurringFee"]) + BigDecimal.new(billing_item["recurringFee"])).to_s('F')
parent_billing_machine["setupFee"] = (BigDecimal.new(parent_billing_machine["setupFee"]) + BigDecimal.new(billing_item["setupFee"])).to_s('F')
parent_billing_machine["laborFee"] = (BigDecimal.new(parent_billing_machine["laborFee"]) + BigDecimal.new(billing_item["laborFee"])).to_s('F')
parent_billing_machine["oneTimeFee"] = (BigDecimal.new(parent_billing_machine["oneTimeFee"]) + BigDecimal.new(billing_item["oneTimeFee"])).to_s('F')
end
else
cost_of_billing_items_without_parent = (BigDecimal.new(cost_of_billing_items_without_parent) + BigDecimal.new(billing_item["recurringFee"])).to_s('F')
cost_of_billing_items_without_parent = (BigDecimal.new(cost_of_billing_items_without_parent) + BigDecimal.new(billing_item["setupFee"])).to_s('F')
cost_of_billing_items_without_parent = (BigDecimal.new(cost_of_billing_items_without_parent) + BigDecimal.new(billing_item["laborFee"])).to_s('F')
cost_of_billing_items_without_parent = (BigDecimal.new(cost_of_billing_items_without_parent) + BigDecimal.new(billing_item["oneTimeFee"])).to_s('F')
end
end
pp "INVOICE: Total cost of devices for account without a parent is:"
pp cost_of_billing_items_without_parent
end
end
end
After the above I make calls to getVirtualGuests and getHardware to get some additional meta information for each machine (I tie them together based on billingItem.id. Example:
billingItemId = billing_machine["billingItemId"]
account_service = softlayer_client.service_named("Account")
filter = SoftLayer::ObjectFilter.new {|f| f.accept("virtualGuests.billingItem.id").when_it is(billingItemId)}
virtual_guests_array = account_service.object_filter(filter).object_mask("mask[id, hostname, datacenter[name], billingItem[orderItem[order[userRecord[username]]]], tagReferences[tagId, tag[name]], primaryIpAddress, primaryBackendIpAddress]").getVirtualGuests()
As you can see I don't make any calls to capture bandwith overage charges. I have printed out the various "category" values I get from the above query but I am not seeing anything specific to network utilization (it's possible there are no extra network utilization costs but I am not certain).
Thank you.
Any extra costs such as bandwidth overages will be included in the billing item from the server. So you don't need to make any other call to the api to get it.

how can I get details of a second leg call with twilio?

I want to get the call details, from a second leg call, and insert them into my database.
Here is the scenario: an inbound call to a toll-free number is routed to second phone. So there are 2 legs, 1) the inbound call to the toll-free number and then 2) connection to the second number.
The code for getting the call details for the FIRST leg is:
get '/hangup' do
user_key = numbers.where(:number => params["To"]).join(:credentials, :user_id => :user_id).get(:user_key)
user_token = numbers.where(:number => params["To"]).join(:credentials, :user_id => :user_id).get(:user_token)
call_sid = params["CallSid"]
call_parent_sid = ["ParentCallSid"]
#sub_account_client = Twilio::REST::Client.new(user_key, user_token)
#subaccount = #sub_account_client.account
call = #subaccount.calls.get(call_sid)
call_sid = call.sid,
call_parent_sid = call.parent_call_sid,
phone_number_id = call.phone_number_sid,
call_from = call.from,
call_to = call.to,
call_start = call.start_time,
call_end = call.end_time,
call_duration = call.duration,
charged_duration = ((call_duration.to_f)/60).ceil
call_price = call.price
call_charged_price = (charged_duration * 0.07)
call_logs.insert(:call_sid => call_sid, :call_parent_sid => call_parent_sid, :phone_number_id => phone_number_id, :call_from => call_from, :call_to => call_to, :call_start => call_start, :call_end => call_end, :call_duration => call_duration, :charged_duration => charged_duration, :call_price => call_price, :call_charged_price => call_charged_price)
end
This works after hangup and the status_callback_url is '/hangup'. But how can I get the same details for the second leg of the call. I have tried as follows:
get '/receive' do
destination_number = numbers.where(:number => params["To"]).join(:users, :id => :user_id).get(:primary_number)
user_id = numbers.where(:number => params["To"]).join(:users, :id => :user_id).get(:id)
greeting_url = voicemail.where(:user_id => user_id).get(:voicemail_play_url)
resp = Twilio::TwiML::Response.new do |r|
r.Dial destination_number, :status_callback => '/hangup_second_leg', :status_callback_method => 'GET'
etc..
This effectively attempts to create a second status_callback_url which, needless to say, did not work.
So, how can I get the details of the second (or even third) leg of a call and bung it into my DB?
Twilio evangelist .....
Many thanks in advance.
Twilio developer evangelist at your service!
I just ran a quick test and the parameters you get back from the hangup callback should include a "CallSid" and a "DialedCallSid" which are the two legs of your call. You can get hold of the data via normal calls to the REST api:
get '/hangup' do
call_sid = params["CallSid"]
dialed_call_sid = params["DialedCallSid"]
#sub_account_client = Twilio::REST::Client.new(user_key, user_token)
#subaccount = #sub_account_client.account
inbound = #subaccount.calls.get(call_sid)
outbound = #subaccount.calls.get(dialed_call_sid)
# Update calls in database
end
Alternatively, the inbound call is the parent of all the other calls that take part within the context of the call. So you can get the details on all the child calls with the following api calls:
#subaccount.calls.list parent_call_sid: params["CallSid"]
# => [<Twilio::REST::Call>, ...]
Also, if you are getting a ParentCallSid parameter in your hangup, then you can use the above code to look up the parent call and child calls from that too.
Hope this helps, let me know if there's anything else I can help with.

sphinx and multilanguage search || search by attribute

I'm trying to get results from sphinx by attr_string. Here is sphinx configuration:
source db
{-
type = mysql
sql_query = \
SELECT id,language,text,page_url \
FROM content
sql_attr_string = language
sql_attr_string = page_url
}
index content
{
source = db
charset_type = utf-8
min_word_len = 3
}
The results that i'm getting are like this:
[matches] => Array
(
[106] => Array
(
[weight] => 4
[attrs] => Array
(
[page_url] => en/example.gtml
[language] => en
)
)
What I want to do is to filter all results by "language"=en.
$sphinx->SetFilter() is working by integers where in this case I'll need only string "en".
Any help is appreciated!
I found solution...
If anybody need it.
Configure "source" to use crc32, Ex:
source db
{
type = mysql
sql_query = \
SELECT id,crc32(language) as language,text,page_url \
FROM content
sql_attr_uint = language
sql_attr_string = page_url
}
And in client, modify setFilter method to use crc32(). ex:
$s->SetFilter('language',array(crc32('en')));
$result = $s->query('bird is a word','content');
I hope it helps somebody...
more information: http://sphinxsearch.com/docs/current.html#attributes

How to organize default order in pagination?

I use will_paginate with ajax sort and seen railscasts.com.
http://railscasts.com/episodes/240-search-sort-paginate-with-ajax
My collection for pagination
#cars = Car.joins(:engine).includes(:engine).select('cars.*, engines.*').order(sort_column + " " + sort_direction).paginate(:page => params[:page], :per_page => 5)
But when I went to the index page, I jumped out error.
ActiveRecord::StatementInvalid in Items#index
SQLite3::SQLException: ambiguous column name: name: SELECT "cars"."id" AS t0_r0, "cars"."name" AS t0_r1, "cars"."model_id" AS t0_r2, "cars"."city_id" AS t0_r3, "cars"."created_at" AS t0_r4, "cars"."updated_at" AS t0_r5, "cars"."engine_id" AS t0_r6, "engines"."id" AS t1_r0, "engines"."name" AS t1_r1, "engines"."created_at" AS t1_r2, "engines"."updated_at" AS t1_r3 FROM "cars" INNER JOIN "engines" ON "engines"."id" = "cars"."engine_id" ORDER BY name asc LIMIT 5 OFFSET 0
But when I go to a page already sorted, it works for me.
I think mistake in default Order in SQL.
How to set 'cars.name' instead 'name'?
I found method and set sort default
private
def sort_column
Car.column_names.include?(params[:sort]) ? params[:sort] : "cars.name"
end

Resources