Saturday, January 5, 2013

How to post facebook app wall feeds onto your own website domain

So here's the problem:  You want to repost a facebook wall status feed onto your own website, what are your options?

You could use pure javascript and this seems to be a popular option.  So why did I not use it?
  1. Using js is not persistent.  if you need to be able to display your entire history of posts, you will need to store them locally which is not possible if using a js only solution
  2. Server side authentication.  I needed to learn more abour rails and the fb api.  It is by fb's own admission the most difficult way to do things, but it has a lot of advantages as will be described in a moment.

What I used to do:

I used to use the hidden rss feeds from facebook to pull the wall feeds using git://github.com/pauldix/feedzirra.git

This was in line with the wonderful railscasts from ryan bates : http://railscasts.com/episodes/168-feed-parsing

So why not continue to use this methodology?  It's simple and it works.  However, the images embedded within the feed are ridiculously small from 90 to 130px in width which make great thumbnails but has little visual impact.

Thew new solution was to leverage the most awesome gem: koala

I was able to make this gem work for a little while late 2012, but evidently the oauth response change the 1.0 version no longer functions and I needed to use the latest version of the gem
gem "koala", "~> 1.6.0rc1"
for fb to respond properly and produce a token.

Besides just an interesting exercise in accessing facebook, why would you go through so much more trouble?

The ability to format and use/skip entries is the holy grail.  If you look at the github repo https://github.com/kimkong/koala-facebook-feed and the feed_helper.rb you will see that there are a lot of different kinds of updates.
The problem is that the facebook docs are not entirely clear on the distinctions between the combinations of entry_type and status_type.  It is possible to have a status_type without a entry_type.

The helper is the product of a purely exploratory endeavor.  I looked at the most common types of posts that my clients were making and made sure that I produced formatted output for those types.  The other types (status posts from others that have no real meaning as a feed) are not displayed at this time.  

There is the possibility of some false negatives; some statuses might be thrown away that shouldn't be.  If you find any such errors, please let me know :)

Oh and another thing, make sure when you setup your developer app on facebook that you have the url set to localhost:3000 when testing and reset it to the domain of your project when ready for the world.

Hope this helps!  I know I spent way more time on this than I envisioned, but sometimes it takes time to develop understanding.



Friday, November 16, 2012

Custom Domains on Heroku : to zerigo or not to zerigo

So, I'm using Heroku for some smaller projects and while the documentation from Heroku is fairly good, for me it helps to re-process the information for my own understanding.

So, https://devcenter.heroku.com/articles/custom-domains has all the good stuff.

The decision tree:

  • Domain Purchased (do not confuse with DNS)
  • DNS purchased
    • Set the following records:
    • Three (3) A name records with example.com pointing to the 3 IPs listed in the url
    • CNAME record
      • *.example.com pointing to myapp.herokuapp.com
  • DNS not purchased
    • Use Zerigo basic (or the other levels)
    • Zerigo presets the 3 A records
    • You have to add the redirect for www to the domain

It took me a while to really understand how all the elements fit together especially since different providers such as GoDaddy, 1&1, Nettica, dyn.com, Zerigo and the list goes on and on have all completely different interfaces for accomplishing what I needed to do.

This was especially true when setting mail records.

If you are using google apps for your mail, you need to set the 5 MX records to the google app specs which Zerigo so conveniently has a snippet for.

If you need to setup aliases, the mechanism depends on the DNS server and the actual hosting web server.  I use a vps for most of my apps, so I can set the aliases via the cpanel or the terminal.  However, from poking around it looks like some dns services have this ability as well.

Anyhow, this isn't ground breaking information, but it took me a few tries to understand when to use and more importantly not use zerigo with heroku.



Friday, October 19, 2012

What to do when the heroku named app no longer matches the git

Evidently I changed the name of the app on Heroku using the web interface and was no longer able to push my code into heroku.

After poking around the Heroku help files, using the command line tools was ultimately unhelpful to do a rename.

What worked for me was the following:

  1. Verify the name of the git repo for the heroku app under Settings.
  2. Check what git thinks the remote repos are.
