Tuesday, July 22, 2014

Ahhhhh! It's ALIVE!



I finally deployed my listing manager app to Heroku.  For the longest time it's been sitting on local host, simply because it needed API calls to provide the content to fill the views and the API keys needed were my own.  StubHub's sandbox hasn't been working for longest time and they haven't been responsive to this issue.  So to get around this, I set up a demo account with limited permissions, basically, you can GET from the API, but cannot PUT/POST/DELETE.  The downside is it's still limited to 10 API calls per minute, which is why I'm not going to post the demo account credentials on here.  But if you'd like to take a look, get at me and I'll send you the login credentials.

New Features Added

User Permissions

As I eluded to in the intro, accounts now have permissions.  This was originally done so that I could have a demo account, but I quickly realized having a permissions table belonging to users would be helpful for managing master > sub accounts since many ticket resellers have employees who also need access to certain things (such as updating prices or creating/deleting listings) and not others (such as profit and loss, or account preferences).  I didn't do any research on the correct way to implement permissions, so my design might not be up to snuff with convention.

In short, Account has_one Permission and Permission belongs_to Account.  In the controllers, some methods have before statement that checks current_user.permission for the correct permissions.  If the user is not permitted, he/she is redirected_to the current page with a flash[:notice] letting the user know they do not have permissions to access that method.

User Settings

Some of the features in the app are susceptible to a users' unique preferences.  For instance, events change color depending on how far out the event is.  Some events, such as concerts might start peaking in sales immediately after an on-sale as well as a few weeks prior to the event, so having an event turn red three days out wouldn't be of much use.  Conversely, soccer tends to be pretty dead until one to three days from the event date.  With User Settings, each user (whether master or sub account) can set their own preferences for when events turn red/yellow/green/blue.  In addition to event date coloring, users can select how many days Recent Sales covers.  This is useful because a large brokerage may only want to see the last 24 hours, while a small brokerage finds it more useful to see the last seven to 14 days worth of sales.  And finally, users can set the chart types that show on previous event reports.



Report Charts


While this area is very much in its infancy, I though it would be useful have to charts detailing different sales metrics.  The first (and currently only) metric that has been implemented is sales trajectory.  When viewing a past event, users can see how many sales a specific event had for each month from the first sale to the event date.  The charts were made using the Chart.js framework and were really simple to integrate with Ruby.  The only 'gotcha' I came across was while injecting Ruby in the JavaScript.  Using ERB tags and passing in only the variable doesn't work, the data comes through without the proper quotes around each string.  Here was the issue and the solution:

Problem
<%= @chart_labels %>  => [&quot;January&quot;, &quot;February&quot; ...]

Solution
<%= raw @chart_labels %> => ["January", "February", ...]


More charts are coming in the near future... ideas? :)

There were a host of other small things added, like CSS styling, locking out User CRUD, and finally the process of deploying to Heroku, but all that's less interesting, so I'll omit that for now.

If you'd like to poke around, let me know and I'll give you the creds.





Monday, July 21, 2014

Form_For: Gotcha!

