My goal was to make my own personal bit.ly. I wanted a home page with a text box that I could paste in a URL, press a button, and get a shortened link back. I also wanted to track the number of times each of my links was clicked. I also wanted a very visual leaderboard of my top links as well as a tabular page of all my links. I also wanted to deploy the app live to the internet and use my own custom short domain.
Here is what I ended up making: acal.io
The very first step was to a create new rails app with postgres since I knew that I would later be deploying to heroku
1
|
|
The next thing I do to any new rails app is to add pry to gemfile. Pry is an amazing gem that really helps me develop. If you are not sure about using pry, or how it can help, you I suggest you watch this talk about REPL Driven Development from Ruby Conf 2013.
1
|
|
I knew that I wanted the app to look at least somewhat nice, so not being a designer I defaulted to using bootstrap. I download the latest copy of bootstrap and unzipped it.
I added the file ‘bootstrap.min.js’ to the folder vendor/assets/javascripts. Then modified application.js to indicate this
1
|
|
I add the file ‘bootstrap.min.css’ to the folder vendor/assets/stylesheets. Then I modified application.css to indicate this
1
|
|
Now I reached the ‘heart’ of the application - the link model. I first generated the scaffolding for the link
1
|
|
I then went into the actual migration file and modified the default value for clicks BEFORE I migrated. This is because you can’t increment a non-integer value (nil), which is the original default.
1
|
|
I then migrated the database
1
|
|
Now that I had my model in place, I still needed to actually generate a short link for each URL that I pasted in.
I made a method ‘generate_slug’, which creates the short part of the link after the base url. All this method does is take the unique id for a link, and converts it into it’s Base 36 equivalent. Base 36 allows really large numbers to be shown in just a few characters. For example the 1 Billionth link in the database will have a slug of “gjdgxs” - just 6 characters as opposed to the 10 characters in the number’s ID (1,000,000,000).
1 2 3 4 |
|
But the slug alone is not enough. I want to show the user the entire full URL. To do this I want to create an environmental variable, and knowing that I will be storing some keys down the line anyway, I want to keep it just to my machine. I added the figaro gem to accomplish this, but there are other ways to do this, which I’ve written about before.
1
|
|
I then used figaro’s generate command to create the application.yml file that git will ignore (so your passwords don’t get committed to the rest of the world)
1
|
|
Then I add the base URL as an environmental variable to the application.yml file
1
|
|
With this I was able to make a convenience method to display the entire shortened URL
1 2 3 |
|
In order to make the trending links section really pop visually, I figured getting a screenshot would do the trick. I also wanted to grab the title of each page, in order to give a bit more context to the end user. I used IMGKit to capture the screenshot, CarrierWave and Fog to associate a screenshot with a model and upload it to Amazon S3, and Mechanize for getting the page title. I also knew upfront that I want to do this asynchronously, so I’ll also threw in SideKiq.
1 2 3 4 5 |
|
I got my key’s from Amazon, and created a bucket on S3. I went back to my application.yml file and added these all as environmental variables, so I could call them elsewhere in the application.
1 2 3 |
|
First I made a method for actually getting the screenshot and page title. For now, these are just Sidekiq Workers which I’ll actually build later. Of note is that I had to pass in the ID of a link, and not the full object, in order to get SideKiq to work.
1 2 3 4 |
|
I already had a method generate a slug, and now I had a method to both capture the screenshot and capture the page title. I decided to use after_create callbacks to make sure these things all happend after each new link was created.
1
|
|
I then made a screenshot worker, which captures a screenshot of each link. Because I had to pass in an ID, I first had to lookup the object. I then needed to create a temporary file of the screenshot as an intermediate step, to ensure it worked with CarrierWave. Finally I associated the screenshot with the link, which then allows triggers a call to Fog to upload the screenshot to S3.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Then I made a scrape worker, which scrapes the link and finds the page title.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Next I made a configuration file for CarrierWave, and made sure it would work on Heroku (which has permissions issues - more on that later)
1 2 3 4 5 6 7 8 9 10 11 |
|
I then made the uploader that CarrierWave needs. the store_dir method tells S3 the naming convention of the screenshots, and I just left it at the default. The cache_dir method is a way to get around Heroku’s file writing permissions issues. Basically Heroku won’t let you write files except in this one place, so I made sure to do this.
1 2 3 4 5 6 7 8 9 10 11 |
|
I finished up by adding the mount_uploader call to the link model.
1
|
|
First up I make some modifications to the auto generated links controller. I decided to delete the index, edit, update, and destroy actions. These actions get into permissions issues, which could lead naturally to building out users and all sorts of other features that are not core to this app. I’m not a fan of feature creep, and recommend that you also limit the scope of your own projects whenever possible. I also knew that I wanted the create action to respond asynchronously. I didn’t want to have to do a hard page reload when you shortened the link, and like bit.ly does, it just appends your new short link back to the screen. To do this I added the ability for the create action to respond to format.js (more on this later).
I also added the ability to route a slug on a naked url to the show action. This is so the URL http://acal.io/slug will naturally get routed to the long URL that the corresponding slug was made for. It also increments every time the link is clicked. If the user instead goes to http://acal.io/links/id, no incrementing is done, and they are taken to the show page for that link - same as normal.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
|
I then updated the routes file to map the naked url with a slug to the show action.
1
|
|
I generally make a home controller for my apps, and it’s a common design pattern I’ve seen others do, so I generated a home controller.
1
|
|
I modified the routes file to make the index action on the home controller the root
1
|
|
I decided to only have the top 12 trending items, since it’s allows for bootstrap to gracefully degrade from 4 to 3 to 2 to 1 columns.
1 2 3 4 |
|
I also wanted a page that just listed all the links created as a table, so first made a route.
1
|
|
I wanted to be sure not to overwhelm the server in case this app received a lot of link shortening requests. I figured pagination would do the trick and I opted to use the will_paginate gem.
1
|
|
Then I filled out the all action, and decided to just put 4 rows per page as the app is still small.
1 2 3 4 |
|
I first made a new partial ‘layouts/_new_link’ for a new link that would persist on top of all the pages in the app. I included a blank div called ‘result’ so I could append the result later on.
1 2 3 4 5 6 7 |
|
I then modified the ‘layout/application’ file. I changed the auto generated title, added the new partial I just created and wrapped everything in a bootstrap container.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
I then modified the link form partial ‘links/_form’. I wanted to make this submit asynchronously so added a remote:true option to the form. I also added a logo, some placeholder text, and some bootstrap styling.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
I then wanted to append the short link result back onto the page once it was processed. I referred to this earlier in the post when I was making the links controller. In order to do this I made a new file called create.js.erb in the ‘views/links’ folder.
1
|
|
I then made the ‘links/show’ page. I added in a bit of formatting, both from bootstrap, and from my own css.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
I also wanted to make sure that non-valid URLs could not be submitted. There are a lot of ways to do this, but I settled with doing client side validation.
I first installed the jquery-validation-rails gem, which is just an easy way to get the JQuery Validation Plugin into a rails app.
1
|
|
I then indicated that these files were part of my application in application.js
1 2 |
|
I then made the actual javascript validation that required both the presence of a URL, and it’s validity as a URL according to a regular expression. I put this in ‘application.js’.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
I then made the ‘home/index’ page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
I finally made the ‘home/all’ page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Along the way I added a lot of custom css to ‘application.css’. Of note is an animated yellow flash of the new shortened link as it is appended to the page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
|
Heroku makes deploying rails apps incredibly easy, and I use it for all my side projects. I first had to add the ‘rails_12factor’ gem and a line indicating that I was using ruby 2.0.0. In order to get SideKiq to work I had to use unicorn, so included the ‘unicorn’ gem too.
1 2 3 |
|
Heroku does not play nicely with the IMGKit gem, and in order to make the screenshots work I needed to download a compiled version of IMGKit.
https://wkhtmltopdf.googlecode.com/files/wkhtmltoimage-0.10.0_rc2-static-amd64.tar.bz2
I unzipped it and put it in the ‘bin’ directory of my application. I then made a configure file for IMGKit so that this would actually take effect.
1 2 3 |
|
I also had to modify config.ru to get CarrierWave to work. This again was a permissions issue with Heroku not allowing file write access, except for the one tmp directory.
1 2 3 4 5 |
|
I then made a Procfile, which is all Heroku needs to run redis and SideKiq for your application automatically. I put it in the base directory (same place as the gemfile).
1 2 |
|
I then had to make a configure file for unicorn.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
I was finally ready to go live! I created, pushed, and migrated the app on Heroku
1 2 3 |
|
I then configured the environmental variables on Heroku (remember, these are in application.yml which is ignored by git and thus not already on Heroku).
1 2 3 4 |
|
Then I added redistogo (free) and added another dyno so that SideKiq would run.
1 2 |
|
Finally I bought a custom domain through hover, who I try to use for all my domain purchasing needs (no affiliation, they are just awesome). I had to add a CNAME record called ‘www’ with the target being ‘cryptic-shore-8548’, since my heroku domain is https://cryptic-shore-8548.herokuapp.com.
I also set up domain forwarding so that a naked url (http://acal.io) would just redirect to www (http://www.acal.io). Heroku does not support naked domains out of the box. There are other solutions out there (they do cost money) but this works for now.
I then associated the domain with my app and opened it up in the browser.
1 2 |
|
It worked!
That seems like a lot of work, but it actually didn’t take me that long to do. It’s a great learning project for those of you just starting out as a developer. Let me know if you can actually use this to make your own URL shortener, or if there is something I missed. Best of luck!
]]>Make a file called env_vars.rb that includes all your keys that you want to keep secret (below, I have put in my twitter keys and tokens) and place it in the app/config folder
1 2 3 4 |
|
In app/config/boot.rb add the following line under require ‘rubygems’:
1
|
|
Add the following line to the end of your .gitignore file
1
|
|
Now you can use whatever environmentl variables you stored in the env_var.rb file. Here is how I call the twitter variables in one of my app’s twitter.rb initializer.
1 2 3 4 5 6 |
|
Now, I am aware that there is an even cooler way to add these environmetal variables to your .bash_profile - but I’ll leave for another time. For now, I am satisfied that I can use environmental variables in a secure, Figaro-free way!
]]>Incorporating a payment system into a web application has been an aspiration of mine for some time now. I kept putting it off because it seemed too daunting - the programming equivilant of climbing Mt. Everest. This weekend, however, a few flatiron students and I built an app called CodeWithUs. The idea is to allow people to post hackathons, and then get the right mix of people to attend them. We finished the data modeling and authentication on Saturday, and then took Sunday to fill in some of the views. Once the views started looking pretty good, Christina and I decided to integrate Stripe so that users could pay for a ticket to a hackathon.
We choose Stripe because we heard it was the easiest API for developers. This seemed like the perfect way to build our fist payment system! I first made a Stripe account - which took all of 2 minutes. Then we started looking at the excellent documentation and found a tutorial for Stripe Checkout using Ruby on Rails.
1
|
|
We followed the tutorial, but had to make some slight modifications sine we were incorporating this into an existing application.
We first added the Stripe gem to our Gemfile.
1
|
|
Then we generated a controller for charges.
1
|
|
We copied the suggested ‘new’ and ‘create’ actions from Stripe into our charges controller.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Then we added a resource for charges to our routes file, which will give us all the standard routes we need.
1
|
|
At this point we created a new file called stripe.rb in the config/initializers folder. We were supposed to store our passwords safely, but Figaro, the Gem we were using to do this, was causing issues, so we temporarily hard coded the keys in.
1 2 3 4 5 6 |
|
This is where we started to venture off the beaten path and go our own way. The tutorial wanted us to create html.erb files for the overall layout, and for the ‘new’ and ‘create’ actions. We already had a layout, and for the sake of getting this to work, we just appended the charges#new functionality into the hacakthon show page. We also were able to dynamically set the price in Stripe based on which hacakthon page the user was on.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
At this point we were able to have our users click on ‘pay with card’, enter their credit card information, and actually buy a ticket to our hackathon!
This is how the page looks with the ‘Pay with Card’ button on the bottom.
This is what the popup looks like where a user can enter in their credit card information to buy a ticket.
The most important skill I’ve developed at the Flatiron School is getting better at taking big problems, and breaking them down into small ones. In order to climb Mt. Everest the first major goal is to make it to base camp one.
Similarily, the first step of fully integrating Stripe payments into your application is to allow a user to successfully buy one product from you. Today, we did this, and it feels great. However looking up, there is still a long way to go to the top of Mt. Stripe. We can’t actually accept real credit cards (only test ones), we are not capturing any information about our customers, and we can only do these transactions as a javascript popup. There is a lot of work left to go, but just accomplishing this small step has given me a lot of energy to push foward towards the summit!
]]>1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
I started out by writing a method that took a number and returned the length of its Collatz sequence.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
I was pretty sure the logic was correct, but when I ran it on a random number it generated a strange error.
1
|
|
I tried a bunch of different approaches to solve this, but none of them were working. I eventually realized that my method needed to be part of a class. I made a new class called Collatz and made each number a new instance of that class. After half an hour of nothing but error messages I decided I needed a new approach.
Without an internet connection I couldn’t just google the problem, so I thought a bit more. It dawned on me that numbers are already objects (since everything in Ruby is an object) and that they are already part of the Fixnum class.
I’ve never modified a core Ruby class or ‘reopened’ a class before, but I did vaguely remember learning about this in a lecture a few weeks ago. So I decided to just reopen the Fixnum class and add this new method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
I tired it out on a test number and it worked! Victory! This is pretty basic stuff, but it’s always satisfying to get past a problem you are stuck on it for a while. All that was left was to iterate over the first million numbers and determine which one had the longest Collatz sequence.
1 2 3 4 5 |
|
The program I built determined correctly that out of the first million numbers - 837,799 has the longest Collatz sequence. My code could be optimized further - it takes a good minute to run now. That would involved determining which numbers I don’t need to iterate over - for instance it seems that even numbers generally (but not always) have longer sequences as you increase, and that odd numbers generally have longer sequences than even numbers.
]]>Project Euler Problem 11
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
I obviously needed to be able to access each value, and was pretty sure they had to be integers as I had plans to perform mathematical operations on them later on.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Rereading the instructions I determined there were four ways (horizontal, vertical, diagonal-right and diagonal-left) that combinations of numbers would be possible. Instead of trying to do this all at once and make one huge class with lots of sub methods, I decided that I would try each method one-by-one and if it produced the correct answer, I would stop.
This was the easiest, so I did it first.
First I tried to find the product of the first 4 numbers.
1 2 |
|
Once I was able to do this for the first 4 numbers, I tried to see if I could do this for any adjacent combiantion of 4 numbers in the first row
1 2 3 4 5 6 7 8 9 |
|
Then I figured out which product of all of these combinations was the greatest in value. As I went further down the rabbit hole I realized it would be helpful to encapsulate this logic into a method, which I did.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
At this point I decided to split my array into nested arrays, with each nested array containing a row of 20 numbers.
1 2 3 4 |
|
Once I had a nested array and a method to find the largest product, I then put the largest product of each row into a new array called answer, and then called the max method on that array to produce (what I hoped would be) the answer to the problem.
1 2 3 4 5 |
|
Unfortunately, this was not the answer, and I had to move on and see if the solution would be a vertical combination.
I now needed to make arrays of the columns from my origonal grid. I realized that I could just ‘shift’ off the first element of each of the row arrays I had previously made, and combine them into a new nested array which contained all the columns of data.
1 2 3 4 5 6 7 8 9 |
|
Once I had this new array, I then see what the largest product of 4 adjacet vertical numbers were. I essentially reused the code I did when I did this for the rows of data, just replacing what array I was using. Looking back I could have put this into it’s own method too.
1 2 3 4 5 |
|
As with the horizontal combinations, this did not produce the correct answer. I knew that I was now venturing into more difficult territory with diagonals, but I was so invested in figuring out this problem that I was actually pretty excited.
I tried to figure out what I needed to do in my head, but it wasn’t working. I went into excel and started visualizing it all, which was tremendously helpful.
I ended up determing that what I would do is make arrays of all the diagonals that went down and to the right. The green diagonals on the bottom-left and top-right represent the first and last array, since arrays beyond them would be less than 4 numbers in size. I figured if I started at the bottom-left most array and worked my way up to the top right most array, I would get all the diagonals in one fell swoop.
After some trial-and-error I was able to come up with a way to get all the numbers from a single diagonal line into an array, and then enapsulated it in a method called make_diagonal_array
1 2 3 4 5 6 7 8 9 |
|
Now that I could get a single diagonal array, I had to get all of them. I made a new array called diagonal, and shoveled each diagonal line onto it, again going from the bottom left most diagonal line to the top right most diagonal line. I used some of the same local varaible names that I used in the make_diagonal_array, which I call in the until loop. While this is a bit confusing, it was the least confusing way I could come up with at the time.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Hoping this would finally yield me the correct answer, I used the same code as I had done in the last two attempts.
1 2 3 4 5 |
|
I suppose this was just my lucky day, since this did not produce the right answer. I then went on to try to final set of combiations: diagonal-left.
For this step all I had to do was modify the code I made for diagonal-right. This time I would start at the top-left most diagonal and go down to the bottom-right most diagonal. This was suprisingly hard to wrap my head around, but I eventually did with enough fiddling.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
FINALLY!! I got the answer (it’s 70,600,674). This was quite a lot of work, but well worth it. If I were to do some serious refactoring, I could put this all into a class, further encapsulate these methods, and make it all work nicely as one program instead of 4 separate attempts. Perhaps another time though - I need to enjoy the rest of my Saturday!
]]>This is a website with hundreds of math problems that you need to solve by building a comptuer program. It is named after the 18th century Swiss mathemetician Leonhard Euler, who according to wikipedia is “one of the most prolific mathematicians ever”.
While there is some disagreement over how to pronounce Euler (some say ‘oil-er’, some say ‘you-ler’), there is a broad consensus that this is a great way to learn how to become a better programmer. However many people are intimidated by this website, since it involves math.
I’ve been going through these problems over the last few weeks and have a git repository of my work. I can say that yes it is a bit challenging, but that you learn so much that you should stop worrying, and just start doing the problems. I’ll take the problem I finished last night, and use it to show what I’ve been able to learn.
1 2 3 4 |
|
Instead of being intimidated by hard math concepts, just view it as an opportunity to hone your math skills! Math was always one of my favotite subjects in school because it made sense, and if I worked hard enough I could find a definitive answer. Perhaps I’m a bit unique in this, but doing math problems is really fun for me. For this problem, I had to jog my memory about prime numbers. I remembered that prime numbers were numbers greater than 1 that had no other factors besides 1 and itself. Not anything enlightening, but good to know I still remember middle school math concepts.
I then realized I needed to break this problem down into many smaller problems. This has been one of the most critical skills I’ve developed while at the Flatiron School. If you are unable to take a big problem and break it down into smaller sub-problems, you won’t be able to do much of anything in programming. Project Euler has been one of the best resources I’ve found to practice doign this.
Here is how I broke down problem 10.
1 2 |
|
Once I started the first step I realized I could break it down further.
1 2 3 |
|
For the second step, I already knew that what I was doing (taking an array and adding it together) perfectly fit the pattern of reduce, and so didn’t need to further break it down. Avi should be proud that I’ve developed this kind of intuition.
I ended up with some code that worked (the answer is 142,913,828,922), but was extremely slow
1 2 3 4 5 6 7 8 9 10 |
|
At this point, I let myself go on the internet and try to find a way to refactor. I stumbled upon the ruby prime guide and realized that the prime module had more functionality that I could use to speed up my program. Here is my new code that I made after doing that research:
1 2 3 4 5 6 |
|
It turns out that Prime is a class that is basically an array of every prime number. Since I am now only iterating over prime numbers as opposed to all numbers, my program went considerably faster - running in about half a minute as opposed to the several minutes it took to run the original.
Refactoring is a concept that some people get intimidated by, but by starting small and taking baby steps you can build up confidence to take on more challenging problems like refactoring huge controllers in rails.
So to all those on the fence about trying Project Euler - I say GO DO IT!
]]>When I first came across Ruby’s method ‘Inject’ I was very confused. The point of inject is to get rid of local variables that iterate when you want to do something simple like sum up the first 10 numbers.
1 2 |
|
But what this ‘Inject’ method is really doing is reducing. Reducing a range of 10 numbers into just their one sum. Reducing the number of local variables you need to keep track of. Reducing the amount of code you need to write. This is why, even after I learned about inject, the name was still throwing me off. Then I discovered that ‘Reduce’ is actually an alias to ‘Inject’ in ruby! Thank you Matz for making me happy. I’ll be leaving the notion of injecting to Ron Popeil, and will write reduce methods in my code from now on.
]]>When I was asked to present to NYC on Rails, I knew that I was limited in my knowledge of programming, and had limited time to prepare since I was spending all day in class and all night studying and doing homework. I was supposed to find a topic, research it, and make a presentation. However I was determined to build something, no matter how small. On the first day of class, Avi ripped up his prepared lecture notes and said ‘we push code from day one’ and had us make a commit to github.Curb. I came here to build things, and so build something I did.
Curb Your Flombaum takes a random quote from the blog the class keeps about Avi, calls up my phone, and speaks it back to me. Here is how I did it.
There are lots of XML parsers out there, but I choose to use feedzirra because it seemed simple and had decent documentation. First, I had to require the Feedzira, Twilio, and Amazon S3 gems
1 2 3 |
|
Then to actually get the quote I had to set the entire XML feed into a variable
1
|
|
From there I could just select a random entry be calling .sample and get just the title element (omitting any comments made beyond just Avi’s quote). The code will look like this
1
|
|
I now have the code that will give me back a string of a random Avi quote, but I need to put it in an actual XML file. To do that I’m first setting a variable xml to a string. This string is in the TwiML format, which I learned about using twillo’s excellent documentation. Twilio will automatically play an mp3 file if you wrap the url for the file in a
1 2 3 4 5 6 7 8 |
|
Now that I have a dynamic variable for what an XML file would contain, I need to save it to my computer. Ruby’s official documentation made this task relatively easy.
1 2 3 |
|
Each time I run the program, I now have a new file called ‘call.xml’ that is saved to my computer. Each time it will include a new random Avi quote. I now need to host this file on the internet in order for Twilio to be able to work. I tried a lot of different solutions, but ultimately Amazon S3 was what I went with. I made an account, created a ‘bucket’ to store my files, and then was able to write more code. First I had to put in my credentials
1 2 3 4 |
|
Then I had to actually upload the file to S3
1 2 |
|
Amazon’s official documentation left out the ‘AWS::S3’ prefix, which I had to figure out on my own. I also just made a guess on how to make the file public (it’s private by default), so they could improve that part of the documentation as well.
Now that I have an XML file with a random Avi quote hosted on the internet, I need to configure Twilio to do it’s magic. First I set my my credentials
1 2 |
|
Then I set up a client to talk to the Twilio REST API
1
|
|
Finally I give twilio instructions on what I want it to do. I want it to call my phone (the to:) using the phone number i have associated with the account (the from:) using the instructions in TwiML format I have hosted on S3 (the url:). At first this did not work, but I asked Twilio for help and they got back to me saying I needed to specify that this was a GET request (the method:).
1 2 3 4 5 6 |
|
So there is how I made Curb Your Flombaum. I have open sourced the project at github, and would love anyone to take this code and run with it. I have a lot of ideas for improving this app - maybe making the ability to sign up to get Avi quotes sent to your phone as they come in. However this was an MVP for a demo, and I’m proud to have done this after learning how to code for just three weeks.
]]>