$ git remote -v
heroku    git@heroku.com:repo-name.git (fetch)
heroku    git@heroku.com:repo-name.git (push)
origin    git@gitrepo.com:arrow/repo-name.git (fetch)
origin    git@gitrepo.com:arrow/repo-name.git (push)

  1. Edit the .git/config file
 for me the offending portion was in the [heroku] section as it still pointed to the randomly generated name from Heroku instead of the named repo I had renamed it to.

  1 [core]
  2   repositoryformatversion = 0
  3   filemode = true
  4   bare = false
  5   logallrefupdates = true
  6 [remote "origin"]
  7   url = git@gitrepo.com:arrow/repo-name.git
  8   fetch = +refs/heads/*:refs/remotes/origin/*
  9 [remote "heroku"]
 10   url = git@heroku.com:repo-name.git
 11   fetch = +refs/heads/*:refs/remotes/heroku/*


5 minutes fix.  Wish all my bugs were this easy to fix.

Thursday, October 18, 2012

Rails page cache sweeping

Fwoosh fwoosh.  Caching is easy.  Expiring those caches on the other hand can drive you absolutely crazy.

Two things I've learned.

Expiring the cache when your Model is used in a single monolithic pattern is a piece of cake.  Following any standard documentation is easy peasy.

However, one of my Models generates an N number of directories and files dependent on the user's setup.

For example, SiteA can have About Us, FAQ, and Contacts as directories with a number of db served pages for each that are cached.

After many many failed attempts here's what I've learned:

  1. You must setup in config/application.rb the config.active_record.observers = :observer or it will never be found.
  2. Sweepers need to be explicitly told which model to observe "observe :model"
  3. use of {page.cache.directory} needs to be more explicit with  "#{ActionController::Base.page_cache_directory}"
  4. For situations where mass numbers of pages need to be expired simultaneously, be very careful in the use of FileUtils.rm_rf improper usage can blow up your file system.

The last one was a tip learned from the venerable Ryan Bates of Railscasts fame -- of course I'm a subscriber. 

Additionally, when I had a Model that generated a single directory with n number of pages inside such as when caching a paged view, the solution was to do:

FileUtils.rm_rf "#{ActionController::Base.page_cache_directory}/directory"

But I had one model that produced an unknown number of pages.  At first I wanted to hard code the directory structure by copy and pasting the above line changing the final directory.  But that's just stupid.  I've learned that every time I found myself hacking out that pattern that I needed to stop, and rethink the problem.

Since the problem was DB generated, the solution had to be as well.

I simply yanked out all the pathnames from the db and rm -rf each of those.

Model.all.each do |page|
  FileUtils.rm_rf "#{ActionController::Base.page_cache_directory}/#{page.path}"
end




Page Caching and selectively preventing it

I was told this joke from my brother:

There are three problems in programming -- First is counting.  Second is expiring caches.

Me being the idiot that I am asked, what's the third one?

Sigh.

So page caching in Rails is *simple*.
go to Controller, add:

  caches_page :show  


Clearing the cache was an entirely different proposition, but I'll talk about that later.

So here's the scenario.  I have a simple CMS system in place for my project.  it allows the user to create, edit the content for their website.  It also has special editable content pages that are secured using Devise (an awesome gem btw).

The problem was that the secure pages were being cached as well.  Having a html file created in the public directory is a double edged sword.  Having it there meant that the Rails stack (which is slow) never gets called, Yay!  But it also meant that the secure information was now accessible in the public if anyone knew the path to the file.

The only way to authorize those pages was to have it run through the Rails stack.  So I needed to not cache those pages.

On Apidock I found an interesting little snippet using a Proc to prevent caching based on the response type.  Not quite what I needed, but it was on the right track.

1:  # cache the index action  
2:  caches_page :index  
3:  # cache the index action except for JSON requests  
4:  caches_page :index, :if => Proc.new { |c| !c.request.format.json? }  
5:  # don't gzip images  
6:  caches_page :image, :gzip => false  

My standard learning/exploration tool is the debugger tool.  I toss a debugger in the code and see what is available in that specific scope.  Inspecting c was unmanageable as page after page of code screamed past.  What I needed was a way to walk through it in smaller steps.  Google to the rescue!  I found that I could list the params of the object [ c.params].  Ah hah!  Now, I could determine which page was being shown based on the id and from that it was a relatively simple matter of creating an array to check against.

  caches_page :show, :unless => Proc.new { |c|
    secure_pages = Page.find_by_path("secure").pages.map { |page| page.id }
    secure_pages.include? c.params["id"]
  }


To my eyes, it looks simple and clean.  But as a novice, I'm still always worried that I'm doing things the hard way, or worse, the wrong way.


---------------------------

So, I ran into a little glitch.

Having it find_by_path returns a nil when there are no secure pages but a .where('path = ?', 'secure') return an []

The former blows up when I don't have a secure page, the latter gracefully just doesn't find anything.

Gotta love those subtle differences.