Hey!  Why is it that my form won't post unless I refresh the page?  The submit button simply doesn't respond to clicks. :(  Surprisingly, the answer was simple and it appears that it's not a Ruby on Rails issue, it's actually an HTML issue when using form_for.

If you're running into this issue, it would be my guess that your form is nested inside <table> tags.  That was my issue.  It seems that if you're going to put your form in a table, you *must* wrap the <table> tags with the <%= form_for @user do |f| %> ... <% end %> erb tags.

Here's a before and after of my issue (broken code and fixed code):

BROKEN CODE - Notice the form_for erb tags are nested inside the HTML table tags.


FIXED CODE - Just moved the form_form erb tags outside the HTML table tags.


If you know why this works, I'd love to hear your explanation.

Sunday, May 18, 2014

StubHub Listing Manager +





"Software is Never Done..."


"...You just kinda choose when to stop working on it."  When I heard one of my gSchool instructors, Jeff Dean, say that, it really hit home.  It allowed me to give myself permission to stop working on my last personal project.  When I started the StubHub Listing Manager +, I had one clear goal:  get all my inventory and sale data form StubHub and put it in a format that easy for me to navigate and digest.  But once I'd done that, I had a million other ideas of what I could do, and truthfully, it became a little overwhelming.  I felt as if I'd never finish this project.

The Problem

StubHub is great for the average consumer who has a couple ticket groups they want to sell or buy.  But if you have a large inventory of tickets, navigating your inventory and sales is a cumbersome process because their take on inventory management is: "Let's list everything the user has for sale on a single page, in chronological order."  There isn't any sorting by date or by event.  There's no clear way to find out how many tickets you have a for given event, how close each event is, or where exactly your prices stand in comparison to other tickets on the market.  You can get that information, but it involves you clicking between multiple screens, writing down information, and manually comparing it to your own.  Simple if you have a couple tickets for sale.  Not simple if you have hundreds or even thousands of tickets for sale.

The Interim Solution

Most large sellers will get a third-party point-of-sale system that holds their inventory and allows them to view it in a sortable manner and provide them with detailed information about the current market, their individual ticket groups, and previous sales.  The catch is, these third-party point-of-sale systems cost between $200-$300 per month, charge you an additional fee per sale, require you to have a credit card processor, business phone lines, deal with chargebacks, handle shipping on your own, and take care of your own customer service.  I did that for a few years, but ultimately found that the overhead wasn't justified.  Well over $1000 per moth went into managing my own inventory.  And the headaches of customer service, dealing with credit card processing and shipping just weren't worth it.  Luckily, if you sell only on StubHub, they handle all that for you (sans inventory management) and charge you 15% per transaction, which is a little higher than handling it on your own, but well worth not having to deal with all the aforementioned headaches.

The New Solution

So after a few years of doing all on our own, we decided to shut it all down and only deal with StubHub.  The problem, as mentioned above, is that inventory management is a huge hassle because it has to be done manually.  So with my new programming super power, I decided to create my own makeshift inventory manager that GET's, POST's, PUT's and DELETE's from StubHub's API, essentially putting the burden on them.  In addition, to verify that a sale has been paid (which a point-of-sale would do for you), I integrated my inventory manager with the PayPal API to verify that the sale StubHub shows, has actually been paid out.

After some quick Bootstrap styling, it's as done as I want it to be... even though there's loads of other features I still think about adding.  Above is a brief video of the finished product.

PS

I learned that all API's are not made the same.  StubHub's API is poorly maintained, lacking a lot information, and their developer support is virtually non-existent.  Kind of sad for such a large company, but it taught me that sometimes you have to fiddle around... a lot... to get things to work.  Because that's the only way it's going to happen.  PayPal wasn't much different.  While they have new RESTful API's that are supposed to be easy to work with, all the information I needed had to come from their Classic (ahem.. Outdated) API's.  I ended up using their SDK gem instead of doing it all manually because it was such a huge pain in the rear.

24 Hours of Le Google (GovDev Hackathon)

1:30 AM - After two-thirds had gone to bed or given up

24 Hours of Le Google


I would imagine it's similar for most budding developers.  Their first endurance hackathon is an eye opening experience into the world of professional software development.  It's more a la Formula 1 than nerds (me included) lapping between their computers, pizza slices and empty Red Bull cans, as mainstream media or even my own pre-hackathon imagination would depict.  So what might you expect?

Off to the Races

Enter Galvanize Denver, the venue of 24 Hours of Le Google (GovDev Hackathon), registration booths manned with pre-printed name tags, free Google swag (t-shirts and water bottles), staff in matching orange shirts, Google colored race banners streaming the ceiling, catered breakfast, and in the main room... the horse and pony show.

Teams arrived with matching computer terminals, small tables packed with 27 inch Apple iMac's paired with 27 inch Apple external displays.  The most impressive team having four such stations all packed into a small table.  Many teams were split into 'pit' duties, the UX guy, the backend guy, the frontend guy, the mobile guy, the project manager ('guy' in the general, non-pejorative or exclusionary sense... some of these 'guys' were gals).  The air of competition was apparent. No one was too friendly or too talkative, they were all there to win.

Leading up to 'go time', there was a parade of who's who in state tech and Google big-wigs.  Talks from the CEO of this, the CIO of that, and the COO of the other, all sharing their ideas of why this was an important race and why what we were doing was furthering private citizen/sector involvement in making government more efficient.  They sold me, I was excited to be part of it (and still am).  After the talks came the challenges:  take this data, make it public and understandable to the layman; take these horrible relics of bureaucracy (repetitive paper forms), digitize and streamline them so that they're easy to complete on a mobile device and pass the completed product to all affected departments to streamline coordination; and finally, take this paper-based donation and dissemination program, make it mobile and seamless.  The last two challenges having to do with disaster response and preparedness, the first challenge dealing with government expenditures and transparency.


We Had no Idea

What started as a team of three (@FindingFixes, @ScottSkender, and I), had no idea the complexity of the tasks we'd been presented with.  We chose to take the challenge of making government expenditures transparent.  It seemed straight forward. Take these CSV files with a half-million line items and make it understandable to Jane and Joe Doe.  Create a filterable dashboard with charts, include map integration, and toss in a few Google API's to meet the minimum requirements.  Much to my surprise, our little laptops didn't like CSV files with a half-million lines.  They were too big!  And taking legacy data formats and converting them into usable content (like converting to JSON or importing into a PostgreSQL database) was more difficult than anticipated.  After 3.5 hours of hacking away (and getting nowhere), one of our members decided it was time to call it day.


And Then There Were Two

I'd had had it with this 'big data' challenge, it was more than I had bargained for and was a touch outside of our team's technical savvy.  So my partner (Seth Musulin) and I started on another challenge that seemed to compliment our technical chops.  The inventory management challenge to track donations and dissemination of donations.  It was to be a CRUD app of donation items, victims, and the donation items they'd been given (that's the superficial view of it).  After 3.5 hours of getting nowhere on the first challenge, having created a database table and an app that CRUD's donation items in the first 30 minutes felt like a huge accomplishment!  We felt as if we'd made a massive accomplishment... until we started understanding what else was needed. hahaha.  Now that our app can take in donations, we need to CRUD people, then we need to checkout these donations to people, then allow staff to search for donations by location, item type, donor, etc.  Easy enough, right?  Unfortunately, that wasn't the hard part.  While doing all that took our team of two until 1AM (having started at noon), we now had to make it work seamlessly from a user experience point of view... and... it had to look good.  But it was 1AM and having seen other teams nearly complete with some super-sexy, ultra functional, and utterly seamless apps... we knew there was no way we could get it done it time.  So my partner and packed our bags and called it a day.  Considering two-thirds of the original competitors had already left, I feel like we hung with the best of them... although our app surely didn't.

