05 Dec 2015
Why
After years of running my own WordPress instance on a VPS I decided to call it quits. Maintaining a server just for running a simple blog kind of got tiring. I spend enough time worrying about backups, security, availability, etc in my day job. Not to mention I was paying more than I pay for my monthly Netflix subscription to keep a resource hog like WordPress humming along.
Although I still liked the hackability of WordPress, so moving to something like Medium or hosted WordPress didn’t seem too appealing.
Search
After a bit of Googling, I decided to go with a static site generator. I liked the idea of being able to host the site virtually for free while retaining full control over the look and feel.
There are many static site generators out there but given Jekyll’s community and my familiarity with the Ruby ecosystem, it was an easy choice. Jekyll would allow me to tinker with the platform without worrying about tedious maintenance.
Now that I had settled on a new home for this blog, I had my work cut out for me. Here’s how I went about the migration:
Data Export
So the first task was figuring out how to get the existing posts out of WordPress. There are couple of options:
-
jekyll-import gem supports importing posts from WordPress among many other platforms and gives you a good amount of control over what you want to import.
-
Jekyll Exporter is a WordPress plugin which makes the job even easier. It packages everything up in a nice zip that you can download and drop into Jekyll.
I went with the latter option since it saved me the trouble of installing Ruby on my VPS or opening up my DB to accept external connections.
Look & Feel
Now that I had the basics figured out, I started looking for a nice theme that I could use as a jumping off point. I browsed Jekyll Themes to find Hyde, a carefully crafted theme built by Mark Otto.
“Installing” the theme was pretty straight forward, I just forked the repo and dropped the contents of my _posts
folder in there.
Customizations
After getting the theme up and running. I went about making a few modifications of my own:
-
Changed the default homepage to be a landing page rather than a blog. It involved moving the main index.html into blog/index.html and creating a new index.md at the root with custom landing page content. I had to create a blog folder because of this bug (or feature?) where paginator is only made available in index.html
-
Added a custom archive page. I borrowed the markup for it from Reyhan Dhuny’s post with some minor adjustments of my own.
-
Changed the default syntax CSS for Pygments with the one found here.
-
Made some tweaks for SEO such as adding a sitemap using the jekyll-sitemap gem. Also added standard meta tags and Google Analytics for tracking. I also plan to implement post specific meta tags at some point.
-
Added a call to action at the bottom of every post inspired by Joshua Lande’s excellent post about his own experience moving to Jekyll.
Hosting
Now the last step was figuring out where to host this site. Official Jekyll website has pretty much documented all the deployment options out there. Simplest one out of them was to use GitHub Pages which comes with built in support for Jekyll and it’s free!
All you have to do is create a repository named username.github.io
, where username is your GitHub username. Once you commit your project, it will automatically be deployed to http://username.github.io URL.
You could also have your custom domain point to that location. Just have to create an A record pointing to GitHub Page’s IP in the DNS settings and add a CNAME
file at the root of your project with your domain listed in it. You can find detailed instructions here.
That was super easy to setup and only took a couple of minutes. Although one thing to keep in mind, GitHub Pages use Jekyll 2.x. So if you are working on Jekyll locally, you’ll want to add github-pages to your Gemfile
so the local version of Jekyll and its dependencies are in sync with what GitHub Pages uses to avoid any inconsistencies based on environment.
Moving Forward
One thing I missed was having a nice WordPress editor where I could work on draft post as and when I please.
Luckily I was able to setup a very similar workflow using prose.io which is an excellent content editor for GitHub specifically designed for static websites like this. It has many configuration options allowing you to setup live previews, image uploading, etc. Definitely worth checking it out.
Lastly I’ve leave you with this screenshot of one of the metrics from my Google Webmaster Tools account.
That huge drop in page download time is, as you’d guess, right after I made the switch to Jekyll. I’m hoping that will eventually also translate into a bump in the search rankings as I’ve read Google now considers speed as one of the small factors in determining the results.
Anyway, that’s it for now. Stay tuned with more updates on my adventures with Jekyll and it’s ecosystem.
12 Sep 2015
In this post I’ll show you how to build your very own entertainment hub in about a $100 bucks. It should be capable of doing almost everything that a Roku, AppleTV, AmazonTV or Chromecast can do and more.
Requirements:
Hardware
Software
- Boot Loader - We will use a software called NOOBS which is a boot loader for RPi that makes installing new operating systems on the device a piece of cake.
- Platform/OS - There are couple of open-source media center platforms that you can use for your setup such as Kodi, Plex and Emby. I decided to go with Kodi since I found it to be very customizable with a wide variety of available plugins. There are couple of OSes such as OpenELEC, OSMC and Xbian which are specifically geared towards running Kodi on RPi. I went with OSMC since it’s actively maintained with regular updates, it’s based on Debian and has a pretty good UI/UX. So that’s what I’ll be focusing on in this guide.
Steps:
Once you have all the required hardware, we are ready to put this thing together!
- Format SD Card
- Download & install SD Formatter 4.0 for your platform.
- Insert your SD card into the computer or SD card reader and make a note of the drive letter allocated to it, e.g. G:/
- Run SD Formatter, select the drive letter for your SD card and format it.
- Install NOOBS
- Download NOOBS (offline and network install)
- Extract the files from the zip.
- Copy/paste all the files from the extracted NOOBS folder into the SD card.
- Hookup RPi
- Insert the SD card into your RPi
- Now place the board in the case. If you bought the clear case listed above, it should be easy to snap on, no screws required.
- Plugin the ethernet cable to your router/switch. If you don’t have easy access to the ethernet port, hookup the wireless USB adapter instead. Although keep in mind wired setup will generally be faster compared to wireless.
- Connect the HDMI cable with your TV
- Plugin the USB adapter for the wireless keyboard
- Lastly, plugin the power source. If your TV has an USB port, use that so your RPi is only powered on while your TV is on. If that’s not an option, hook it up to the standard AC adapter. RPis are designed to stay powered for a long time, so other than the minor inconvenience of manually turning it off, it’s a safe option.
- Install OSMC
- Now switch your TV source, you should see your RPi booting up to the NOOBS screen.
- Once booted, on the selection screen, choose OSMC and hit “Install”.
- Follow the wizard steps to complete the installation.
- All done! - Now that you are all done, there are couple of things you can do to make your experience with Kodi/OSMC even more enjoyable
- Download the official remote apps from their respective app stores so you can control your Kodi without the keyboard. Although I’ve had better experience with Yatse on Android and SYBU on iOS. Just make sure to give it permissions by going to
System -> Settings -> Services -> UPnP/DLNA -> Allow remote control via UPnP
- If you use Chrome, download the Play to Kodi extension so you can send content from sites like YouTube to your Kodi from your browser. Again make sure appropriate permissions are given by going to
System -> Settings -> Services -> Web server -> Allow remote control via HTTP
- Kodi also supports HDMI CEC which lets you control it from your TV remote, make sure to enabled by going to
System -> Settings -> System -> Input Devices -> Peripherals -> CEC adapter -> Enabled
. Click here to check if you TV brand supports it.
- Lastly, add SuperRepo to your Kodi to get access to thousands of addons. Here’s the step-by-step instructions on how to go about installing it.
That’s it for now. Comment down below and let me know how it worked out. Enjoy!
23 Aug 2015
I recently ran across the need to build a complex ActiveRecord query which called for conditional joins and lookups based on certain parameters.
My options were to either write a raw SQL query which would be hard to maintain or end up doing in-memory operations after a certain point which would be detrimental to performance. So I decided to take a different approach which would let me cleanly write the query while avoiding those pitfalls.
The best way to demonstrate the technique is by showing you an example. So say we wanted to list all the upcoming music gigs in a city and optionally search for a specific venue/band and paginate the results using a scope like this:
Gig.upcoming({venue: 'Fillmore', band: 'Doors', 'page': 1})
To implement a scope like that, we’ll need to make use of something like tap
which is built into Ruby 1.9+. It’s basically a helper for method chaining. Let’s look at how tap
is implemented at it’s source:
VALUE rb_obj_tap(VALUE obj)
{
rb_yield(obj);
return obj;
}
That basically translates to this in Ruby:
class Object
def tap
yield self
self
end
end
So let’s make use of that to implement the scope like this:
class Gig
delegate :genre, :to => :band
belongs_to :band
belongs_to :venue
delegate :region, :to => :venue
scope upcoming(options = {}), -> {
where('start_date > ?', DateTime.now).tap do |query|
#Perform conditional logic here and return the query...
query
end
}
end
But looks like there is a problem. None of the conditional queries inside the tap
block seem to be taking effect. Taking a second look at how tap
is implemented, it makes sense. tap
passes it’s object into the given block and after the block finishes, it returns the object. But in our case, what we need is the return value of the block itself not the object.
So let’s make that change and introduce a separate method which can do exactly that. We’ll call it let
and add it to Ruby’s Object class (open classes FTW!):
class Object
def let
return yield self
end
end
Now we can implement the upcoming scope on the Gig model something like this:
class Gig
delegate :genre, :to => :band
belongs_to :band
belongs_to :venue
delegate :region, :to => :venue
scope upcoming(options = {}), -> {
where('start_date > ?', DateTime.now).let do |query|
if options[:venue].present?
query = query.include(:venue).search(venues_name_cont: options[:venue]).result #ransack DSL
else
query = query.where(featured: true)
end
if options[:search].present?
query = query.search(name_and_description_cont: options[:search]).result #ransack DSL
end
if options[:page].present?
query = query.page(options[:page]).per(20) #kaminari DSL
end
query
end
}
end
Now I know this particular example can be written in many different ways and may not make the best case for making use of a let
method. But in more complicated cases this isn’t possible which is where let
would come in handy.
Anyway I’d love to hear about what other techniques are out there for building complex AR queries. Share your thoughts in the comments.
15 Mar 2015
I was looking for a good way to generate website thumbnail previews for the end-user which would load near instantly. With a quick Google search I came across services that can take a screenshot but they were neither free or fast. So I set out to create my own home brewed solution which looked something like this:
I’m going to use KnockoutJS which is a MVVM JavaScript framework for the purpose of this demo just for the convenience factor. You can do this in plain old JavaScript as well if you wanted to.
TL;DR: Scroll to the bottom for a link to the demo
HTML:
<div class="live-example">
<input data-bind='value: myURL' />
<button data-bind='click: initLinkPreview'>Show Preview</button>
<!-- ko if: showPreview -->
<iframe class="link-preview" data-bind="attr: {target: '_top', src: myURL}" sandbox='' scrolling="no" />
<!-- /ko -->
</div>
Key part to note in the HTML is that we are loading the iFrame in a sandbox mode to make sure it loads the link with a white-list of restrictions to mitigate any risk of malicious activity.
CSS:
.live-example {
height: 200px !important;
overflow: hidden;
}
.link-preview {
width: 1028px;
height: 800px;
border: none;
pointer-events: none;
-webkit-transform: scale(0.2);
-moz-transform: scale(0.2);
-ms-transform: scale(0.2);
transform: scale(0.2);
-webkit-transform-origin: 0 0;
-moz-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
}
The main crux of this technique comes down to the transform
CSS property which will allow us to render the URL in a full sized iFrame and then scale it down to a smaller size to make it look like a thumbnail. Also as you can see, the container class .live-example
has a height restriction of 200px to hide the space that the browser will initially occupy to render a full-sized iFrame.
RoR:
def get_headers
meta = open(params[:url]) { |f| f.meta }
render :json => {status: "success", headers: meta}
end
I also created a back-end endpoint (in this case in RoR) to return the website headers to the front-end. This is to allow the front-end to detect if the site which we are loading allows itself to be rendered in an iFrame. Lot of mainstream sites such as Google and Yahoo explicitly set X-Frame-Options
header to avoid Clickjacking attacks, etc. By doing this we can control the UX and make sure we either show a default thumbnail or hide the area in which we were supposed to render the iFrame in case the X-Frame-Options
header was set to DENY
or SAMEORIGIN
.
JavaScript:
var MyViewModel = function MyViewModel() {
var self = this;
self.myURL = ko.observable();
self.showPreview = ko.observable();
self.initLinkPreview = function () {
$.ajax({
type: "POST",
url: "/get_headers/url=?" + self.myURL(),
success: function (data) {
var headers = data.headers;
if (headers['x-frame-options'] && (headers['x-frame-options'].toUpperCase() == 'DENY' || headers['x-frame-options'].toUpperCase() == 'SAMEORIGIN')) {
self.showPreview(false);
} else {
self.showPreview(true);
}
}
});
};
};
ko.applyBindings(new MyViewModel());
So lastly the JS ties everything together. It grabs the URL from the front-end, checks with back-end to see if it’s kosher to render it in an iFrame and then either shows or hides the iFrame with that URL.
Demo: http://jsfiddle.net/2jv7n2q7/37/
30 Nov 2014
I wanted to create a Rails Concern which can accept arguments from the parent and/or it’s inherited sub-classes.
Most examples I came across online were simple Concerns which didn’t take any parameters or arguments. So here’s how I went about creating one. Let’s call it Arguable for the sake of this blog post.
Implementation:
module Arguable
extend ActiveSupport::Concern
module ClassMethods
attr_reader :arguable_opts
private
def arguable(opts={})
@arguable_opts = opts
end
end
def do_something
opts = get_arguable_opts
excluded_attrs = opts[:except] || []
included_attrs = opts[:only] || []
custom_attrs = opts[:custom] || {}
#Do something with the attrs here
puts opts
end
def get_arguable_opts
if self.class.arguable_opts.blank? && self.class.superclass.arguable_opts.present?
opts = self.class.superclass.arguable_opts
elsif self.class.arguable_opts.present? && self.class.superclass.arguable_opts.present?
opts = self.class.superclass.arguable_opts.merge(self.class.arguable_opts)
else
opts = self.class.arguable_opts
end
opts || {}
end
end
Usage:
class Shape > ActiveRecord::Base
include Arguable
arguable exclude: [:id]
end
class Circle > Shape
include Arguable
arguable include: [:order], custom: {foo: 'bar'}
end
Circle’s options would then have exclude
available from it’s parent class and all the other include
and custom
options available from the subclass.
> c = Circle.find(1)
> c.do_something # => {exclude: [:id], include: [:order], custom: {foo: 'bar'}}