That's great for reading options. But how do you save them back to options.
My talk from AdhearsionConf 2011 was posted a month ago, and somehow it slipped my mind to post it here. It's about AT5001, a war dialer built in my spare time using cloud telephony.
Weaponizing the Cloud: Wardialing with Adhearsion -- AdhearsionConf 2011 from Adhearsion Foundation, Inc. on Vimeo.
Tropo's cloud telephony services are absolutely awesome, and the fact that they make them available free to developers makes them an absolute haven for us to create weird telephony applications. I've recently been working on a wardialer using Tropo's cloud for a talk I'm giving at AdhearsionConf, and I thought I'd take a moment to explain how to work with the originate and recording functions when working with Tropo.
Initiating an outbound call with Tropo is actually a really simple process. After you create your Tropo application, you'll notice on your application page there's a voice outbound token assigned to your application. With that token in hand you can actually form a simple request to initiate the call.
res = Net::HTTP.postform(URI.parse('http://api.tropo.com/1.0/sessions'), "token" => @token, "destination" => number, "tropotag" => call_num)
In this case all I'm doing is using a simple POST to initiate a call via their API (acceptable parameters can be found here). The token field contains the voice token for your application, the destination field contains the number you wish to call (with country code), and in this case I'm also using the tropo_tag field to tag it with a unique identifier that I'll match on the adhearsion side when it comes time to actually control the call.
I've got my tropo application currently configured to use tropo-agitate to forward on control of the call to my adhearsion process (instructions for setting up tropo-agitate can be found here). So once the call is answered and control passes to my adhearsion process the first thing I want to do is begin to monitor the call (Warning: Recording calls may only be done with the consent of both parties in 12 states. In all other states, you only need the permission of one party, in this case yourself), so I'll send off off this little piece of code in my component:
num = JSON.parse(@call.tropoheaders)["tropotag"]
res = @call.execute "startcallrecording", { 'uri' => "http://MYSERVER.com:3000/audio/#{num}", :method => "POST", :format => "audio/mp3" }.tojson
Here I'm pulling the tropo_tag out (the unique identifier I originally sent out), and then sending along the command to begin recording the call. Obviously since we don't have access to Tropo's servers, we have to have a way to get the audio afterwards, so you can either have Tropo FTP the file back to you, or provide it with an HTTP address to return the file to. In my case I felt like I'd have better control of my call's workflow if they sent it via an HTTP POST request (that way I can have rails throw it into the queue to be processed when it receives it). With that in mind I send it the address I want that POST request to go to in the uri field, along with the format (acceptable formats are audio/wav and audio/mp3).
Once your call is wrapped up, Tropo will transcribe that call into a temporary file and send it to the uri you specified beforehand. I haven't seen any way to force Tropo to name that file anything on it's return trip, or to include another tag, so this is where that unique id I assigned earlier came in handy. I was able to use it to form an id in the url that the audio is sent to. The file will come across as the 'filename' parameter in the post request, so to scoop it up, here's some simple file transcription code for your controller:
audio = params["filename"]
name = "call#{params[:id]}.mp3"
directory = "audiodata"
path = File.join(directory, name)
File.open(path, "wb") { |f| f.write(audio.read) }
This simply reads in the data in the POST and writes it out to a predetermined directory (in this case 'audio_data'). Keep in mind that this particular code does no checking on the incoming file to determine it's veracity, so if you're going to deploy something like this to production, you should verify that you're even waiting for a particular file, or risk people uploading malicious files to your server.
Anyways, that's the basic process I've used for placing and recording outgoing calls in my applications using Tropo. Hopefully this will help someone else in developing their own custom telephony applications.
Recently I came across an issue where I had several tables in my rails application that needed options. I really didn't want to just add options fields to each of them for obvious reasons (the options might change, etc). In the code of the project, the options were represented as a hash unique to each individual user ie: { :display_creator => true, :position => 1.1 }. So in order to abstract some of this away I decided to go with a polymorphic table in ActiveRecord, which works like so:
class Option < ActiveRecord::Base
belongsto :owner, :polymorphic => true
end
class User < ActiveRecord::Base
hasmany :options, :as => :owner
end
class Operation < ActiveRecord::Base
has_many :options, :as => :owner
end
Pretty basic stuff, now every time I reference the options method from an individual user I get back a series of option objects associated with my users. If I reference the options method from my Operation object, I'll get back only the options associated with that particular operation. Rails does this by looking for two columns you must create when you create your model
With this solution in place I was off to the races, however I noticed that I was having to convert all these options back into a hash (they were essentially being stored as a key value pair of strings in the db). Naturally this is an action that would be great to throw into the models, however I began to realize that I'd have to repeat this option object to hash method in each model if I wanted to store it there. And that's certainly not very DRY. Remembering some work I had done on the govkit library, I decided to use an acts_as reference condensing all the attributes of a model that are associated with having options down and creating a method that could add them to any individual model with a single call. (Note the Option class is unchanged)
config/initializers/activerecordaddons.rb
module ActiveRecordAddons
def hasoptions
classeval do
hasmany :rawoptions, :as => :owner, :classname => "Option"
def options
opts = {}
rawoptions.each |opt|
opts[opt.key.to_sym] = converter(opt.value)
end
opts
end
private
def converter val
Integer(val)
rescue ArgumentError
Float(val)
rescue ArgumentError
val
end
end
end
end
ActiveRecord::Base.extend ActiveRecordAddons
You'll note that now when you call options, it's actually referencing the options method which parses out the rawoptions from the database and returns a hash. If I were doing this from an independant library, I would have packaged this all up in a gem and included the gem in my gemfile, however I'm only using this from my one project, so I instead wrote the code out and added it to an activerecordaddons.rb file in the config/initializers directory. This ensured that the method was monkey patched onto the ActiveRecord::Base parent before the models were instansiated. So now ActiveRecord::Base and all it's children have this hasoptions method available, which will add in all the necessary code to make the models able to store their options hashes. So now my models look like so:
class User < ActiveRecord::Base
hasoptions
end
class Operation < ActiveRecord::Base
hasoptions
end
Nice and DRY, and now any changes I need to make to how these models deal with their options can be done from one place.
Hopefully someone else finds this helpful. Enjoy!
That's great for reading options. But how do you save them back to options.
Hmmm... I'd probably define a options= method to iterate through the hash and update/add the options to the object, so that you can maintain the nice User.first.options = { :key => "value" } format. Though given that the = operator is universally understood to set the value of something I'd probably also add an add_options method to just append options without deleting any or resetting the full object.
Something like this: https://gist.github.com/1158636
If I had to break down all the things I learned at RailsConf into individual items, I think most people would be surprised which individual items sees the most usage when I'm giving tips to someone else on their Ruby code. When working with an item that I need to be an array, and yet have no idea what it actually is, people frequently use an if:
if result.class != "Array"
result = [result]
Or, some people will use the more compacted method of a ternary operator:
result = result.class == "Array" ? result : [result]
However, the Array class is already equipped for a more confident method:
result = Array(result)
The Array class' initialize method already returns an array of any class you pass it, with the exception of another Array. If you pass it an Array already it will simply return the original Array.
It's quite a simple tip, but I've been extremely surprised how infrequently used it is, and how often I've used it or passed it along since I got back from RailsConf. Big thanks to Avdi Grimm for his amazing lecture Confident Code at RailsConf 2011.
One of the things I love most about Ruby is the simple extensible ways you can manipulate objects. So when I recently came across a new instance of this, I thought I'd pass it along to my readers. I decided to write a framework for working with pen and paper games, and when I started writing the dice rolling class I noticed that I had a block that had to be unnecessary in Ruby.
num.times { rolls << (rand(dtype)+1) }
sum = 0
rolls.each do |r|
sum += r
end
The first line is just rolling the dice a specified number of times and loading them into the rolls array that I previously declared. The rest of it is just adding up all the numbers to return a sum. Being a former Java programmer this is exactly how I would have done it there, so I just wrote it that way and moved on. But as I began to look back, I realized that it was quite ugly. Beyond that, I couldn't believe that Ruby wouldn't have a more elegant way to handle this common task of reducing an array of components to a final result. Fortunately it does, and the answer is in the inject and reduce methods.
These two methods appear to be identical as far as I can see (if I'm wrong, then feel free to correct me in the comments and I'll edit this later), so I'll be addressing just reduce, since I find it more pleasing syntacitcally. So using these how can I solve my problem?
rolls.reduce(:+)
One tiny line. I love me some Ruby. Reduce actually performs an identical operation on each element of the array, keeping a carryover variable as it does so. For simple mathmatical operations, you can pass a symbol of the operator you want to use, like :+ to add everyone up. But you can also use other operators, even :** if you wanted the code to exponentially increase on every iteration. However, what if you have an array of strings you'd like to get specific data out of with a constant operation. Or what if you want to do a little more complex operation to each one. Well as usual, blocks come to the rescue.
rolls.reduce { |total, n| (total + n) * -1 }
rolls.reduce { |highest, n| highest > n ? highest : n }
The first one does a more complex operation, multiplying the result by -1 every time. It's contrived, but it shows how you can give the array a block of more complex math. The second example iterates through the array comparing the elements looking for the largest item in the array. It should be noted that the return value from the block becomes the new carried variable, and the final returned variable is the return from the method. Also note this doesn't change the value of the array.
Hopefully someone else will find that this saves them some time later!