Lesson Learned

These guys take endurance hackathons seriously!  They plan teams where each person is a well-oiled, integral cog in a finely tuned software producing machine.  They don't play around.  They know their strengths and they avoid spinning their wheels on tasks that don't fit their skill-set.  For future endeavors, I'll be part of larger team with varied disciplines and I'll stick to what I know.  While it was a great opportunity to learn some new technologies, like Apache Solr (for fulltext and location-based search), and JavaScript location services, it was certainly not the venue to 'learn' if your intent was to finish and possibly even win.  That said, I'll do it again, and again... and again!  It was a great time, but certainly not what I'd expected.


Tuesday, May 13, 2014

T's OBGYN Patient Intake App - My Very First App!

My first personal project at gSchool was a very simple Sinatra + PostgreSQL app for my lady.  She had been complaining that she had to type out these ridiculously long text messages to her team every time she took in a new patient in triage, and that her life would be so much simpler if technology could do it for her.  Lucky her!  I happened to know exactly how to do it :)

So I made a simple form, styled with Bootstrap, that took all the required inputs, formatted them, saved them to a database (in case she wanted needed the data in the future), then gave her the option to: a) text the results to herself or someone else, or b) copy and paste the results.



There's a lot of fields to this form, but it kept her from having to manually type each one.   A little bit of background on its purpose.  She's an OBGYN and every time a new patient comes in, she has to get a history for each patient including such things as: how many times they've been pregnant, number of miscarriages, successful births, results of various tests, the weight of previous children at birth, the current baby's weight, etc.  Luckily, all of the information is anonymous, in that there is no identifying information that could possibly link this info to patient, so no need to worry about HIPAA.  Anyway, when the information is gathered, it's sent out to the team on call so everyone is aware of the current patients, their history, and possible complications.

Since all of the fields above are attributes of a single patient, I put them all in the patient class, which was ugly... nearly 20 instance variables!  Luckily there's a way to make that look decent:

1:  require 'patient_repository'  
2:    
3:  class Patient  
4:    
5:   ATTRIBUTES = [  
6:     :age, :g, :p, :at_weeks, :at_days, :by_weeks, :by_days, :ultrasound, :prenatal_care,  
7:     :placenta, :group_b_strep, :one_hr_diabetes, :three_hr_diabetes, :history, :times_delivery_type,  
8:     :largest_baby_birthed, :estimated_fetal_weight_lbs, :estimated_fetal_weight_oz, :efw_by,  
9:     :sterile_vaginal_exam_time, :sve_dilation, :sve_effacement, :sve_station, :comment, :time  
10:   ]  
11:    
12:   attr_accessor *ATTRIBUTES  
13:    
14:   def initialize(options)  
15:    ATTRIBUTES.each do |attr|  
16:     instance_variable_set(:"@#{attr}", options[attr])  
17:    end  
18:   end  
19:    
20:   def attributes  
21:    Hash[ATTRIBUTES.map { |name| [name, instance_variable_get("@#{name}")] }]  
22:   end  
23:    
24:   def validate  
25:    ATTRIBUTES.each do |attribute|  
26:     replace_attribute = ['', '--'].include?(instance_variable_get("@#{attribute}"))  
27:     instance_variable_set("@#{attribute}", nil) if replace_attribute  
28:    end  
29:   end  
30:  end  

Instead of initializing ~20 instance variables, I put them into an attributes array and iterated through the array in the initialize method.  This did two things, solved a potential security vulnerability and also made the class look a ton cleaner.

Also, since not all the values were required and the database wasn't too keen on taking empty strings or '--' values in integer cells, I made a validate method that checked the form inputs for these and replaced them with nil.

Below is a screenshot of what the database:




After all the values have been input and submitted, below is the results.  What really made my day was being told that this little app now saves my darling about hour per day!  Nothing like producing software (in my first month of gSchool) that is actually used in a professional setting :)


If there are any OBGYN's out there that think this would be useful for them, feel free to use it: 

http://www.tiare.herokupapp.com

It's optimized for mobile, and kind of looks poopy on desktop.  But hey, it was my first app, ever!

As a PS, I looked all over GitHub for a for an active gem that allowed sending text messages through Google Voice.  Unfortunately, there weren't any active gems... so I had use some code from a blog I read and repurpose it for my app.  I'll have to scour Google SERPs for the blog (because he deserves the credit) and add it later, since I didn't bookmark it.


1:  class TextMessage  
2:    
3:   attr_accessor :data, :phone_number  
4:    
5:   def initialize(data, phone_number)  
6:    @data = data  
7:    @phone_number = phone_number  
8:   end  
9:    
10:    
11:   def text_message  
12:    login_response = ''  
13:    
14:    url = URI.parse('https://www.google.com/accounts/ClientLogin')  
15:    login_req = Net::HTTP::Post.new(url.path)  
16:    login_req.form_data = {'accountType' => 'GOOGLE', 'Email' => 'pt.intake.generator@gmail.com', 'Passwd' => '****************', 'service' => 'grandcentral', 'source' => 'tiare.herokuapp.com'}  
17:    login_con = Net::HTTP.new(url.host, url.port)  
18:    login_con.use_ssl = true  
19:    login_con.start { |http| login_response = http.request(login_req) }  
20:    
21:    url = URI.parse('https://www.google.com/voice/sms/send/')  
22:    req = Net::HTTP::Post.new(url.path, {'Content-type' => 'application/x-www-form-urlencoded', 'Authorization' => 'GoogleLogin auth='+login_response.body.match("Auth\=(.*)")[0].gsub("Auth=", "")})  
23:    
24:    req.form_data = {'id' => '', 'phoneNumber' => @phone_number, 'text' => @data, '_rnr_se' => '********************'}  
25:    con = Net::HTTP.new(url.host, url.port)  
26:    con.use_ssl = true  
27:    con.start { |http| response = http.request(req) }  
28:   end  
29:    
30:  end  

I totally lied...

A while back ... my last post... I stated that I was going to make my own blog from scratch.  Needless to say, my ambitions got the best of me.  I had no idea what I was in for at gSchool.  No one told me that the ability to program was like a super power and once you know (even a little) how to program, you'll want to take over the planet with all the ideas that cross your mind.   At least that's what happened to me.   Anyway, I'm not making a new blog, yet.  This will do while I work on more interesting projects.  

In my next post, I'll show off a couple apps I've made recently:  A patient intake generator that takes input, generates a formatted output and allows you to text it via SMS (through a Google Voice hack) that I made for my significant other; and a StubHub inventory manager that utilizes StubHub's API to present inventory and sales in a better format and also ties in with PayPal's API to verify that StubHub sale has been paid.  

Maybe I'll do a rant on gSchool, too. :)

Tuesday, March 18, 2014

Silence

Hey all, I just wanted to update everyone... I've been silent, because I've been slammed with gSchool work.  I'm planning on moving to a blog created by me and not hosted on blogspot... so stay tuned :)  More to come, I promise!

Monday, January 13, 2014

gSchool Prep



It's time to prep!  gSchool has sent out the list of things to accomplish prior to the first day, and here's what it's looking like:

Typing
  • Watch a 1-minute video by a master coder/typist {complete}
  • Spend 20-30 minutes/day on Typing.io
Reading
  • Extreme Programming Explained by Kent Beck
  • How to Count by Steven Frank
  • The 5 Elements of Effective Thinking by Edward B. Burger
Coding
  • Codecademy Web Fundamentals {complete}
  • Codecademy JavaScript
  • Codecademy Ruby {complete}
Not so bad, eh?  The only thing I'm dreading is doing the JavaScript lessons and Typing.io lesson.  I've been avoiding it, but as this list gets closer and closer to completion... the more I have to do it.  Ughhh.

Typing.io is a pretty cool web app.  I was pleasantly surprised at my typing (code) ability.  My average over ~22,500 is 52 WPM, though lately I've been consistently in the 60's and even in the low 70's.  What's even more cool is that it shows you the amount of useless keystrokes (10% currently), and your total time spent practicing.  The biggest issue I'm having now is finding out how to effectively reach for the special characters and get back to the home row.  That's been killing my accuracy and speed.  I should add, these stats are mostly for Ruby.  When I do JavaScript lessons, my WPM drops like a rock, somewhere in the low 40's.

On another note, I've tweeted with a few soon-to-be fellow students.  Interestingly, two of the four I've connected with have also lived in Japan and one seems to speak fairly fluently.  This should be an interesting class!  gSchool just opened up the Google Group for the incoming class, so I'm really looking forward to connecting with the others. :)

Completely off the topic of gSchool, I met with another person who recently finished DevBootCamp - one of San Francisco's oldest and most respected code bootcamps - and picked his brain about his experience.  He said that it was a great program, but because of how short it was and the hours required (~80hrs/wk), he felt like the biggest downfall was that you didn't have time to work on your own projects.  He said that's important because when you're interviewing, it helps a ton to have stuff on GitHub that you've done from start to finish.  That little bit of feedback has caused me to set a goal for myself:  while in gSchool, have a personal project that I can complete by the end of the course.  I've already got one in mind, but I'm not sure if it's too complicated to do on my own and with the little time I will have over the next 6 months.


Friday, January 3, 2014

Brick Wall

So I've been knocking out Codecademy.com's tutorials... I've finished Web Fundamentals and Ruby, and am now working on JavaScript.  I really enjoyed Web Fundamentals (HTML5/CSS3) and Ruby, but have found JavaScript to be a like a nagging girlfriend (luckily I haven't a nagging girlfriend in years).  Uhhhh! It's so picky and forces my attention to detail to be nothing but perfect.  I've been working on a rock, paper, scissors game that's been kicking my butt, all these curly braces and semi-colons are driving me nuts!

I read another person's blog that talked about the brick walls we hit while learning programming, and how overcoming those brick walls is what makes the difference between someone who will succeed in programming and someone who will ultimately give up or fail.  That's what keeps me trudging away... the obstacle of JavaScript will be overcome!  But I must say, I am not a huge fan of JavaScript, the syntax is nowhere near as enjoyable as Ruby.

On another note, I dropped off my $1,000 deposit at gSchool!  I'm in... now all I have to do is come up with another $4,000 before the start of class.  I took some money out of my Roth IRA and am driving for Lyft in my spare time to come up with it.  And, my parents offered to co-sign on a loan if I need more money to make this happen.  According to my interviewers, the problem most students have at gSchool is living expenses for the 6 months of school, since you can't work outside of school.  Luckily one of my companies makes money with minimal time investment on my part.  Things are well on their way!  Hopefully by September of this year I will be a Junior Developer at some awesome startup.