My Profile Photo

rubycoloredglasses


I'm Jason, a web applications developer in the San Francisco Bay area.


Simple-Jekyll-Search

Simple-Jekyll-Search

Build Status

A JavaScript library to add search functionality to any Jekyll blog.

Find it on npmjs.com


idea from this blog post


Promotion: check out Pomodoro.cc

Demo

Install

bower install --save simple-jekyll-search
# or
npm install --save simple-jekyll-search

Getting started

Place the following code in a file called search.json in the root of your Jekyll blog.

This file will be used as a small data source to perform the searches on the client side:

---
---
[
  
    {
      "title"    : "Markdown Links and 80 Character Line Length",
      "category" : "",
      "tags"     : "markdown",
      "url"      : "/2017/11/markdown-links-80-character-line-length/",
      "date"     : "2017-11-25 09:55:00 -0500"
    } ,
  
    {
      "title"    : "Fitter Happier",
      "category" : "",
      "tags"     : "radiohead, voice synthesis",
      "url"      : "/2017/08/fitter-happier/",
      "date"     : "2017-08-07 12:00:00 -0700"
    } ,
  
    {
      "title"    : "FileMerge (also known as opendiff)",
      "category" : "",
      "tags"     : "filemerge, opendiff, xcode",
      "url"      : "/2017/08/opendiff/",
      "date"     : "2017-08-07 12:00:00 -0700"
    } ,
  
    {
      "title"    : "Running a Bitcoin Core Full Node",
      "category" : "",
      "tags"     : "ubuntu, bitcoin",
      "url"      : "/2017/05/running-a-bitcoin-core-full-node/",
      "date"     : "2017-05-25 21:08:00 -0700"
    } ,
  
    {
      "title"    : "Configuring a New Ubuntu Server with Sudo",
      "category" : "",
      "tags"     : "ubuntu, sudo, sshd, security",
      "url"      : "/2017/05/configuring-new-ubuntu-server-with-sudo/",
      "date"     : "2017-05-25 21:08:00 -0700"
    } ,
  
    {
      "title"    : "Detecting if WebMock is enabled for Net::HTTP",
      "category" : "",
      "tags"     : "WebMock, HTTParty",
      "url"      : "/2017/05/detecting-webmock-enabled-net-http/",
      "date"     : "2017-05-17 14:43:52 -0700"
    } ,
  
    {
      "title"    : "Static Hosting with Neocities",
      "category" : "",
      "tags"     : "static, neocities, jekyll",
      "url"      : "/2017/05/static-hosting-with-neocities/",
      "date"     : "2017-05-12 09:43:51 -0700"
    } ,
  
    {
      "title"    : "Intro to Tmux",
      "category" : "",
      "tags"     : "tmux, screen",
      "url"      : "/2016/06/tmux-intro/",
      "date"     : "2016-06-30 00:00:00 -0700"
    } ,
  
    {
      "title"    : "Unbricking TP-Link TL-WDR4300",
      "category" : "",
      "tags"     : "wifi, tp-link, wdr4300, openwrt, mesh",
      "url"      : "/2016/04/tp-link-wdr4300-recovery/",
      "date"     : "2016-04-14 00:00:00 -0700"
    } ,
  
    {
      "title"    : "Getting Started with IRSSI",
      "category" : "",
      "tags"     : "irc",
      "url"      : "/2016/04/getting-started-with-irssi/",
      "date"     : "2016-04-09 00:00:00 -0700"
    } ,
  
    {
      "title"    : "Recommended Gems",
      "category" : "",
      "tags"     : "gems, ruby",
      "url"      : "/2016/03/recommended-gems/",
      "date"     : "2016-03-05 00:00:00 -0800"
    } ,
  
    {
      "title"    : "Looping through dictionaries in jinja2 templates",
      "category" : "",
      "tags"     : "jinja2, ansible, templates",
      "url"      : "/2015/11/looping-through-dictionaries-in-jinja2-templates/",
      "date"     : "2015-11-05 02:10:32 -0800"
    } ,
  
    {
      "title"    : "Vagrant SSH Failure - Connection closed by remote host",
      "category" : "",
      "tags"     : "",
      "url"      : "/2015/09/vagrant-ssh-failure-connection-closed-by-remote-host/",
      "date"     : "2015-09-10 19:21:52 -0700"
    } ,
  
    {
      "title"    : "Error when building PhantomJS 2.0",
      "category" : "",
      "tags"     : "phantomjs",
      "url"      : "/2015/08/error-when-building-phantomjs-2-0/",
      "date"     : "2015-08-08 01:34:12 -0700"
    } ,
  
    {
      "title"    : "Setup Environment for Django Development",
      "category" : "",
      "tags"     : "python, django, virtualenv, pip",
      "url"      : "/2015/02/setup-environment-for-django-development/",
      "date"     : "2015-02-02 00:26:28 -0800"
    } ,
  
    {
      "title"    : "Issues with RVM after upgrade to OS X Mavericks",
      "category" : "",
      "tags"     : "",
      "url"      : "/2014/10/issues-with-rvm-after-upgrade-to-os-x-mavericks/",
      "date"     : "2014-10-02 00:00:00 -0700"
    } ,
  
    {
      "title"    : "Bypassing the AngularJS router for anchor tags",
      "category" : "",
      "tags"     : "AngularJS, ngRoute, routing, anchor, CSV download",
      "url"      : "/2014/09/bypassing-the-angularjs-router-for-anchor-tags/",
      "date"     : "2014-09-18 19:19:44 -0700"
    } ,
  
    {
      "title"    : "Sharing Administrative Rights with Homebrew",
      "category" : "",
      "tags"     : "homebrew, mac-osx, permissions",
      "url"      : "/2014/06/sharing-administrative-rights-with-homebrew/",
      "date"     : "2014-06-29 18:52:42 -0700"
    } ,
  
    {
      "title"    : "InstructureCon Hack Day",
      "category" : "",
      "tags"     : "canvas, instructure, lti-integration",
      "url"      : "/2014/06/instructurecon-hack-day/",
      "date"     : "2014-06-17 19:40:05 -0700"
    } ,
  
    {
      "title"    : "Strong Parameters with Spree Extensions",
      "category" : "",
      "tags"     : "Spree",
      "url"      : "/2014/04/strong-parameters-with-spree-extensions/",
      "date"     : "2014-04-20 01:05:29 -0700"
    } ,
  
    {
      "title"    : "Ruby Class Name",
      "category" : "",
      "tags"     : "",
      "url"      : "/2014/03/ruby-class-name/",
      "date"     : "2014-03-20 21:32:23 -0700"
    } ,
  
    {
      "title"    : "Using 'for in' in Javascript",
      "category" : "",
      "tags"     : "javascript, JsLint",
      "url"      : "/2014/03/using-for-in-in-javascript/",
      "date"     : "2014-03-18 02:04:24 -0700"
    } ,
  
    {
      "title"    : "How to 'head' a text file in Ruby",
      "category" : "",
      "tags"     : "ruby, head",
      "url"      : "/2014/01/how-to-head-a-text-file-in-ruby/",
      "date"     : "2014-01-30 22:51:32 -0800"
    } ,
  
    {
      "title"    : "Objective C Notes",
      "category" : "",
      "tags"     : "",
      "url"      : "/2014/01/objective-c-notes/",
      "date"     : "2014-01-09 07:46:44 -0800"
    } ,
  
    {
      "title"    : "Recommended Sublime 3 Packages",
      "category" : "",
      "tags"     : "sublime text, lint",
      "url"      : "/2013/12/recommended-sublime-3-packages/",
      "date"     : "2013-12-17 17:39:00 -0800"
    } ,
  
    {
      "title"    : "Setting up PostgreSQL for Rails",
      "category" : "",
      "tags"     : "postgresql",
      "url"      : "/2013/11/setting-up-postgresql-for-rails/",
      "date"     : "2013-11-21 20:14:34 -0800"
    } ,
  
    {
      "title"    : "ComputerName: not set",
      "category" : "",
      "tags"     : "oh-my-zsh",
      "url"      : "/2013/10/computername-not-set/",
      "date"     : "2013-10-02 23:20:22 -0700"
    } ,
  
    {
      "title"    : "Bundler Definitions",
      "category" : "",
      "tags"     : "bundler",
      "url"      : "/2013/09/bundler-definitions/",
      "date"     : "2013-09-01 20:16:38 -0700"
    } ,
  
    {
      "title"    : "Yard Documentation",
      "category" : "",
      "tags"     : "Yard",
      "url"      : "/2013/08/yard-documentation/",
      "date"     : "2013-08-31 21:50:47 -0700"
    } ,
  
    {
      "title"    : "Exploring Bundler Commands",
      "category" : "",
      "tags"     : "rubygems, bundler, Thor",
      "url"      : "/2013/08/exploring-bundler-commands/",
      "date"     : "2013-08-30 01:11:49 -0700"
    } ,
  
    {
      "title"    : "Paperclip URL and Path",
      "category" : "",
      "tags"     : "paperclip, s3",
      "url"      : "/2013/08/paperclip-url-and-path/",
      "date"     : "2013-08-28 20:04:13 -0700"
    } ,
  
    {
      "title"    : "Open Source Ideas",
      "category" : "",
      "tags"     : "",
      "url"      : "/2013/08/open-source-ideas/",
      "date"     : "2013-08-25 22:47:39 -0700"
    } ,
  
    {
      "title"    : "Precompiling Rails 4 Assets When Deploying to Heroku",
      "category" : "",
      "tags"     : "heroku, rails4, asset pipeline",
      "url"      : "/2013/08/precompiling-rails4-assets-when-deploying-to-heroku/",
      "date"     : "2013-08-25 00:13:01 -0700"
    } ,
  
    {
      "title"    : "Resetting Paths for Homebrew",
      "category" : "",
      "tags"     : "homebrew, command line, cmdline",
      "url"      : "/2013/08/resetting-paths-for-homebrew/",
      "date"     : "2013-08-22 19:31:38 -0700"
    } ,
  
    {
      "title"    : "Time Management",
      "category" : "",
      "tags"     : "time management",
      "url"      : "/2013/07/time-management/",
      "date"     : "2013-07-30 05:25:04 -0700"
    } ,
  
    {
      "title"    : "Ruby Strftime",
      "category" : "",
      "tags"     : "dates, times",
      "url"      : "/2013/07/ruby-strftime/",
      "date"     : "2013-07-26 22:16:42 -0700"
    } ,
  
    {
      "title"    : "Uptime Monitoring and Alerts",
      "category" : "",
      "tags"     : "",
      "url"      : "/2013/07/uptime-monitoring-and-alerts/",
      "date"     : "2013-07-26 00:34:25 -0700"
    } ,
  
    {
      "title"    : "Installing Rails 3.2.13",
      "category" : "",
      "tags"     : "Rails 3",
      "url"      : "/2013/07/installing-rails-3-2-13/",
      "date"     : "2013-07-16 03:00:40 -0700"
    } ,
  
    {
      "title"    : "POW RVM ZSH",
      "category" : "",
      "tags"     : "rvm, pow, zsh",
      "url"      : "/2013/07/pow-rvm-zsh/",
      "date"     : "2013-07-15 00:07:38 -0700"
    } ,
  
    {
      "title"    : "Devise_For with Skip",
      "category" : "",
      "tags"     : "devise",
      "url"      : "/2013/07/devise_for-with-skip/",
      "date"     : "2013-07-11 22:26:51 -0700"
    } ,
  
    {
      "title"    : "Project / Task Management Applications",
      "category" : "",
      "tags"     : "planning, analysis, project management",
      "url"      : "/2013/07/project-task-management-applications/",
      "date"     : "2013-07-07 23:11:31 -0700"
    } ,
  
    {
      "title"    : "Refinery Extension Not Named After Model",
      "category" : "",
      "tags"     : "refinery-cms",
      "url"      : "/2013/06/refinery-extension-not-named-after-model/",
      "date"     : "2013-06-18 06:01:25 -0700"
    } ,
  
    {
      "title"    : "Splitting a Branch with Git",
      "category" : "",
      "tags"     : "git",
      "url"      : "/2013/06/splitting-a-branch-with-git/",
      "date"     : "2013-06-05 19:18:38 -0700"
    } ,
  
    {
      "title"    : "Application Builders",
      "category" : "",
      "tags"     : "builder",
      "url"      : "/2013/06/application-builders/",
      "date"     : "2013-06-05 07:11:12 -0700"
    } ,
  
    {
      "title"    : "Technical Debt",
      "category" : "",
      "tags"     : "technical debt",
      "url"      : "/2013/06/technical-debt/",
      "date"     : "2013-06-03 18:43:05 -0700"
    } ,
  
    {
      "title"    : "Why Ruby Was Named After a Gemstone",
      "category" : "",
      "tags"     : "ruby, perl",
      "url"      : "/2013/06/why-ruby-was-named-after-a-gemstone/",
      "date"     : "2013-06-03 16:54:30 -0700"
    } ,
  
    {
      "title"    : "Über-Securing Ubuntu 12.04 LTS with Mod-Security + Ruby on Rails 3.2.13",
      "category" : "",
      "tags"     : "security, mod_security, ubuntu, DDOS, linux, hosting, ssh",
      "url"      : "/2013/06/uber-securing-ubuntu-12-04-lts-precise-pangolin/",
      "date"     : "2013-06-01 08:29:51 -0700"
    } ,
  
    {
      "title"    : "Downloadable Documentation",
      "category" : "",
      "tags"     : "documentation",
      "url"      : "/2013/05/downloadable-documentation/",
      "date"     : "2013-05-30 18:20:00 -0700"
    } ,
  
    {
      "title"    : "History of Internationalization in Software",
      "category" : "",
      "tags"     : "unicode",
      "url"      : "/2013/05/history-of-internationalization-in-software/",
      "date"     : "2013-05-29 18:09:34 -0700"
    } ,
  
    {
      "title"    : "Mobile Application Performance Monitoring and Management",
      "category" : "",
      "tags"     : "mobile",
      "url"      : "/2013/05/mobile-application-performance-monitoring-and-management/",
      "date"     : "2013-05-28 19:45:57 -0700"
    } ,
  
    {
      "title"    : "Use Ruby to Develop iOS or Mac OSX",
      "category" : "",
      "tags"     : "ios, mac-osx",
      "url"      : "/2013/05/use-ruby-to-develop-ios-or-mac-osx/",
      "date"     : "2013-05-22 01:53:31 -0700"
    } ,
  
    {
      "title"    : "Uninstalling Command Line Tools for Xcode",
      "category" : "",
      "tags"     : "xcode",
      "url"      : "/2013/05/uninstalling-command-line-tools-for-xcode/",
      "date"     : "2013-05-20 20:51:42 -0700"
    } ,
  
    {
      "title"    : "Setting Rspec as the Default",
      "category" : "",
      "tags"     : "generators, workflow",
      "url"      : "/2013/05/setting-rspec-as-the-default/",
      "date"     : "2013-05-19 05:19:49 -0700"
    } ,
  
    {
      "title"    : "Remote Pair Programming",
      "category" : "",
      "tags"     : "pair programming, remote pair programming, coding presentation",
      "url"      : "/2013/04/remote-pair-programming/",
      "date"     : "2013-04-22 17:48:59 -0700"
    } ,
  
    {
      "title"    : "Languages Supported by Github Flavored Markdown",
      "category" : "",
      "tags"     : "yardoc, github, markdown",
      "url"      : "/2013/04/languages-supported-by-github-flavored-markdown/",
      "date"     : "2013-04-12 20:57:57 -0700"
    } ,
  
    {
      "title"    : "Coding Games",
      "category" : "",
      "tags"     : "javascript, code games",
      "url"      : "/2013/04/coding-games/",
      "date"     : "2013-04-11 20:30:59 -0700"
    } ,
  
    {
      "title"    : "Customize your IRB",
      "category" : "",
      "tags"     : "irb",
      "url"      : "/2013/03/customize-your-irb/",
      "date"     : "2013-03-22 17:36:54 -0700"
    } ,
  
    {
      "title"    : "htaccess tester",
      "category" : "",
      "tags"     : "htaccess",
      "url"      : "/2013/03/htaccess-tester/",
      "date"     : "2013-03-01 08:43:17 -0800"
    } ,
  
    {
      "title"    : "Using Find Each to Process Batches",
      "category" : "",
      "tags"     : "batch processing",
      "url"      : "/2013/02/using-find-each-to-process-batches/",
      "date"     : "2013-02-28 20:49:14 -0800"
    } ,
  
    {
      "title"    : "Development Time",
      "category" : "",
      "tags"     : "time, estimate",
      "url"      : "/2013/02/development-time/",
      "date"     : "2013-02-28 02:02:05 -0800"
    } ,
  
    {
      "title"    : "Minecraft Mods",
      "category" : "",
      "tags"     : "minecraft, mods, craftbukkit, console",
      "url"      : "/2013/02/minecraft-mods/",
      "date"     : "2013-02-10 02:30:53 -0800"
    } ,
  
    {
      "title"    : "Obtain MySQL Query Statistics using Explain",
      "category" : "",
      "tags"     : "mysql, explain",
      "url"      : "/2013/02/obtain-mysql-query-statistics-using-explain/",
      "date"     : "2013-02-07 00:56:31 -0800"
    } ,
  
    {
      "title"    : "Git Branching Model",
      "category" : "",
      "tags"     : "",
      "url"      : "/2013/02/git-branching-model/",
      "date"     : "2013-02-06 19:57:45 -0800"
    } ,
  
    {
      "title"    : "Referencing Gem Source Code",
      "category" : "",
      "tags"     : "gem, gem source, unpack",
      "url"      : "/2013/02/referencing-gem-source-code/",
      "date"     : "2013-02-06 05:11:46 -0800"
    } ,
  
    {
      "title"    : "You can be a programmer too!",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/12/you-can-be-a-programmer-too/",
      "date"     : "2012-12-28 02:52:52 -0800"
    } ,
  
    {
      "title"    : "Spree Extension Development Environment using RVM",
      "category" : "",
      "tags"     : "Spree, extension",
      "url"      : "/2012/12/spree-extension-development-environment-using-rvm/",
      "date"     : "2012-12-25 10:30:38 -0800"
    } ,
  
    {
      "title"    : "Creating a Gem",
      "category" : "",
      "tags"     : "gem",
      "url"      : "/2012/12/creating-a-gem/",
      "date"     : "2012-12-25 09:50:03 -0800"
    } ,
  
    {
      "title"    : "Ruby File Modes",
      "category" : "",
      "tags"     : "file",
      "url"      : "/2012/12/ruby-file-modes/",
      "date"     : "2012-12-21 01:14:20 -0800"
    } ,
  
    {
      "title"    : "Return FALSE or Raise Error?",
      "category" : "",
      "tags"     : "ruby, exception handling",
      "url"      : "/2012/12/return-false-or-raise-error/",
      "date"     : "2012-12-20 18:35:44 -0800"
    } ,
  
    {
      "title"    : "When Testing Seems Pointless",
      "category" : "",
      "tags"     : "testing, tdd, unit-testing",
      "url"      : "/2012/12/when-testing-seems-pointless/",
      "date"     : "2012-12-19 02:51:53 -0800"
    } ,
  
    {
      "title"    : "Using Rspec to Test Controllers",
      "category" : "",
      "tags"     : "rspec, controller",
      "url"      : "/2012/12/using-rspec-to-test-controller/",
      "date"     : "2012-12-13 01:46:41 -0800"
    } ,
  
    {
      "title"    : "Good Guy Greg",
      "category" : "",
      "tags"     : "testing, rspec",
      "url"      : "/2012/12/good-guy-greg/",
      "date"     : "2012-12-11 21:48:15 -0800"
    } ,
  
    {
      "title"    : "Using Rails 2.3.8",
      "category" : "",
      "tags"     : "rails, Rails-2.3.8, bundler",
      "url"      : "/2012/12/using-rails-2-3-8/",
      "date"     : "2012-12-03 19:57:38 -0800"
    } ,
  
    {
      "title"    : "Rspec Executable Not Found",
      "category" : "",
      "tags"     : "rvm, rspec",
      "url"      : "/2012/11/rspec-executable-not-found/",
      "date"     : "2012-11-28 01:14:27 -0800"
    } ,
  
    {
      "title"    : "Changing the Default Text Editor",
      "category" : "",
      "tags"     : "git, text-editor",
      "url"      : "/2012/11/changing-the-default-text-editor/",
      "date"     : "2012-11-19 21:30:07 -0800"
    } ,
  
    {
      "title"    : "Metaclass",
      "category" : "",
      "tags"     : "metaprogramming, metaclass",
      "url"      : "/2012/09/metaclass/",
      "date"     : "2012-09-19 19:19:03 -0700"
    } ,
  
    {
      "title"    : "Using Super with Ruby class methods",
      "category" : "",
      "tags"     : "superclass",
      "url"      : "/2012/09/using-super-with-ruby-class-methods/",
      "date"     : "2012-09-18 21:06:32 -0700"
    } ,
  
    {
      "title"    : "Ruby Coloured Glasses",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/09/ruby-coloured-glasses/",
      "date"     : "2012-09-18 19:46:48 -0700"
    } ,
  
    {
      "title"    : "Duplicate associated records when using FactoryGirl",
      "category" : "",
      "tags"     : "factory_girl",
      "url"      : "/2012/09/issues-with-duplicate-associated-records-when-using-factorygirl/",
      "date"     : "2012-09-09 23:26:46 -0700"
    } ,
  
    {
      "title"    : "Finding Records without Specific Child in Many-to-Many Relationship",
      "category" : "",
      "tags"     : "mysql, many-to-many",
      "url"      : "/2012/07/finding-records-without-specific-child-in-many-to-many-relationship/",
      "date"     : "2012-07-16 21:57:49 -0700"
    } ,
  
    {
      "title"    : "Listing Gems from Rails Console",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/06/listing-gems-from-rails-console/",
      "date"     : "2012-06-20 21:59:03 -0700"
    } ,
  
    {
      "title"    : "Add a Serialized Hash Attribute to a Factory_Girl Definition",
      "category" : "",
      "tags"     : "factory_girl, hash",
      "url"      : "/2012/06/add-a-serialized-hash-attribute-to-a-factory_girl-definition/",
      "date"     : "2012-06-11 20:25:13 -0700"
    } ,
  
    {
      "title"    : "List Sorted Methods in Ruby",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/06/list-sorted-methods-in-ruby/",
      "date"     : "2012-06-11 18:06:48 -0700"
    } ,
  
    {
      "title"    : "Updating a Serialized Object from a Web form",
      "category" : "",
      "tags"     : "serialize",
      "url"      : "/2012/06/updating-a-serialized-object-from-a-web-form/",
      "date"     : "2012-06-06 18:19:01 -0700"
    } ,
  
    {
      "title"    : "RSpec Controller Tests Receiving 'No route matches' Error",
      "category" : "",
      "tags"     : "rspec, namespaced controller",
      "url"      : "/2012/05/rspec-controller-tests-receiving-no-route-matches-error/",
      "date"     : "2012-05-25 18:24:17 -0700"
    } ,
  
    {
      "title"    : "Cubase Installation Failure",
      "category" : "",
      "tags"     : "cubase, package scripts, install failure",
      "url"      : "/2012/05/cubase-installation-failure/",
      "date"     : "2012-05-23 03:48:01 -0700"
    } ,
  
    {
      "title"    : "Generators Not Working in Rails 2.3.8",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/05/generators-not-working-in-rails-2-3-8/",
      "date"     : "2012-05-16 01:14:15 -0700"
    } ,
  
    {
      "title"    : "Establishing New Ruby Environment in a Folder using RVM",
      "category" : "",
      "tags"     : "rvm",
      "url"      : "/2012/05/establishing-new-ruby-environment-in-a-folder-using-rvm/",
      "date"     : "2012-05-15 17:58:16 -0700"
    } ,
  
    {
      "title"    : "History of the Canonical Gem Host for Ruby Gems",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/05/history-of-the-canonical-gem-host-for-ruby-gems/",
      "date"     : "2012-05-14 18:41:23 -0700"
    } ,
  
    {
      "title"    : "Using Serialize Option with ActiveRecord Objects",
      "category" : "",
      "tags"     : "rails3.1, forms",
      "url"      : "/2012/04/using-serialize-option-with-activerecord-objects/",
      "date"     : "2012-04-25 19:01:26 -0700"
    } ,
  
    {
      "title"    : "Save the Tests, Don't Throw Them Away",
      "category" : "",
      "tags"     : "testing, tdd",
      "url"      : "/2012/04/save-the-tests-dont-throw-them-away/",
      "date"     : "2012-04-20 17:48:02 -0700"
    } ,
  
    {
      "title"    : "Factory Girl Associations and Records Persisting Across Tests",
      "category" : "",
      "tags"     : "rails3.1, testing, factory_girl, tdd",
      "url"      : "/2012/04/factory-girl-associations-records-persisting-across-tests/",
      "date"     : "2012-04-11 22:32:23 -0700"
    } ,
  
    {
      "title"    : "Generating Test File Stubs for Existing Models, Views, and Controllers",
      "category" : "",
      "tags"     : "rails3.1, testing, rspec, tdd",
      "url"      : "/2012/04/generating-rspec-tests-for-existing-models-views-controllers/",
      "date"     : "2012-04-03 13:10:12 -0700"
    } ,
  
    {
      "title"    : "Rails 3 and Subclasses Method",
      "category" : "",
      "tags"     : "rails3.1",
      "url"      : "/2012/03/rails-3-and-subclasses-method/",
      "date"     : "2012-03-26 18:38:14 -0700"
    } ,
  
    {
      "title"    : "Locate and Updatedb with Homebrew",
      "category" : "",
      "tags"     : "os x lion, findutils, homebrew",
      "url"      : "/2012/03/locate-and-updatedb-with-homebrew/",
      "date"     : "2012-03-26 14:08:59 -0700"
    } ,
  
    {
      "title"    : "Foreign Key References when Generating Model",
      "category" : "",
      "tags"     : "migrations",
      "url"      : "/2012/03/foreign-key-references-when-generating-mode/",
      "date"     : "2012-03-23 18:15:26 -0700"
    } ,
  
    {
      "title"    : "Edit Devise User without Password",
      "category" : "",
      "tags"     : "rails, devise",
      "url"      : "/2012/03/edit-devise-user-without-password/",
      "date"     : "2012-03-20 16:38:43 -0700"
    } ,
  
    {
      "title"    : "Factory Girl Not Generating Factories with Scaffold",
      "category" : "",
      "tags"     : "rails3.1, factory_girl",
      "url"      : "/2012/03/factory-girl-not-generating-factories-with-scaffold/",
      "date"     : "2012-03-19 14:18:44 -0700"
    } ,
  
    {
      "title"    : "Ruby Comparison Operator =~",
      "category" : "",
      "tags"     : "comparison operator, ruby",
      "url"      : "/2012/03/ruby-comparison-operator/",
      "date"     : "2012-03-07 18:26:34 -0800"
    } ,
  
    {
      "title"    : "Invalid Gemspec Error Regarding Invalid Date Format",
      "category" : "",
      "tags"     : "rails3.1, rubygems",
      "url"      : "/2012/02/invalid-gemspec-error-invalid-date-format/",
      "date"     : "2012-02-22 18:30:45 -0800"
    } ,
  
    {
      "title"    : "Deleting Git Branches in Remote Repository",
      "category" : "",
      "tags"     : "git",
      "url"      : "/2012/01/deleting-git-branches-in-remote-repository/",
      "date"     : "2012-01-24 18:08:06 -0800"
    } ,
  
    {
      "title"    : "Rails 3 on WHM / cPanel VPS Server",
      "category" : "",
      "tags"     : "capistrano, passenger, rails3.1, cpanel",
      "url"      : "/2012/01/rails-3-on-whm-cpanel-vps-server/",
      "date"     : "2012-01-08 13:14:58 -0800"
    } ,
  
    {
      "title"    : "Configuring Rails 3.1.3 under Sub-URI",
      "category" : "",
      "tags"     : "rails3.1, relative_url_root, sub-uri",
      "url"      : "/2012/01/configuring-rails-3-1-3-under-sub-uri/",
      "date"     : "2012-01-04 02:02:40 -0800"
    } ,
  
    {
      "title"    : "Custom Rake Tasks Not Loading",
      "category" : "",
      "tags"     : "rake",
      "url"      : "/2012/01/custom-rake-tasks-not-loading/",
      "date"     : "2012-01-01 18:57:34 -0800"
    } ,
  
    {
      "title"    : "Troubleshooting ActiveResource Requests",
      "category" : "",
      "tags"     : "ActiveResource, HighRise, REST API",
      "url"      : "/2012/01/troubleshooting-activeresource-requests/",
      "date"     : "2012-01-01 18:46:52 -0800"
    } ,
  
    {
      "title"    : "Example Rake Task",
      "category" : "",
      "tags"     : "rake",
      "url"      : "/2012/01/example-rake-task/",
      "date"     : "2012-01-01 18:26:28 -0800"
    } ,
  
    {
      "title"    : "Adding a New User in Ubuntu",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/12/adding-a-new-user-in-ubuntu/",
      "date"     : "2011-12-29 18:08:48 -0800"
    } ,
  
    {
      "title"    : "Resolving issues with Namespaced Models in Rails 3.1.0",
      "category" : "",
      "tags"     : "rails, namespaced models, rails3.1",
      "url"      : "/2011/12/resolving-issues-with-namespaced-models-in-rails-3-1-0/",
      "date"     : "2011-12-06 19:09:51 -0800"
    } ,
  
    {
      "title"    : "Paperclip error with non-image file",
      "category" : "",
      "tags"     : "paperclip, identify, imagemagick, non-image",
      "url"      : "/2011/12/paperclip-error-with-non-image-file/",
      "date"     : "2011-12-05 16:43:25 -0800"
    } ,
  
    {
      "title"    : "Issues with RVM",
      "category" : "",
      "tags"     : "rails, os x lion, rvm",
      "url"      : "/2011/11/issues-with-rvm/",
      "date"     : "2011-11-13 20:11:04 -0800"
    } ,
  
    {
      "title"    : "Setting up Ubuntu for Rails App via Passenger",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/setting-up-ubuntu-for-rails-app-via-passenger/",
      "date"     : "2011-10-29 22:11:11 -0700"
    } ,
  
    {
      "title"    : "Formtastic use of semantic_form_remote_for",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/formtastic-use-of-semantic-form-remote-for/",
      "date"     : "2011-10-20 15:29:02 -0700"
    } ,
  
    {
      "title"    : "Exporting Routes in Rails 3",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/exporting-routes-rails/",
      "date"     : "2011-10-20 14:36:54 -0700"
    } ,
  
    {
      "title"    : "Using URL Helpers in Models or Rake Tasks",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/using-url-helpers-models-or-rake-tasks/",
      "date"     : "2011-10-19 16:41:51 -0700"
    } ,
  
    {
      "title"    : "Building a Query String from a Hash with Rails 3",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/building-query-string-from-hash-rails/",
      "date"     : "2011-10-19 14:35:09 -0700"
    } ,
  
    {
      "title"    : "Rails 3 Autoloading with Namespaced Models",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/rails-autoloading-namespaced-models/",
      "date"     : "2011-10-18 15:50:03 -0700"
    } ,
  
    {
      "title"    : "Form Fields not Displaying with Formtastic",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/form-fields-not-displaying-formtastic/",
      "date"     : "2011-10-18 10:48:34 -0700"
    } ,
  
    {
      "title"    : "Adding Event Listeners to Google-Maps-for-Rails Markers",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/adding-event-listeners-to-google-maps-for-rails-markers/",
      "date"     : "2011-10-11 11:24:27 -0700"
    } ,
  
    {
      "title"    : "Issues with Bluetooth in OS X Lion after Upgrade",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/09/issues-with-bluetooth-in-os-x-lion-after-upgrade/",
      "date"     : "2011-09-28 19:08:39 -0700"
    } ,
  
    {
      "title"    : "Redirect_to not working",
      "category" : "",
      "tags"     : "http post",
      "url"      : "/2011/09/redirect_to-not-working/",
      "date"     : "2011-09-27 16:37:59 -0700"
    } ,
  
    {
      "title"    : "Advanced Use of Will_Paginate",
      "category" : "",
      "tags"     : "rails, pagination, will_paginate",
      "url"      : "/2011/09/advanced-use-of-will_paginate/",
      "date"     : "2011-09-23 18:08:56 -0700"
    } ,
  
    {
      "title"    : "Getting File object for Paperclip Attachment via S3",
      "category" : "",
      "tags"     : "rails, csv, paperclip, s3",
      "url"      : "/2011/09/getting-file-object-for-paperclip-attachment-via-s3/",
      "date"     : "2011-09-22 15:34:10 -0700"
    } ,
  
    {
      "title"    : "Issues with MacPorts After Upgrading to OS X Lion",
      "category" : "",
      "tags"     : "macports",
      "url"      : "/2011/09/issues-with-macports-after-upgrading-to-os-x-lion/",
      "date"     : "2011-09-16 18:10:00 -0700"
    } ,
  
    {
      "title"    : "Error: 'unintitialized constant MySQL' with Rails 3 on Snow Leopard Mac",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/05/error-unintitialized-constant-mysql-with-rails-3-on-snow-leopard-mac/",
      "date"     : "2011-05-19 23:05:08 -0700"
    } ,
  
    {
      "title"    : "Installing PHPdoc for Ubuntu for use with Command Line",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/05/installing-phpdoc-for-ubuntu/",
      "date"     : "2011-05-18 20:21:45 -0700"
    } ,
  
    {
      "title"    : "Ruby on Rails session - Access from PHP",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/12/ruby-on-rails-session-access-from-php/",
      "date"     : "2010-12-14 00:25:37 -0800"
    } ,
  
    {
      "title"    : "Obtaining Request Domain Name for Ruby on Rails",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/10/obtaining-request-domain-name-for-ruby-on-rails/",
      "date"     : "2010-10-12 01:19:16 -0700"
    } ,
  
    {
      "title"    : "Changing Column Order via ActiveRecord Migration",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/08/changing-column-order-via-activerecord-migration/",
      "date"     : "2010-08-15 22:09:40 -0700"
    } ,
  
    {
      "title"    : "Rails Performance Statistics",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/08/rails-performance-statistics/",
      "date"     : "2010-08-09 02:26:40 -0700"
    } ,
  
    {
      "title"    : "RailRoad Gem",
      "category" : "",
      "tags"     : "diagram, models, activerecord",
      "url"      : "/2010/08/railroad/",
      "date"     : "2010-08-09 02:07:44 -0700"
    } ,
  
    {
      "title"    : "Annotate Models",
      "category" : "",
      "tags"     : "rails, plugin",
      "url"      : "/2010/08/annotate-models/",
      "date"     : "2010-08-07 22:02:30 -0700"
    } ,
  
    {
      "title"    : "Selenium RC, Firefox 3, and Ubuntu",
      "category" : "",
      "tags"     : "linkedin",
      "url"      : "/2010/07/selenium-rc-firefox-3-and-ubuntu/",
      "date"     : "2010-07-29 18:46:26 -0700"
    } ,
  
    {
      "title"    : "Undefined method 'ref' for ActiveSupport::Dependencies:Module",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/07/unable-to-run-rails-migrations-mysql-gem-on-snow-leopard/",
      "date"     : "2010-07-27 10:19:01 -0700"
    } ,
  
    {
      "title"    : "Setting up Deployment for Rails using Capistrano, Apache with Passenger and Git",
      "category" : "",
      "tags"     : "rails, capistrano, git, passenger",
      "url"      : "/2010/07/setting-up-deployment-for-rails-using-capistrano-apache-with-passenger-and-git/",
      "date"     : "2010-07-20 23:48:23 -0700"
    } ,
  
    {
      "title"    : "Rake Tasks",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/07/rake-tasks/",
      "date"     : "2010-07-16 17:37:56 -0700"
    } ,
  
    {
      "title"    : "MySQL Gem Installation on Mac 10.5.8 - 64 bit??",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/07/mysql-gem-installation-on-mac-10-5-8-64-bit/",
      "date"     : "2010-07-16 17:26:14 -0700"
    } ,
  
    {
      "title"    : "Wordpress Plugin - Custom Pages?",
      "category" : "",
      "tags"     : "wordpress, plugin, permalinks",
      "url"      : "/2010/06/wordpress-plugin-custom-pages/",
      "date"     : "2010-06-28 22:39:15 -0700"
    } ,
  
    {
      "title"    : "Ubuntu 9.10 Karmic Koala - VNC resolution limited without monitor",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/02/ubuntu-9-10-karmic-koala-vnc-resolution/",
      "date"     : "2010-02-20 07:29:28 -0800"
    } ,
  
    {
      "title"    : "PHP Not Parsing on Debian / Ubuntu server with Apache2",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/02/php-not-parsing-on-debian-ubuntu-server/",
      "date"     : "2010-02-10 21:03:59 -0800"
    } ,
  
    {
      "title"    : "Dell Dimension 3000 - Audio is Choppy",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/01/dell-dimension-3000-audio-is-choppy/",
      "date"     : "2010-01-13 18:49:45 -0800"
    } ,
  
    {
      "title"    : "Un-Hide Someone in Facebook",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/01/un-hide-someone-in-facebook/",
      "date"     : "2010-01-11 17:40:15 -0800"
    } ,
  
    {
      "title"    : "Selenium - no display specified",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/01/selenium-no-display-specified/",
      "date"     : "2010-01-11 14:51:10 -0800"
    } ,
  
    {
      "title"    : "Common Computer Mistakes",
      "category" : "",
      "tags"     : "",
      "url"      : "/2009/11/common-computer-mistakes/",
      "date"     : "2009-11-02 14:59:02 -0800"
    } ,
  
    {
      "title"    : "Rounded Corners",
      "category" : "",
      "tags"     : "",
      "url"      : "/2009/04/rounded-corners/",
      "date"     : "2009-04-24 17:11:18 -0700"
    } ,
  
    {
      "title"    : "Database Schema Information",
      "category" : "",
      "tags"     : "mysql, rails",
      "url"      : "/2009/03/database-schema-information/",
      "date"     : "2009-03-13 17:20:50 -0700"
    } ,
  
    {
      "title"    : "PHP Compilation",
      "category" : "",
      "tags"     : "php",
      "url"      : "/2005/02/php-compile/",
      "date"     : "2005-02-28 02:22:01 -0800"
    } ,
  
    {
      "title"    : "MBox and Linux Test Server",
      "category" : "",
      "tags"     : "mbox, linux",
      "url"      : "/2005/02/mbox-and-linux-test-server/",
      "date"     : "2005-02-23 15:25:01 -0800"
    } ,
  
    {
      "title"    : "PHP/MySQL Bug Tracking",
      "category" : "",
      "tags"     : "bug tracking",
      "url"      : "/2004/09/bug-tracking/",
      "date"     : "2004-09-09 13:51:00 -0700"
    } 
  
]

You need to place the following code within the layout where you want the search to appear. (See the configuration section below to customize it)

For example in _layouts/default.html:

<!-- Html Elements for Search -->
<div id="search-container">
<input type="text" id="search-input" placeholder="search...">
<ul id="results-container"></ul>
</div>

<!-- Script pointing to jekyll-search.js -->
<script src="/bower_components/simple-jekyll-search/dest/jekyll-search.js" type="text/javascript"></script>

Configuration

Customize SimpleJekyllSearch by passing in your configuration options:

SimpleJekyllSearch({
  searchInput: document.getElementById('search-input'),
  resultsContainer: document.getElementById('results-container'),
  json: '/search.json',
})

searchInput (Element) [required]

The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.

resultsContainer (Element) [required]

The container element in which the search results should be rendered in. Typically an <ul>.

json (String|JSON) [required]

You can either pass in an URL to the search.json file, or the results in form of JSON directly, to save one round trip to get the data.

searchResultTemplate (String) [optional]

The template of a single rendered search result.

The templating syntax is very simple: You just enclose the properties you want to replace with curly braces.

E.g.

The template

<li><a href="{url}">{title}</a></li>

will render to the following

<li><a href="/jekyll/update/2014/11/01/welcome-to-jekyll.html">Welcome to Jekyll!</a></li>

If the search.json contains this data

[
    {
      "title"    : "Welcome to Jekyll!",
      "category" : "",
      "tags"     : "",
      "url"      : "/jekyll/update/2014/11/01/welcome-to-jekyll.html",
      "date"     : "2014-11-01 21:07:22 +0100"
    }
]

templateMiddleware (Function) [optional]

A function that will be called whenever a match in the template is found.

It gets passed the current property name, property value, and the template.

If the function returns a non-undefined value, it gets replaced in the template.

This can be potentially useful for manipulating URLs etc.

Example:

SimpleJekyllSearch({
  ...
  middleware: function(prop, value, template){
    if( prop === 'bar' ){
      return value.replace(/^\//, '')
    }
  }
  ...
})

See the tests for an in-depth code example

noResultsText (String) [optional]

The HTML that will be shown if the query didn’t match anything.

limit (Number) [optional]

You can limit the number of posts rendered on the page.

fuzzy (Boolean) [optional]

Enable fuzzy search to allow less restrictive matching.

exclude (Array) [optional]

Pass in a list of terms you want to exclude (terms will be matched against a regex, so urls, words are allowed).

Replace ‘search.json’ with the following code:

---
layout: null
---
[
  
    {
      "title"    : "Markdown Links and 80 Character Line Length",
      "category" : "",
      "tags"     : "markdown",
      "url"      : "/2017/11/markdown-links-80-character-line-length/",
      "date"     : "2017-11-25 09:55:00 -0500",
      "content"  : "I’ve long been a fan of using Markdown for documentation in projectshosted on Github. In October of 2014 I decided to migrate from a Wordpressblog to Github Pages, which is powered by limited Jekyllfunctionality on the Github server side.With this migration I converted all my articles from HTML toGithub Flavored Markdown (GFM), which resulted in much better support forformatting my code examples, tables, strikethrough text formatting, andemojii.I’ve made use of the following cheat sheets for Markdown syntax:  Github Markdown Cheatsheet  Daring Fireball - Markdown: Syntax  Adam-P Markdown CheatsheetAn issue I’ve had is trying to limit the line length of my markdown. Linebreaks do not break apart paragraphs when rendered, however you cannot add linebreaks into the URL of the link without breaking the link.Alternative SyntaxTypically link syntax is provided like so:[Google](http://www.google.com/)However if the link and link text exceeds 80 characters, then you end up withhard to read Markdown.The solution is to use a syntax not commonly mentioned in Markdown guides forlinking that separates the text content from the URL.The links may still wrap at the bottom of the document, but at least thecontent is easy to read in plain text, even on the command line.My Links:* [Github Flavored Markdown][1]* [Basic Writing and Formatting Syntax - Using Emoji][2][1]: https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown[2]: https://help.github.com/articles/basic-writing-and-formatting-syntax/#using-emojiOne problem I’ve run into is that the numbered references end up providedthroughout the page out of order, which bothers me in some obsessive-compulsivesort of way.Instead you can use the link text itself.Check out [Spotify] for cool music[Spotify]: https://www.spotify.com/Alternatively, you can also use a case insensitive text key if the link text istoo informal for you.[Click here for Google][Google Link][google link]: http://www.google.com/ImagesA similar alternative for images can also be used:![Beautiful flower photo][flower photo][flower photo]: /images/flower.png"
    } ,
  
    {
      "title"    : "Fitter Happier",
      "category" : "",
      "tags"     : "radiohead, voice synthesis",
      "url"      : "/2017/08/fitter-happier/",
      "date"     : "2017-08-07 12:00:00 -0700",
      "content"  : "say -v fred "Fitter"say -v fred "happier"say -v fred "More productive"say -v fred "Comfortable"say -v fred "Not drinking too much"say -v fred "Regular exercise at the gym, three days a week"say -v fred "Getting on better with your associate employee contemporaries"say -v fred "At ease"say -v fred "Eating well, no more microwave dinners and saturated fats"say -v fred "A patient, better driver"say -v fred "A safer car, baby smiling in back seat"say -v fred "Sleeping well, no bad dreams"say -v fred "No paranoia"say -v fred "Careful to all animals, never washing spiders down the plughole"say -v fred "Keep in contact with old friends, enjoy a drink now and then"say -v fred "Will frequently check credit at moral bank, hole in wall"say -v fred "Favours for favours, fond but not in love"say -v fred "Charity standing orders on sundays, ring-road supermarket"say -v fred "No killing moths or putting boiling water on the ants"say -v fred "Car wash, also on sundays"say -v fred "No longer afraid of the dark or midday shadows, nothing so ridiculously teenage and desperate"say -v fred "Nothing so childish"say -v fred "At a better pace, slower and more calculated"say -v fred "No chance of escape"say -v fred "Now self-employed"say -v fred "Concerned, but powerless"say -v fred "An empowered and informed member of societ, pragmatism not idealism"say -v fred "Will not cry in public"say -v fred "Less chance of illness"say -v fred "Tires that grip in the wet, shot of baby strapped in backseat"say -v fred "A good memory"say -v fred "Still cries at a good film"say -v fred "Still kisses with saliva"say -v fred "No longer empty and frantic"say -v fred "Like a cat"say -v fred "Tied to a stick"say -v fred "That's driven into"say -v fred "Frozen winter shit, the ability to laugh at weakness"say -v fred "Calm, fitter, healthier and more productive"say -v fred "A pig in a cage on antibiotics""
    } ,
  
    {
      "title"    : "FileMerge (also known as opendiff)",
      "category" : "",
      "tags"     : "filemerge, opendiff, xcode",
      "url"      : "/2017/08/opendiff/",
      "date"     : "2017-08-07 12:00:00 -0700",
      "content"  : "Recently a developer colleague of mine was asking about diff tools. We let him know that he can useHomebrew to install a ported version of the ‘diff’ tool provided byGNU utils.An expensive alternative is Kaleidoscope app, which looks great but might beoverkill for our purposes.The good news is that XCode provides a GUI tool called FileMerge, which is also known as opendiff from the commandline. You do have to agree to the Xcode/iOS license, which requires local admin privileges, to use this tool.$ which opendiff/usr/bin/opendiffIt appears to provide a very intuitive GUI representation of the differences. You can also configure it to be thedefault merge tool with Git.git config --global merge.tool opendiffIf you want to launch FileMerge from the Launcher, you’ll need to open the Applications folder, right-click on XCode,choose to ‘Show Package Contents’, then navigate to Contents/Applications. Inside you’ll see the FileMerge application.If you right-click on FileMerge, you can right-click, choose to ‘Make Alias’, then move the alias to your Applicationsfolder."
    } ,
  
    {
      "title"    : "Running a Bitcoin Core Full Node",
      "category" : "",
      "tags"     : "ubuntu, bitcoin",
      "url"      : "/2017/05/running-a-bitcoin-core-full-node/",
      "date"     : "2017-05-25 21:08:00 -0700",
      "content"  : "There has been a lot of hype concerning crypto currencies like Bitcoin and Ethereum recently. I even had some of my ownminor gains through an account I have with Coinbase.com.I haven’t been much into the zeitgeist of Bitcoin investment, or even the possibilities of blockchainmethods used for real-world applications other than currency, until now.You will need a server that has at least 150 GB available, and as the size of the blockchain increases this will rise.I configured my node to use the auto-pruning feature, but it still is using 128 GB currently.$ du -sh .bitcoin/128G  .bitcoin/Install the software-properties-common Packagesudo apt-get install software-properties-commonAdd the Bitcoin Personal Package Archive (PPA)sudo apt-add-repository ppa:bitcoin/bitcoin Stable Channel of bitcoin-qt and bitcoind for Ubuntu, and their dependenciesNote that you should prefer to use the official binaries, where possible, to limit trust in Launchpad/the PPA owner.No longer supports precise, due to its ancient gcc and Boost versions. More info: https://launchpad.net/~bitcoin/+archive/ubuntu/bitcoinPress [ENTER] to continue or ctrl-c to cancel adding itIgnore the message about ‘precise’ no longer being supported, and press ENTER to continue. It’s referring to Ubuntu12.04.5 LTS (Precise Pangolin). You can check your own version of Ubuntu by running cat /etc/lsb-release.After this completes you should update all the packages.sudo apt-get updateInstall Bitcoin Core daemon (bitcoind)sudo apt-get install bitcoindConfiguring Bitcoin DaemonA problem that you will likely run into is where the daemon uses up all the disk space on your server. I recommendcreating abitcoin.confconfiguration file. It’s best to set the minimum value for pruning, and also set the db cache size to be an appropriateamount of RAM in measured in megabytes.# Enable pruning to reduce storage requirements by deleting old blocks.# This mode is incompatible with -txindex and -rescan.# 0 = default (no pruning).# 1 = allows manual pruning via RPC.# &gt;=550 = target to stay under in MiB.prune=550# Set database cache size in megabytes (4 to 16384, default: 300)dbcache=1000Run Bitcoin Core DaemonExit to an unprivileged user account, and then run bitcoind -daemonbitcoind -daemon -conf=bitcoin.confBitcoin server startingAfter this point you can run various commands to interact with the daemon.# Get Network Infobitcoin-cli getnetworkinfo# Get Blockchain Infobitcoin-cli getblockchaininfo# Get Wallet Infobitcoin-cli getwalletinfo# Stop the Nodebitcoin-cli stopStarting Bitcoin DaemonIt’s cumbersome to type the command above each time you need to re-start the daemon. By default Ubuntu configuresyour $PATH so that it includes ~/bin, should that directory exist. Do the following to prepare some scripts foreasy execution.mkdir ~/bintouch ~/bin/btcstarttouch ~/bin/btclogecho -e '#!/usr/bin/env bash\nbitcoind -daemon -conf=~/bitcoin.conf' &gt; ~/bin/btcstartecho -e '#!/usr/bin/env bash\ntail -F ~/.bitcoin/debug.log' &gt; ~/bin/btclogYou’ll have to logout and log in again, but now you will be able to start your daemon using btcstart command.$ btcstartBitcoin server starting$ btclog2017-05-26 15:59:19 Opened LevelDB successfully2017-05-26 15:59:19 Using obfuscation key for /home/johnsmith/.bitcoin/blocks/index: 0000000000000000......You’ll have to use CTRL+C to exit out of the logs."
    } ,
  
    {
      "title"    : "Configuring a New Ubuntu Server with Sudo",
      "category" : "",
      "tags"     : "ubuntu, sudo, sshd, security",
      "url"      : "/2017/05/configuring-new-ubuntu-server-with-sudo/",
      "date"     : "2017-05-25 21:08:00 -0700",
      "content"  : "Here are my notes for configuring a new Ubuntu server with a single user with sudo rights, with the ‘root’ user logindisabled in the SSHd configuration.This guide assumes that you have just created a server from the web interface of a service likeLinode or Digital Ocean, and you know the root password.Local ConfigurationFrom your local machine, you can configure your SSH client within ~/.ssh/config. Use the following configurationto connect to the server using a specific username and SSH key.Host myserver  Hostname 192.168.1.2  Port 22  User johnsmith  IdentityFile ~/.ssh/id_rsaThis configuration makes it possible to connect to the server quickly using ssh myserver.Create User AccountBecause the account doesn’t exist on the server yet, you’ll need to login as root with the root password or with thesame type of SSH key configuration.Once you’re in the server as ‘root’, create the user account using:adduser johnsmithAdd User to Sudo GroupUbuntu has a ‘sudo’ group already setup. Simply use usermod to add your new user account to that group.usermod -aG sudo johnsmithConfigure SSH KeyYou’ll need to login to the new account using the su command.su - johnsmithNext create a ~/.ssh folder with authorized_keys file, and place your public SSH key (likely located within~/.ssh/id_rsa.pub on your local machine) within this authorized_keys file.mkdir -p ~/.ssh/touch ~/.ssh/authorized_keysnano ~/.ssh/authorized_keysAfter you’ve configured your new account for SSH key authentication, use exit to get back to ‘root’.Configure SSHd to Disallow Root User LoginWithin /etc/ssh/sshd_config, find the PermitRootLogin setting and set it from ‘yes’ to ‘no’. Do the same for the‘PasswordAuthentication’ setting.PermitRootLogin noPasswordAuthentication noAlso add an entry that ensures that only your sudo user can login, for good measure. This keeps any other accountsthat might exist from being used.AllowUsers johnsmithFor good measure you could also change the port used by SSHd. This would require that you set a different port numberin your SSH config file (~/.ssh/config) with the port specified.Port 6221After you’ve saved the changes to the configuration file, restart the SSHd server./etc/init.d/ssh restartNow logout and hope that you can login as your user. Perhaps you should stay logged in and open a new terminal taband test it out before you logout as ‘root’.Becoming RootNow you can log into your box as your normal user account, then become root using:sudo su rootYou’ll just have to type in your own password once. This means that hackers will need to know your username, SSHprivate key, and password, to gain full access to your box."
    } ,
  
    {
      "title"    : "Detecting if WebMock is enabled for Net::HTTP",
      "category" : "",
      "tags"     : "WebMock, HTTParty",
      "url"      : "/2017/05/detecting-webmock-enabled-net-http/",
      "date"     : "2017-05-17 14:43:52 -0700",
      "content"  : "I ran into an issue where we were mocking HTTP responses 400+ in our Rspec tests, which resulted in our applicationlogging an error and a stack trace. When we expect errors because we’re using WebMock to emulate an HTTP 500 response,logging the stack trace involved can be too verbose.Sometimes we might need the stack trace, such as when a developer is debugging code involving the handling of errorresponses. I discussed this with other developers they expressed that they don’t want to introduce a globalconfiguration flag to turn the stack trace logging on or off.The ideal solution was to simply not log the stack trace when WebMock is being used in the ‘test’ environment.We’re using HTTParty, which uses Net::HTTP. I did some investigating and discovered that when WebMock isenabled (via WebMock.enable!), that it replaces the HTTP module with it’s own. There isn’t anything clear to indicateif WebMock is enabled or not, however I noticed thatNet::HTTP.socket_type is redefined as StubSocketwhen WebMock is enabled.&gt; Net::HTTP.socket_type=&gt; Net::BufferedIO&gt; WebMock.enable!=&gt; {:net_http=&gt;WebMock::HttpLibAdapters::NetHttpAdapter}&gt; Net::HTTP.socket_type=&gt; StubSocket&gt; WebMock.disable!&gt; Net::HTTP.socket_type=&gt; Net::BufferedIOI don’t see the equivalent modification in other adapters, such asCurbI’m going to open a Github issue requesting support such as this. Perhaps a simple unified call to set a classvariable in WebMock class itself, with a corresponding WebMock.is_enabled? method. I’ve madean issue to request this. I will make a pull request soon."
    } ,
  
    {
      "title"    : "Static Hosting with Neocities",
      "category" : "",
      "tags"     : "static, neocities, jekyll",
      "url"      : "/2017/05/static-hosting-with-neocities/",
      "date"     : "2017-05-12 09:43:51 -0700",
      "content"  : "I’ve been using a Wordpress site for my blog for years, but that has become cumbersome,especially when you have to deal with your website being exploited due to holes inone of the many plugins that your site is relying on.I used to focus on LAMP stack development, and so running my own cPanel/WHM serverwas a no brainer. I more recently migrated my tech blog, Ruby Colored Glasses,from Wordpress to Github Pages. This is nice because the site is hosted for free by Github,however that’s limited to one site per each account.So I’ve decided to try to find another cheap low-cost static website solution that works with Jekyll.NeocitiesBack in the 90’s there used to be a free hosting solution known as GeoCities that hosted many awesome websitesfor many people. This is where many people were able to express themselves in their own unique ways, while alsolearning HTML.Neocities hopes to provide the same type of community. For $5 a month you canbecome a Supporter, which earns you the ability to create as many sites as you wish,use a custom domain with each site, and also use WebDAV to manage files. If you want the same for a lifetime, you cansend them $100 via Bitcoin.So my goal at the current moment is to explore if it’s possible to generate a website via Jekyll, and then uploadit to one of the Neocities sites.ImportOne of the first steps for me is to import my Wordpress site. There is a plugin that one can use to import all of their Wordpress content into a Jekyll site, however it requires that you havedirect MySQL access to your server.Note: The importer only converts your posts and creates YAML front-matter. It does not import any layouts, styling, or external files (images, CSS, etc.).Configure Server for Public AccessI had to go into my server and configure MySQLd to bind to more than just the local hostaddress. This required that I edit /etc/mysql/mysql.conf.d/mysqld.cnf on the Ubuntu machineI’m currently hosting the site from and change the IP to 0.0.0.0.# Instead of skip-networking the default is now to listen only on# localhost which is more compatible and is not less secure.# bind-address          = 127.0.0.1bind-address            = 0.0.0.0I was then able to connect directly to the server and authenticate. Luckily I didn’thave any sort of firewall blocking the ports. I tested the connection using this command:mysql --host=123.321.123.5 --user=my_user --password=mySecr3tPaSS my_database_nameInstall Gemsgem install jekyll-import unidecode sequel mysql2 htmlentitiesPerform ImportI’m choosing to import all the files to md (Markdown) file extensions instead of ‘html’. This command worked just fine for me.ruby -rubygems -e 'require "jekyll-import";  JekyllImport::Importers::WordPress.run({    "dbname"   =&gt; "my_db_name",    "user"     =&gt; "my_db_username",    "password" =&gt; "my_secret_password",    "host"     =&gt; "192.123.193.12",    "socket"   =&gt; "",    "table_prefix"   =&gt; "wp_",    "site_prefix"    =&gt; "",    "clean_entities" =&gt; true,    "comments"       =&gt; true,    "categories"     =&gt; true,    "tags"           =&gt; true,    "more_excerpt"   =&gt; true,    "more_anchor"    =&gt; true,    "extension"      =&gt; "md",    "status"         =&gt; ["publish"]  })'This resulted in all my pages and posted imported into the repository, and ready for a long cleanup.ResourcesHere are some various links I’ve explored in finding a low-cost Jekyll based hosting solution.  DesignRope - Static Web Hosting: Who’s Best?  Aerobatic  Neocities          Neocitizen - Used to public site from a folder        Neocities API  Jekyll Docs - Wordpress Import  Jekyll Docs - Deployment Methods  James Ward - Jekyll on Heroku  Netlify - Static hosting with a free entry tier  Hugo - an alternative to Jekyll I assume  Smashing Magazine - Static Website Generators Reviewed"
    } ,
  
    {
      "title"    : "Intro to Tmux",
      "category" : "",
      "tags"     : "tmux, screen",
      "url"      : "/2016/06/tmux-intro/",
      "date"     : "2016-06-30 00:00:00 -0700",
      "content"  : "Recently I learned a few of the basic commands needed to usethe GNU screen command to keepa command line session running even after I’ve disconnected from a remote VPS.I learned this specifically so that I could keep irssirunning and logged into a specific IRC channel, so I could return to the sessionand view the history of messages that I had missed.Recently I heard about Tmux as analternative solution, and also discovered that it can also be used to maintainseparate virtual terminals (windows), as well as split the screen into separate“panes”. Splitting the screen into panes can also be done with GNU screen, butit’s not as well supported. See reasons to use tmux instead of screen.InstallationInstalling for MacUse Homebrew to install tmux on a Mac OS X machine.brew install tmuxInstalling for Linuxsudo apt-get install tmuxFirst UseAfter you run tmux for the first time, you’ll notice that you are returned toa typical shell prompt, however there is now a green bar at the bottom of yourscreen.You are now operating within a tmux session. Within a session you can establishmultiple windows, with each window supporting multiple panes that display withinthe window.Sessions are like different work spaces. You can detach from a work space andthen drop into another session that you setup previously.PanesMany commands supported by tmux involve using a keystroke known as the ‘prefix’.By default this keystroke is CTRL + B, however you can configure tmux to usea different keystroke as the prefix.Pressing CTRL + B, followed by % will split the screen into two panesvertically. You can press CTRL + B (PREFIX), then one of the arrow keys toswitch between the panes. For instance PREFIX, then LEFT ARROW key will moveyour cursor to the left pane.Next if you type PREFIX then " (PREFIX - "), it will split the pane into twopanes horizontally. You can use PREFIX then UP ARROW or DOWN ARROW to switchbetween the horizontal panes.When you are inside of a specific pane, you can hold down the PREFIX keystrokeand tap one of the arrow keys multiple times to resize the pane.If you want to make a pane temporarily full screen, you can use PREFIX - z totoggle between full screen and original size.To close a pane you can simply use the exit command from the shell.WindowsUse PREFIX - c to open up a new window. You’ll now see that the status barat the bottom of the screen reflects the new windows existence. You can switchbetween the windows using PREFIX followed by the number of the window (e.g.PREFIX - 0 and PREFIX - 1).Notice that there is an asterisk (*) next to the window that you are currentlyviewing in the status bar, and a dash (-) next to the last window you wereviewing. PREFIX - l will allow you to switch between the current and lastwindow.SessionsA session will run in tmux until you end it. You can detach from a session byusing PREFIX - d. You can list sessions using tmux list-sessions ortmux ls.You can re-attach to the tmux session by using tmux attach. If you havemultiple sessions runing, you can use tmux attach -t 0, where -tmeans “target”, and 0 is the number for the session. You can also killsessions using a similar command: tmux kill-session -t 0.Alternatively you can name sessions when you start them usingtmux new -s session_name, and then use tmux attach -t session_name toreconnect to the session.Further Reading  tmux cheatsheet  Thoughtbot - A tmux Crash Course  The Pragmatic Programmer - tmux"
    } ,
  
    {
      "title"    : "Unbricking TP-Link TL-WDR4300",
      "category" : "",
      "tags"     : "wifi, tp-link, wdr4300, openwrt, mesh",
      "url"      : "/2016/04/tp-link-wdr4300-recovery/",
      "date"     : "2016-04-14 00:00:00 -0700",
      "content"  : "I tried to flash the TP-Link TL-WDR4300 router with a custom OpenWRT imagerecently, and after doing so I was unable to connect to the device like Iexpected.Here is how you can recover / un-brick the device.Install tftpdI’m using an Ubuntu machine. There are instructions for installing tftpd andxinetd, but these don’t seem to work with Ubuntu 14.04. If you’re using Windows,then I recommend this video.I found instructions on a Spiceworks.com forumthat worked for me.Install tftpd-hpa and tftp clientsudo apt-get install tftpd-hpa tftpEdit the TFTPd Configuration FileEdit /etc/default/tftpd-hpa to use the following configuration$ sudo vi /etc/default/tftpd-hpaTFTP_USERNAME="tftp" TFTP_DIRECTORY="/tftpboot" TFTP_ADDRESS="0.0.0.0:69" TFTP_OPTIONS="-s -c -l -vv"The -vv will cause the TFTP server to log out to /var/log/syslogCreate the TFTP DirectoryThe server will serve files from the /tftpboot directory. You need to createit and give it the proper permissions.sudo mkdir /tftpbootsudo chmod -R 777 /tftpboot sudo chown -R nobody /tftpbootRestart the servicesudo service tftpd-hpa restartTest the TFTP DaemonCreate a file in the directoryecho "this is a test" &gt; /tftpboot/test.txtDownload the file via tftp to your home directory. If it downloads fine, yourtftp server is running.$ cd ~$ tftp localhosttftp&gt; get test.txtReceived 16 bytes in 0.1 secondstftp&gt; quit$ cat test.txtthis is a testDownload the Latest FirmwareDownload the firmware from the tp-link official support page to the /tmp directory and unzip the file.cd /tmpwget http://www.tp-link.us/res/down/soft/TL-WDR4300_V1_151104_US.zipunzip TL-WDR4300_V1_151104_US.zipCopy the binary image file to /tftpboot named as ``.cp wdr4300v1_en_us_3_14_3_up_boot\(151104\).bin /tftpboot/wdr4300v1_tp_recovery.binConfigure your MachineChange your machines IP address to 192.168.0.66. The router will try toconnect to this address and download the image from it in a future step. Thisrequires a subnet setting of 255.255.255.0, with a gateway of 0.0.0.0.Enable TFTP Recovery ModeTaken from OpenWRT - TP-Link TL-WDR4300 - Flashing via TFTP:Power up the TL-WDR4300 and as soon as the asterisk/star symbol to the right ofthe power/IO image starts to flash, hold down the WPS/Reset button that is onthe back of the device for about 10 seconds. The asterisk symbol should beginto flash much faster than before. Let the device continue to fit and do thisuntil it reboots.Wait for the firmware transfer (about 20s), firmware flash (about 90s) and subsequent reboot (about 30s).You can tail the syslog to see if the router is actually interfacing with the TFTPd server.tail -F /var/log/syslogReferences  DD-WRT Forum - How to unbrick TP-Link N750 WDR-4300  DD-WRT - TP-Link TL-WRT4300  "
    } ,
  
    {
      "title"    : "Getting Started with IRSSI",
      "category" : "",
      "tags"     : "irc",
      "url"      : "/2016/04/getting-started-with-irssi/",
      "date"     : "2016-04-09 00:00:00 -0700",
      "content"  : "Often open source projects or organizations use an IRC channel on FreeNode toprovide support to users and/or developers. I’m trying to retain familiaritywith the command line, rather than become completely dependent on GUIapplications, so I’ve decided to use IRSSI instead of Pidgin or Adium (Mac OS X).InstallationInstalling IRSSI is easy on Ubuntu, simply use:apt-get install irssiYou can also install it using Homebrew on Mac OSX:brew install irssiAfter it’s done installing, simply run the programirssiWindowsIRSSI support separate “windows” for the different channels you are connectedto, or for the different people you are chatting with. If for some reason youdo not see information on the screen for a command you’ve run, it may bedisplayed in another window.By default you can use the ALT key combined with a number key (e.g. ALT+1,ALT+2, ALT+3, etc) to switch between the different displays in IRSSI.If your terminal program doesn’t support this, or uses these key combinationsto switch between it’s own tabs (like Ubuntu terminal does), then you shoulduse the /window command instead./WINDOW NEW                    - Create new split window/WINDOW NEW HIDE               - Create new hidden window/WINDOW CLOSE                  - Close split or hidden window/WINDOW HIDE [&lt;number&gt;|&lt;name&gt;] - Make the split window hidden window/WINDOW SHOW &lt;number&gt;|&lt;name&gt;   - Make the hidden window a split window/WINDOW SHRINK [&lt;lines&gt;]       - Shrink the split window/WINDOW GROW [&lt;lines&gt;]         - Grow the split window/WINDOW BALANCE                - Balance the sizes of all split windowsCommandsFor those that are new to IRC, it’s a good idea to become familiar withthe common commands that IRC programs support. Here are a few:  /join #channel_name - Joins a channel  /names - Lists names of users in the current channel  /who &lt;nickname&gt; - Get info on user (shown in window 1)  /me &lt;action&gt; - Announces some action such as /me waves hello  /msg &lt;nickname&gt; &lt;message&gt; - Send a direct message to another user  /ignore &lt;nickname&gt; - Block someone that is harassing you  /quit or /exit - Quits IRC programThere are other commands that are supported only by IRSSI that can be found inthe IRSSI DocumentationIt’s recommended that you use the /help command to get the list of othersupported commands. You can get more information on each command by followingthe /help command with the name of the command. For instance you can get moreinformation on the /connect command by using /help connect.Getting StartedUpon opening the program for the first time IRSSI will connect to a defaultIRC network. There is a configuration file in ~/.irssi/config that you caninspect, but you can use commands from within the program to configure IRSSI toautomatically perform when you first open the program. This includes connectingto Freenode, authenticating using your registered nick name, and joining adefault channel.You can use these commands to get started immediately:Set your nick name and real name/set nick &lt;nick&gt;/set real_name &lt;Real Name&gt;Connecting to FreeNode/connect irc.freenode.net 8001Join Channel/join #ubuntuRegistering with FreeNodeThe FreeNode IRC network allows you to register your nickname and associateit with your email address. This is done by using the following commands:/msg nickserv REGISTER &lt;password&gt; &lt;email&gt;You should receive a message informing you that you need to check your emailaccount and obtain instructions to verify yourself.To make sure that your email address isn’t revealed to other users, use thefollowing command to ensure that it is hidden./msg NickServ SET HIDEMAIL ONYou can verify your information with the NickServ by using:/msg nickserv infoAutomatic ConfigurationConfigure IRSSI with Freenode network, then register the Freenode server you will connect to via an SSL connection, then configure the automatically joinedchannel (#ubuntu in this example)./network add Freenode/server add -auto -ssl -ssl_verify -ssl_capath /etc/ssl/certs -network Freenode irc.freenode.net 7000/channel add -auto #ubuntu Freenode/saveAfter you’ve successfully registered your FreeNode nick name, you can run thiscommand to configure IRSSI to login automatically after connecting to FreeNode./network add -autosendcmd "/msg nickserv identify &lt;password&gt; ;wait 2000" Freenode"
    } ,
  
    {
      "title"    : "Recommended Gems",
      "category" : "",
      "tags"     : "gems, ruby",
      "url"      : "/2016/03/recommended-gems/",
      "date"     : "2016-03-05 00:00:00 -0800",
      "content"  : "Here are some Gems we recommend that you checkout.  Authentication / Authorization          devise - Flexible authentication solution for Rails with Warden      cancan - authorization library for Rails which restricts what resources a given user is allowed to access      pundit - Minimal authorization through OO design and pure Ruby classes        HTTP Clients          curb - Ruby bindings for libcurl      httparty - Fun HTTP client for Ruby      typhoeus - Multithreaded library for accessing web services in Ruby        Mac OSX          lunchy - A friendly wrapper for launchctl, used to manage services. Great for managing daemons installed via Homebrew, such as Postgres, Memcached, Redis, etc.        Logging          itslog - log formatter with color support        Rails Console          pry - IRB alternative and runtime developer console                  pry-rails - Rails initializer for Rails          pry-remote - Connect to pry console remotely          pry-nav - Binding navigation commands for Pry to make a simple debugger                    rbenv - Simple Ruby version management. Less intrusive than RVM.        ORM          audited - ORM extension that logs all changes to your Rails models        Form Helpers          simpleform - Alternative form helpers, tied to a simple DSL, with no opinion on markup, with support for Twitter Bootstrap        Configuration          figaro - Facilitates storing sensitive configuration information for your app in a file not checked into the repository, such as AWS keys, passwords, etc.        Testing / Continuous Integration          rspec - Alternative to Test::Unit. Easier to read. More specific test support (doesn’t couple view/controller testing)      webmock - Library for stubbing and setting expectations on HTTP requests in Ruby      simplecov - SimpleCov is a Code coverage analysis tool for Ruby 1.9+.      fabrication - alternative to FactoryGirl for fixtures replacement. Github      database_cleaner - Strategies for cleaning databases in Ruby. Can be used to ensure a clean state for testing      heckle - mutation tester that modifies your code and runs your tests to make sure they fail (like they should)      cucumber-rails - Rails Generators for Cucumber with special support for Capybara and DatabaseCleaner      launchy - launches external application from within ruby programs. Used to view state of virtual page renders with Cucumber/Capybara      capybara - Acceptance test framework for web applications      capybara-webkit - A capybara driver that uses WebKit via QtWebKit      poltergeist - Headless Javascript engine driver for Capybara      headless - Ruby wrapper for Xvfb, the virtual framebuffer      guard - command line tool to easily handle events on file system modifications. Use ‘gem search -r ^guard-‘ to view the many plugins that work with guard to automate testing, asset building, etc.                  guard-rspec - automatically run your specs after modifying models/spec files          guard-pow - automatically manage Pow applications restart          guard-cucumber - automatically run your features                      Development          capistrano - Used to deploy Rails applications to hosting environments such as a VPS      capistrano-unicorn - Capistrano integration for Unicorn      jasminerice - Pain free coffeescript testing under Rails 3.1      "
    } ,
  
    {
      "title"    : "Looping through dictionaries in jinja2 templates",
      "category" : "",
      "tags"     : "jinja2, ansible, templates",
      "url"      : "/2015/11/looping-through-dictionaries-in-jinja2-templates/",
      "date"     : "2015-11-05 02:10:32 -0800",
      "content"  : "I am adding a script to our server using Ansible. The roles are all setup to support multiple Wordpress websites based on the dictionary defined in ansible/group_vars/wordpress_sites.yml, as my Ansible configuration is based on Trellis.I don’t want to use the Ansible template module to create a script for every website, because really I only have one website configured. Sure I might have configuration files for each site under Nginx, so that makes sense. So I decided that instead of creating multiple scripts, I’ll just have Ansible generate scripting for each of the sites inside of my shell script.Well it turns out that this isn’t do easy for someone not very familiar with Jinja2 templates or Python objects.At first I figured that I would simply loop through each element inside of the ‘wordpress_sites’ dictionary like so:{% for site in wordpress_sites.values() %}echo "-------------------------------------------------------"echo "| Backing Up Assets and Database for {{ site.key }} |"echo "-------------------------------------------------------"echo ""read -s -p "MySQL Password for '{{ site.env.db_user }}': " mysqlpw# Other script code goes here for each site{% endfor %}Unfortunately when I’d run the script to generate this site I would get this error:TASK: [admin-scripts | Add Backup script] *************************************fatal: [45.79.167.52] =&gt; {'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'str object' has no attribute 'env'", 'failed': True}fatal: [45.79.167.52] =&gt; {'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'str object' has no attribute 'env'", 'failed': True}This was very frustrating, as I just expected each object to have yet another dictionary object as it’s value. Why am I getting a string object?After much experimentation (trial and error), I realized that I could traverse through the dictionary manually.{{ wordpress_sites }}{{ wordpress_sites['mysite.example.com'].env }}{{ wordpress_sites['mysite.example.com'].env.db_user }}{{ wordpress_sites['mysite.example.com'].env.doesnt_exist }}This resulted in an error about no attribute ‘doesnt_exist’, so I knew that the global variable is there and accessible. So there must be something wrong with the loop that is converting the value to a string. I found an article that used dict.values(), implying that you could call values() on a dictionary, and it would return the values.I guess that a for loop inside of a jinja2 template expects a list, not a dictionary.{% for site in wordpress_sites.values() %}echo "-------------------------------------------------------"echo "| Backing Up Assets and Database for {{ site.key }} |"echo "-------------------------------------------------------"echo ""read -s -p "MySQL Password for '{{ site.env.db_user }}': " mysqlpw# Other script code goes here for each site{% endfor %}This still left me unable to access the key that was used to represent the site, which is needed by my script. I tested a configuration that iterated with key and value available inside of the code block.{% for site_name, site in wordpress_sites.iteritems() %}echo "-------------------------------------------------------"echo "| Backing Up Assets and Database for {{ site_name }} |"echo "-------------------------------------------------------"echo ""read -s -p "MySQL Password for '{{ site.env.db_user }}': " mysqlpwecho ""{% endfor %}This resolved my issue.I wonder if this is the type of thing that’s a no brainer to a Python developer. Probably."
    } ,
  
    {
      "title"    : "Vagrant SSH Failure - Connection closed by remote host",
      "category" : "",
      "tags"     : "",
      "url"      : "/2015/09/vagrant-ssh-failure-connection-closed-by-remote-host/",
      "date"     : "2015-09-10 19:21:52 -0700",
      "content"  : "I recently was running into issues with Vagrant where I’d start the virtual machine using the ‘vagrant up’ command, but I’d receive an error when trying to use vagrant ssh.$ vagrant sshssh_exchange_identification: Connection closed by remote hostI’m using a Vagrant/Ansible configuration based on roots/trellis.I tried to look into the issue further by running the command with verbose output.$ vagrant ssh -- -vvvI noticed that it’s trying to use 127.0.0.1 to SSH into the VM on port 2222. When I try to SSH manually using ssh vagrant@192.168.50.5 -p 2222 it works fine, but with 127.0.0.1 I get the error still. It seemed that connecting to the VM from 127.0.0.1 is triggering some sort of block.I tried to check /var/log/syslog and /var/log/auth.log (with SSHD configured for verbose mode). I don’t see any log for the failed attempt in the auth.log, though I do see a normal login. It doesn’t seem like the connection is being blocked.I reported this issue to the roots/trellis project - #348After further investigation I realized that I was configuring sshd on the virtual machine to use port 2222, when really Vagrant or Virtualbox was responsible for forwarding port 2222 on localhost to port 22 of the VM. I was essentially making the port forwarding that it configures invalid by changing SSHD to listen on port 2222."
    } ,
  
    {
      "title"    : "Error when building PhantomJS 2.0",
      "category" : "",
      "tags"     : "phantomjs",
      "url"      : "/2015/08/error-when-building-phantomjs-2-0/",
      "date"     : "2015-08-08 01:34:12 -0700",
      "content"  : "I was tasked with installing PhantomJS 2.0 on an Ubuntu 14.04 VPS running with 2 GB of RAM. Online discussions on Github and Google Groups seemed to have pointed to the build process requiring much RAM to complete without error.g++: internal compiler error: Killed (program cc1plus)Please submit a full bug report, with preprocessed source if appropriate.See &lt;file:///usr/share/doc/gcc-4.8/README.Bugs&gt; for instructions.make[2]: *** [.obj/inspector/InspectorAllInOne.o] Error 4make[2]: *** Waiting for unfinished jobs....make[2]: Leaving directory `/home/app/src/phantomjs-2.0.0/src/qt/qtwebkit/Source/WebCore'make[1]: *** [sub-Target-pri-make_first-ordered] Error 2make[1]: Leaving directory `/home/app/src/phantomjs-2.0.0/src/qt/qtwebkit/Source/WebCore'make: *** [sub-Source-WebCore-WebCore-pro-make_first-ordered] Error 2To overcome this error I checked the build.sh script and found that the script would discover the number of CPU cores you’re running on a machine and thus run that many concurrent build processes, thus using more memory. To overcome this you can run the script with the number of jobs specified.$ ./build.sh --jobs 1It turns out that this wasn’t anything new. The official build instructions actually advise to use the --jobs 1 argument, I just missed this because I downloaded the ZIP file before proceeding. I did however find out that the ZIP file they have you download still results in error, whereas pulling the source from the ‘2.0’ branch of Github is building much better now."
    } ,
  
    {
      "title"    : "Setup Environment for Django Development",
      "category" : "",
      "tags"     : "python, django, virtualenv, pip",
      "url"      : "/2015/02/setup-environment-for-django-development/",
      "date"     : "2015-02-02 00:26:28 -0800",
      "content"  : "Although this website is primarily devoted to Ruby / Rails development, I’ve found it necessary to learn Python for a new position I might take in the upcoming year. Here is my guide for setting up your local workstation for Python / Django development on a Mac OS X workstation.HomebrewThe first step is to ensure that you have Homebrew installed, which is a package manager for Mac OS X that installs various software packages that are ported for Mac OS X.To install Homebrew run the following from your Terminals command line:ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"Once this is installed you should run ‘brew doctor’ and make sure that it’s setup properly. Usually I find that I have to make sure that /usr/local/bin is the first path shown in /etc/paths. You can edit this using nano from the command line.$ sudo nano /etc/pathsYou’ll likely also have to run brew update. Once brew doctor reports ‘Your system is ready to brew’, you can move forward.For development it’s important to install software packages that are provided by Homebrew, so that all the executables and libraries you are using are provided by Homebrew, and thus not conflicting with system libraries. Homebrew installs executables in /usr/local/bin, which is configured to be your primary path. This ensures that when you try to run a command it uses the Homebrew executable and libraries rather than the default executables and libraries provided by Mac OS X.PythonThe next step is to install Python. By default Python v2.7.6 is already available for Mac OS X (Yosemite), however certain programs may rely on this version of Python to run on your system. By installing Python via Homebrew, it will depend on other dependencies installed by Homebrew.This command will install both python version 2 and 3.$ brew install python python3After this is finished you can use ‘which’ to see which Python executables are present in your environment by default.$ brew install python python3$ which python/usr/local/bin/python$ which python3/usr/local/bin/python3As you can see, the Homebrew versions of Python will be used when you use these commands.VirtualEnv and VirtualEnvWrapperPython comes with a package manager called Pip that installs Python libraries from the PyPI (Python Package Index). By default, this library installs packages globally for the version of Python you are using. For instance for Python v2, you would use ‘pip’, and for Python v3, you would use ‘pip3’ to install Python packages.$ which pip/usr/local/bin/pip$ which pip3/usr/local/bin/pip3These packages are installed globally, and available across all your projects. This can be convenient, but it can also become a problem. For instance, one project might require one version of Django, while another project requires another one be installed as the primary version.In the Ruby community this is where RVM or rbenv have been used to isolate the environment in use when you’re running a specific Ruby application, with an isolated RubyGem gem set.In the Python community the preferred tool is VirtualEnv and VirtualEnvWrapper. These are both Python tools that will need to be installed globally.$ pip install virtualenv virtualenvwrapperNext you’ll want to make a directory to store your virtual environments under. To keep these hidden we’ll create a hidden directory under your home directory.mkdir ~/.virtualenvsNext add the following to your .profile file in your home directory.export WORKON_HOME=$HOME/.virtualenvssource /usr/local/bin/virtualenvwrapper.shexport PIP_VIRTUALENV_BASE=$WORKON_HOMEalias workoff='deactivate'You can now create a new project to work in using the following command:$ mkvirtualenv mydjangoappNew python executable in mydjangoapp/bin/python2.7Also creating executable in mydjangoapp/bin/pythonInstalling setuptools, pip...done.Next, to work in this virtual environment, use the ‘workon’ command like so:$ workon mydjangoappTo exit the virtual environment you are in, simply use the ‘deactivate’ or ‘workoff’ command. You can remove virtual environments using the ‘rmvirtualenv’ command.To create a virtual environment using the Homebrew version of Python 3, use this command:$ mkvirtualenv -p /usr/local/bin/python3 mydjangoappPostgresTypically I’d use MySQL, but it looks like the open source community is recommending adoption of Postgres. For instance, Heroku doesn’t support MySQL by default, as they found it more portable than MySQL databases.Run the following to install Postgres, set it up to be started automatically by the system daemon launcher (launchd), and then start the service immediately.$ brew install postgres$ ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plistNow that the Postgres server is up and running, we need to establish an empty database and a user with all permissions for that database.The Postgres config file is located in /usr/local/var/postgres/pg_hba.conf.Psycopg2Django requires the Psycopg2 library to connect with Postgres databases. Go into your virtual environment and install this package as well as the Django package.$ workon mydjangoapp$ pip install psycopg2 djangoDjangoNow we’re ready to create our first Django application.$ django-admin.py startproject mydjangoappInside of the project folder you just created will be another folder with the same name (mydjangoapp). To Python, this simply looks like a Python module. Django doesn’t care what the name of the outer folder is, just as long as the app folder within it holds the correct name and configuration files.After you’ve created the new application folder, change into it’s directory and run the following to start the Django development server.$ cd mydjangoapp$ python manage.py runserverIf you want to run this server on another IP address or port this is possible. See runserver reference.$ python manage.py runserver 8080$ python manage.py runserver 0.0.0.0:8000Database SetupWe need to create a database, and then a user with permissions to use the database in PostgreSQL. Typically you would run sudo as the ‘postgres’, but Postgres was installed by Homebrew to run as you, so you’re the Postgres admin user.$ createdb mydjangoapp$ createuser -SDR mydjangoapp$ psql -d postgres -c "ALTER USER mydjangoapp WITH PASSWORD 'devpass';"ALTER ROLE$ psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE mydjangoapp to mydjangoapp;"GRANTInside of your application folder you’ll see a ‘settings.py’ file. This file holds various settings for your Django application, which technically is a Python module. By default Django uses SQLite for the database, however we’re going to use PostgreSQL.This requires that we change the keys in the DATABASES ‘default’ item inside of settings.py.DATABASES = {    'default': {        'ENGINE': 'django.db.backends.sqlite3',        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),    }}For our needs change this entry to reflect the following:DATABASES = {    'default': {        'ENGINE': 'django.db.backends.postgresql_psycopg2',        'NAME': 'mydjangoapp',        'USER': 'mydjangoapp',        'PASSWORD': 'devpass',        'HOST': '',        'PORT': '',    }}After saving these changes, run the following command to have Python create the needed tables inside of the database:$ python manage.py syncdbOperations to perform:  Apply all migrations: admin, auth, sessions, contenttypesRunning migrations:  Applying contenttypes.0001_initial... OK  Applying auth.0001_initial... OK  Applying admin.0001_initial... OK  Applying sessions.0001_initial... OKYou have installed Django's auth system, and don't have any superusers defined.Would you like to create one now? (yes/no): yesUsername (leave blank to use 'myusername'):Email address: myusername@example.comPassword: ******Password (again): ******Superuser created successfully.Now you’re ready to start building your application. You can start by generating a model using the following command.$ python manage.py mydjangoapp modelnameThis is where this guide leaves off. You can continue your experimentation with building a Django application by following the Writing your first Django app, part 1 tutorial from the Creating Models section."
    } ,
  
    {
      "title"    : "Issues with RVM after upgrade to OS X Mavericks",
      "category" : "",
      "tags"     : "",
      "url"      : "/2014/10/issues-with-rvm-after-upgrade-to-os-x-mavericks/",
      "date"     : "2014-10-02 00:00:00 -0700",
      "content"  : "So I just upgraded to OS X Mavericks (10.9.5). I also upgraded to X Code 6, and also installed the command line tools via the xcode-select --install command. I also have the ‘apple-gcc42’ Homebrew package installed to provide GCC 4.2.Still however, when I would try to install a version of Ruby via RVM, I would get this error:$ rvm install ruby-1.9.3ruby-1.9.3-p547 - #removing src/ruby-1.9.3-p547 - please waitSearching for binary rubies, this might take some time.No binary rubies available for: osx/10.9/x86_64/ruby-1.9.3-p547.Continuing with compilation. Please read 'rvm help mount' to get more information on binary rubies.Checking requirements for osx.Certificates in '/usr/local/etc/openssl/cert.pem' are already up to date.Requirements installation successful.Installing Ruby from source to: /Users/jasonmiller/.rvm/rubies/ruby-1.9.3-p547, this may take a while depending on your cpu(s)...ruby-1.9.3-p547 - #downloading ruby-1.9.3-p547, this may take a while depending on your connection...ruby-1.9.3-p547 - #extracting ruby-1.9.3-p547 to /Users/jasonmiller/.rvm/src/ruby-1.9.3-p547 - please waitruby-1.9.3-p547 - #applying patch /Users/jasonmiller/.rvm/patches/ruby/GH-488.patch - please waitruby-1.9.3-p547 - #configuring - please waitError running './configure --prefix=/Users/jasonmiller/.rvm/rubies/ruby-1.9.3-p547 --with-opt-dir=/usr/local/opt/libyaml:/usr/local/opt/readline:/usr/local/opt/libksba:/usr/local/opt/openssl --without-tcl --without-tk --disable-install-doc --enable-shared', showing last 15 lines of /Users/jasonmiller/.rvm/log/1412286075_ruby-1.9.3-p547/configure.logconfigure: WARNING: unrecognized options: --without-tcl, --without-tkchecking build system type... i386-apple-darwin13.4.0checking host system type... i386-apple-darwin13.4.0checking target system type... i386-apple-darwin13.4.0checking whether the C compiler works... noconfigure: error: in `/Users/jasonmiller/.rvm/src/ruby-1.9.3-p547':configure: error: C compiler cannot create executablesSee `config.log' for more detailsThere has been an error while running configure. Halting the installation.I was able to get it installed and running fine by specifying for RVM to use the clang compiler.$ rvm install 1.9.3 --with-gcc=clangNote: Had an issue with Canvas installation, which involved some C code displayed, but it turns out that this was due to an issue with the Thrift gem on Mavericks."
    } ,
  
    {
      "title"    : "Bypassing the AngularJS router for anchor tags",
      "category" : "",
      "tags"     : "AngularJS, ngRoute, routing, anchor, CSV download",
      "url"      : "/2014/09/bypassing-the-angularjs-router-for-anchor-tags/",
      "date"     : "2014-09-18 19:19:44 -0700",
      "content"  : "I’m working with a Rails application that is using an AngularJS front-end. We are using routing to override the behavior of anchor tags to ensure that they load other templates with controllers, as defined in our routeConfiguration.js. This works out great most of the time, unless you need to override the routing so that your anchor tag can point to an end-point served by your Rails back-end. In my case, I’m linking to an end-point that serves a named CSV file. Without any sort of over-ride, I was finding that the default fallback behavior defined by the otherwise() method was occurring. In my case this was a 404 page template that loaded.After much searching, the following solution was found. All you have to do is simply add a target attribute to the anchor tag with the value “_self”.&lt;a href="/download.csv" target="_self"&gt;Download CSV File&lt;/a&gt;Much thanks to BJ Basañes for posting this solution. I’m re-posting it here so that it’s not lost forever, and also so that I can lend additional keywords to lead others to this solution.Update: It turns out that this is mentioned in the documentation for $location."
    } ,
  
    {
      "title"    : "Sharing Administrative Rights with Homebrew",
      "category" : "",
      "tags"     : "homebrew, mac-osx, permissions",
      "url"      : "/2014/06/sharing-administrative-rights-with-homebrew/",
      "date"     : "2014-06-29 18:52:42 -0700",
      "content"  : "I installed Homebrew on my work computer, and have installed many ports using Homebrew from an account on my machine. This has resulted in all of the files and folders managed by Homebrew being owned by the user account I installed the ports from, with ‘admin’ group ownership.Recently I created another account on my machine, logged into it, and ran ‘brew doctor’ just to make sure everything was in excellent order, and I ran into these errors:$ brew doctorWarning: /usr/local/etc isn't writable.This can happen if you "sudo make install" software that isn't managed byby Homebrew. If a brew tries to write a file to this directory, theinstall will fail during the link step.You should probably `chown` /usr/local/etcWarning: /usr/local/include isn't writable.This can happen if you "sudo make install" software that isn't managed byby Homebrew. If a brew tries to write a file to this directory, theinstall will fail during the link step.You should probably `chown` /usr/local/includeWarning: /usr/local/lib isn't writable.This can happen if you "sudo make install" software that isn't managed byby Homebrew. If a brew tries to write a file to this directory, the install will fail during the link step.You should probably `chown` /usr/local/libWarning: /usr/local/lib/pkgconfig isn't writable.This can happen if you "sudo make install" software that isn't managed by by Homebrew. If a brew tries to write a file to this directory, the install will fail during the link step.You should probably `chown` /usr/local/lib/pkgconfigWarning: /usr/local/share isn't writable.This can happen if you "sudo make install" software that isn't managed by by Homebrew. If a brew tries to write a file to this directory, the install will fail during the link step.You should probably `chown` /usr/local/shareWarning: Some directories in /usr/local/share/man aren't writable.This can happen if you "sudo make install" software that isn't managed by Homebrew. If a brew tries to add locale information to one of these directories, then the install will fail during the link step.You should probably `chown` them:    /usr/local/share/man    /usr/local/share/man/man1    /usr/local/share/man/man3    /usr/local/share/man/man5    /usr/local/share/man/man7    /usr/local/share/man/man8It became clear that this is happening because these files and folders are owned by my other user account. I see that they’re associated with the ‘admin’ group, so I just figured that I needed to add my new account to the ‘admin’ group. I did this using the following command:sudo dseditgroup -o edit -a usernametoadd -t user adminStill this command did not resolve my issue. Further investigation showed that my account was created as an Administrator, so I should be in this ‘admin’ group already.I found many articles online that suggested other various things, including adding a ‘brew’ group and changing all the files to be owned by this group. I don’t recommend this, because Homebrew is already using an appropriate group, ‘admin’, as the default. Homebrew updated the package manager to use the ‘admin’ group for all files/folders setup under /usr/local back in 2011.I looked at the group permissions of the files/folders and noticed that the group did not have write permission. I used the following commands, taken from a StackExchange post, which resolved my issue.chmod -R g+w /usr/localchmod -R g+w /Library/Caches/HomebrewUpdate 1This morning I went back to work and found that my Postgres server was not running. I checked the logs and found this error:$ tail -F /usr/local/var/postgres/server.logLOG:  shutting downLOG:  database system is shut downFATAL:  data directory "/usr/local/var/postgres" has group or world accessDETAIL:  Permissions should be u=rwx (0700).FATAL:  data directory "/usr/local/var/postgres" has group or world accessDETAIL:  Permissions should be u=rwx (0700).FATAL:  data directory "/usr/local/var/postgres" has group or world accessDETAIL:  Permissions should be u=rwx (0700).FATAL:  data directory "/usr/local/var/postgres" has group or world accessDETAIL:  Permissions should be u=rwx (0700).This resulted from the permissions change I made. Changing the permissions as advised resolved the issue.$ chmod 700 /usr/local/var/postgres$ ls -la /usr/local/var/total 0drwx-w----   9 johnsmith   admin  306 Jun 20 15:31 .drwxrwxr-x  19 root        admin  646 Jun  2 11:15 ..drwxrwxr-x   3 johnsmith   admin  102 Oct  8  2013 dbdrwxrwxr-x   4 redconfetti admin  136 Jun 20 15:31 logdrwxrwxr-x   6 johnsmith   admin  204 Jun 20 15:47 mongodbdrwxrwxr-x   8 johnsmith   staff  272 Oct  9  2013 mysqldrwx------  21 johnsmith   admin  714 Jun 27 17:45 postgresdrwxrwxr-x   2 johnsmith   admin   68 Oct  8  2013 run-rw-rw-r--   1 johnsmith   admin    0 Feb 25 16:45 stdoutUpdate 2It appears that these instructions also caused issues with the permissions of the plist files, which store the configuration of the services launched by launchd. The plist files for Memcached and Redis are symlinked in /Users/myuser/Library/LaunchAgents/ to their location to files like /usr/local/opt/service-name/homebrew.mxcl.service-name.plist. If these have the wrong permissions, launchd will not use those configurations to launch the service.lunchy start redislaunchctl: Dubious permissions on file (skipping): /Users/johnsmith/Library/LaunchAgents/homebrew.mxcl.redis.plistnothing found to loadstarted homebrew.mxcl.redisEven though it said that Redis was started, it was not actually started. Here is the command I ran to resolve this:$ sudo chmod 644 /Users/johnsmith/Library/LaunchAgents/homebrew.mxcl.memcached.plist$ sudo chmod 644 /Users/johnsmith/Library/LaunchAgents/homebrew.mxcl.redis.plistI’m starting to think that there isn’t an ideal solution to this issue. Now my plist files cannot be updated by Homebrew."
    } ,
  
    {
      "title"    : "InstructureCon Hack Day",
      "category" : "",
      "tags"     : "canvas, instructure, lti-integration",
      "url"      : "/2014/06/instructurecon-hack-day/",
      "date"     : "2014-06-17 19:40:05 -0700",
      "content"  : "The opinions or statements expressed herein should not be taken as a position of or endorsement by the University of California, Berkeley.I’m currently at InstructureCon attending the “Hack Day” event, which is simply an event where any developers wishing to integrate their systems with Canvas can ask questions, talk to Canvas developers, etc.Here are some things I’ve clarified with their developers thus far, thanks to Eric Berry and Brian Palmer (codekitchen.LTI Template BuilderEric Berry (cavenb) is part of the Developer Support team at Instructure, which is a group that develops guides and tools to help developers integrate their systems with Canvas. He informed me of the LTI Template Builder, which provides a command you can use to generate a Ruby on Rails engine that provides a template for the LTI application type of your choice.Canvas PluginsIn the Coding Guidelines documentation for Canvas-LMS, the possibility of developing a plugin for Canvas is mentioned. The documentation mentions “Plugins can be registered at runtime but only appear in the interface for enabled root accounts”. I had assumed this meant that plugins could be enabled for a primary account (our account), but this was a wrong assumption. This only means that Site Admins for a Canvas instance, such as Canvas employees that are the root Administrators for the Cloud hosted Canvas service, are able to manage / activate these plugins. For Canvas to introduce such a plugin to their cloud hosted service, the plugin would need to provide functionality that benefits all institutions, without conflicts.For instance, the Adobe Connect plugin for web conferencing was developed by OCAD University. Any proposed plugins that are developed would need to meet similar criteria of use across institutions.Custom Javascript and CSS Application LogicWith the cloud hosted Canvas service, the custom Javascript and CSS files specified under your account settings are applied to the pages ONLY when a hostname associated with your account is in use. For instance, UC Berkeley uses http://bcourses.berkeley.edu/ with the Canvas Cloud hosted service.When using a local Canvas instance, you’ll likely use http://localhost:3000/, and thus the Javascript and CSS from an account may be applied to other accounts that are not configured with a custom Javascript and CSS configuration.Canvas Refresh IntervalCanvas refreshes the configuration/data for their Beta and Test systems on a specific schedule. I got some details on what this schedule is:  Beta - Refresh every Sunday afternoon  Test - Refresh every 3 weeks on Sunday afternoonCustom Javascript and CSS APIEvery time the Beta and Test Canvas instances are updated, we have to manually update the Javascript and CSS configuration for our account so that they point to the Development and QA instances of our LTI application server. Luckily I was just informed that an API is coming soon that will make it possible to update these URLs.Also a new option will soon be supported to store the Javascript and CSS code within Canvas, instead of pointing to an external URL that may go offline.Using RBEnv or RVM with CanvasI noted to Brian Palmer that when I specify a .ruby-version or .ruby-gemset file with my local Canvas instance, the files show up expecting to be staged in the Git repository. I noted that these files aren’t configured in the .gitignore file in the Canvas-LMS repository.He informed me that this intentional. Canvas developers are expected to configure these files as ignored globally for Git."
    } ,
  
    {
      "title"    : "Strong Parameters with Spree Extensions",
      "category" : "",
      "tags"     : "Spree",
      "url"      : "/2014/04/strong-parameters-with-spree-extensions/",
      "date"     : "2014-04-20 01:05:29 -0700",
      "content"  : "I’m currently working on an extension for Spree, an e-commerce solution for Ruby on Rails applications. The developer documentation for Spree is very helpful, letting developers know that they should use certain Ruby meta-programming methods to extend the functionality of the Spree system. The extension I’m working on was setup under a version of Spree that used Rails 3.Now that Spree v2.2.1 uses Rails 4.0.4, I’m having to refactor some parts of this extension to adapt to new practices.From Accessible Attributes to Strong ParametersUnder Rails 3, you have to use #attr_accessible to ensure that attributes of a model can be updated via methods such as #update_attributes. This was implemented to protect models from mass assignment vulnerability. In Rails 4, this functionality re-implemented as a convention at the controller level, in a feature known as Strong Parameters. This Rails 4 Quick Look: Strong Parameters article explains this clearly.Rails 3 DecoratorsUnder Rails 3, a Spree extension could introduce new columns to Spree models via a migration, and then simply introduce a decorator like this one to make the new attributes available for mass assignment updates.Spree::Order.class_eval do  attr_accessible :my_extensions_attribute, :my_extensions_attribute2endBut now with Rails 4, I have to create a decorator for Spree::Api::OrdersController instead. I imagined that this decorator will have to somehow apply a call to the #permit method on the ‘params’, allowing my extension attributes to be updated as well.After some searching online I realized that the best solution to this problem is to specify an alias_method_chain inside my decorator. We don’t have control over the Spree code, and there is no option for using ‘super’ because inheritance isn’t involved here. So this is definitely a situation where we should use an alias method chain.Spree Controller Helpers for Strong ParametersI just noticed however that the Spree::Api::OrdersController#order_params method has a more complex method for permitting the attributes than I expected. In this case the order attributes are provided by #permitted_order_attributes, which makes a ‘super’ call that refers to the parent controller Spree::Api::BaseController. The BaseController doesn’t have a #permitted_order_attributes method defined, however it does include Spree::Core::ControllerHelpers::StrongParameters. which defines #permitted_order_attributes. If you follow the dependencies further, you’ll see that all these methods in Spree::Core::ControllerHelpers::StrongParameters rely on Spree:PermittedAttributes.So all that is necessary to define a new Spree::Order attribute is to define a Spree::PermittedAttributes decorator like so:# lib/spree/permitted_attributes_decorator.rbSpree::PermittedAttributes.class_eval do  @@checkout_attributes.push(:my_extensions_attribute, :my_extensions_attribute2)endI’ll have to test this out, but it seems like the plausible approach. I hope this helps any other developers.UpdateI just went back to a StackOverflow article on this subject that I had seen before - Rails 4 - strong parameters concept involvement in spree-2.1. It turns out that they referenced a simpler approach by simply placing the following into an initializer.Spree::PermittedAttributes.user_attributes.push :first_name, :last_nameI don’t think this is the best approach however, because an initializer has to be installed into the application via a generator. A generated initializer cannot be maintained either."
    } ,
  
    {
      "title"    : "Ruby Class Name",
      "category" : "",
      "tags"     : "",
      "url"      : "/2014/03/ruby-class-name/",
      "date"     : "2014-03-20 21:32:23 -0700",
      "content"  : "I  noticed that in a module used on the CalCentral project that logger expressions used in a module referenced ‘self.name’ many times. I checked ApiDock.com for a reference to this class in the Ruby or Rails documentation, but I couldn’t find one. The module itself didn’t define a #name method, so I was perplexed.The module I was inspecting is meant to be used to extend other classes, meaning that it establishes the methods as class methods. It turns out that the ‘Class’ class is officially documented as having a #name method that returns a string version of the class name. This is a valid way of logging which class the log message originates from."
    } ,
  
    {
      "title"    : "Using &#39;for in&#39; in Javascript",
      "category" : "",
      "tags"     : "javascript, JsLint",
      "url"      : "/2014/03/using-for-in-in-javascript/",
      "date"     : "2014-03-18 02:04:24 -0700",
      "content"  : "Today our lead front-end developer pointed out to me that when using a ‘for in’ loop in Javascript that you want to make sure to use hasOwnProperty() on the element to make sure it belongs to the object, and not properties that were inherited through the prototype chain.More information is available on this page describing common Javascript code mistakes caught by JSLint."
    } ,
  
    {
      "title"    : "How to &#39;head&#39; a text file in Ruby",
      "category" : "",
      "tags"     : "ruby, head",
      "url"      : "/2014/01/how-to-head-a-text-file-in-ruby/",
      "date"     : "2014-01-30 22:51:32 -0800",
      "content"  : "I wanted to just view the first 20 lines of a 10,000 line CSV file returned by an API in a Ruby on Rails project I’m working on. Here is the chain of Ruby commands I came up with to effectively ‘head’ the CSV document returned.&gt;&gt; csv = "first line\nsecond line\nthird line\nfourth line\nfifth line\nsixth line\n"&gt;&gt; csv.split("\n")[0..3].join("\n")=&gt; "first line\nsecond line\nthird line\nfourth line""
    } ,
  
    {
      "title"    : "Objective C Notes",
      "category" : "",
      "tags"     : "",
      "url"      : "/2014/01/objective-c-notes/",
      "date"     : "2014-01-09 07:46:44 -0800",
      "content"  : "I’m exploring Objective C right now. There are some things that I notice and am curious about, so I’m going to note what I find here.ArgC and ArgVMany tutorials will likely start you off using XCode to create a command line application. The ‘main’ function with Objective C is defined like so:int main(int argc, const char * argv[]){    @autoreleasepool {        // insert code here...        NSLog(@"Hello, World!");    }    return 0;}I wondered what the two parameters for the main function represent. It turns out that “argc” means “argument count”. It signifies how many arguments are being passed into the command line tool you are creating. “argv” means “argument values”, and is a pointer to an array of characters, otherwise representing the string of arguments.Objective-c main routine, what is: int argc, const char * argv[]Objective C File ExtensionI wondered why Objective C files end with ‘.m’ instead of ‘.oc’ or something like that. The inventor of Objective C, Brad Cox, has indicated it’s because .o and .c were already taken by the C language. It is said that the ‘m’ stands for ‘messages’, and that some call them ‘method files’.See Why do Objective C files use the .m extension?"
    } ,
  
    {
      "title"    : "Recommended Sublime 3 Packages",
      "category" : "",
      "tags"     : "sublime text, lint",
      "url"      : "/2013/12/recommended-sublime-3-packages/",
      "date"     : "2013-12-17 17:39:00 -0800",
      "content"  : "If you haven’t already switched to Vim, and you’re hacking everything out from the command line, you might want to check out Sublime Text 3. Sublime Text is supported for Mac, Ubuntu, and Windows.Once you’ve obtained a copy of Sublime Text 3, make sure you install Package Control by wbond. Using the SHIFT + COMMAND + P keystroke provides you with a whole menu of options to choose from. Here are packages that are highly recommended for use with Sublime Text 3.  DocBlockr  EditorConfig  GitGutter - Indicates lines that have been added, modified, or removed in the files you are viewing.  LiveReload  Markdown Preview  SideBarEnhancements  Sass  SublimeLinter - Helps to detect mistakes in your code. Many packages to support various languages.          SublimeLinter-csslint      SublimeLinter-html-tidy      SublimeLinter-jshint      SublimeLinter-json      SublimeLinter-ruby        SublimeCodeIntel - Function call tooltips, code complete, and jump to file and line of certain symbols  TrailingSpaces - Highlights unnecessary whitespace in your documents, and removes the whitespace when saving the document."
    } ,
  
    {
      "title"    : "Setting up PostgreSQL for Rails",
      "category" : "",
      "tags"     : "postgresql",
      "url"      : "/2013/11/setting-up-postgresql-for-rails/",
      "date"     : "2013-11-21 20:14:34 -0800",
      "content"  : "I’ve always used either SQLite (the default) with new Rails projects, or I’ve used MySQL because I’ve been using it ever since 2002 when I started doing web development with PHP. Recently however I was challenged with deploying an application to Heroku as part of a code challenge I’m taking part in. Unfortunately, Heroku doesn’t support SQLite, and recommends PostgreSQL. Rather than waste time trying to create a MySQL app and running into problems, I’m going to go the easy route and use PostgreSQL.The first step I had to take was installing PostgreSQL using Homebrew. I figured it would default to using ‘root’ as the super user locally without a password, just like MySQL. Postgres is actually setup owned by your local user account though. This makes sense given that usually a daemon is setup to run as a certain user. Unix admins should create a ‘postgres’ user, login to that account, then initialize and run the database as that user.I find that it’s useful to control when the Postgres server is running using the Lunchy gem. It makes it easy to start and stop daemons such as this that are installed via Homebrew.$ gem install lunchy$ lunchy start postgres$ lunchy stop postgresCreating a User for your Rails AppYou likely don’t want to configure your Rails app to use your username in development. It’s best to use a username that is related to your application. The following command will let you add a super user/role to Postgres with the ability to create databases, create other user/roles, and login.$ createuser --superuser --createrole --createdb --login myappuserIf you need to delete a user/role, you can use ‘dropuser’.$ dropuser myappuserNow that a super user is setup, you can run the rake commands to create the database and run migrations.$ bundle exec rake db:create:all$ bundle exec rake db:migrate$ bundle exec rake db:migrate RAILS_ENV=testCommand Line ClientThe command line client is ‘psql’. It defaults to using your actual Linux/Mac username, which is fine because Postgres is running under your username locally anyway. It requires a database name also, so you’ll have to specify a database name to even get the prompt. You can use ‘postgres’ as the database name. Otherwise use your applications database name if you want.$ psql postgrespsql (9.2.4)Type "help" for help.postgres=#Also ‘quit’ or ‘exit’ don’t get you out of the client. You have to use ‘\q’. You can use the ‘help’ command as prompted to see other commands.If you want to view a list of users directly from the ‘postgres’ database, you can use the following query.SELECT * FROM pg_roles;To view a list of databases, you can directly use the psql command from the command line.$ psql -l"
    } ,
  
    {
      "title"    : "ComputerName: not set",
      "category" : "",
      "tags"     : "oh-my-zsh",
      "url"      : "/2013/10/computername-not-set/",
      "date"     : "2013-10-02 23:20:22 -0700",
      "content"  : "I recently installed Oh-my-Zsh on a new Macbook Pro running Mountain Lion. When I opened up my terminal, I received the message “ComputerName: not set”.I tried to use the ‘sudo hostname’ command, but this didn’t seem to work. I ended up opening System Preferences -&gt; Sharing, and then set my Computer Name.I found an article that also suggested using the following:sudo scutil --set ComputerName "newname"sudo scutil --set LocalHostName "newname"sudo scutil --set HostName "newname""
    } ,
  
    {
      "title"    : "Bundler Definitions",
      "category" : "",
      "tags"     : "bundler",
      "url"      : "/2013/09/bundler-definitions/",
      "date"     : "2013-09-01 20:16:38 -0700",
      "content"  : "I’m currently starting work on a Ruby gem, ‘annotate_gemfile’, that will grab the title, description, homepage URL, or source URL for every defined gem, and then add them as an annotation / commented for each gem definition in the Gemfile.As part of this exploration, I’m digging into the source for Bundler to try an understand how it imports details on the gems from the Gemfile, how it queries for details on each from RubyGems. Here are some discoveries I’m making.Bundler.definitionThis appears to return an initialized object with the Gemfile definitions loaded. Bundler.definition returns an instance of Bundler::Definition for the default Gemfile and default lock file (Gemfile.lock). Readable attributes of this “definition” are platforms, sources, ruby_version, and dependencies.&gt;&gt; Bundler.definition.platforms=&gt; ["ruby"]&gt;&gt; Bundler.definition.sources=&gt; [source at ., rubygems repository https://rubygems.org/]&gt;&gt; Bundler.definition.ruby_version=&gt; nil&gt;&gt; Bundler.definition.dependencies=&gt; [&lt;Bundler::Dependency type=:runtime name="annotate_gem" requirements="&gt;= 0"&gt;, &lt;Bundler::Dependency type=:development name="bundler" requirements="~&gt; 1.3"&gt;, &lt;Bundler::Dependency type=:development name="rake" requirements="&gt;= 0"&gt;, &lt;Bundler::Dependency type=:development name="rspec" requirements="~&gt; 2.14.1"&gt;]PlatformsBundler allows the specification for gems to be installed only on certain Ruby platforms. Options include different minor versions of Ruby (1.8, 1.9, 2.0) as well as differences between types of Ruby (MRI Ruby, Rubinius, jRuby, various Windows Ruby versions).SourcesThere appear to be three source types supported by Bundler.RubyGemsA Bundler::Source::RubyGems object represents a RubyGems server. The default one is RubyGems.org. If you check your Gemfile, you’ll see a ‘source’ directive that points to the URL for the gem server with http://rubygems.org/ as the URL.1.9.3p448 :044 &gt; Bundler.definition.sources[1].class =&gt; Bundler::Source::Rubygems1.9.3p448 :038 &gt; Bundler.definition.sources[1] =&gt; rubygems repository https://rubygems.org/1.9.3p448 :039 &gt; Bundler.definition.sources[1].name =&gt; "rubygems repository https://rubygems.org/"1.9.3p448 :040 &gt; Bundler.definition.sources[1].options =&gt; {"remotes"=&gt;["https://rubygems.org/"]}1.9.3p448 :041 &gt; Bundler.definition.sources[1].remotes =&gt; [#&lt;URI::HTTPS:0x007fb59138ea20 URL:https://rubygems.org/&gt;]1.9.3p448 :042 &gt; Bundler.definition.sources[1].caches =&gt; [#&lt;Pathname:/Users/redconfetti/Sites/annotate_gemfile/vendor/cache&gt;, "/Users/redconfetti/.rvm/gems/ruby-1.9.3-p448@annotate_gemfile/cache", "/Users/redconfetti/.rvm/gems/ruby-1.9.3-p448@global/cache"]1.9.3p448 :043 &gt; Bundler.definition.sources[1].dependency_names =&gt; ["rake", "annotate_gem", "bundler", "diff-lcs", "rspec-core", "rspec-expectations", "rspec-mocks", "rspec"]The ‘dependency_names’ are the names of gems which rely on this RubyGem source server.PathA Bundler::Source::Path object represents a local gem path. This source is from the local path of the Gemfile I’m developing. The ‘name’ appears to be the name of the dependency that relies on the “path” source.1.9.3p448 :045 &gt; Bundler.definition.sources[0].class =&gt; Bundler::Source::Path1.9.3p448 :030 &gt; Bundler.definition.sources[0].name =&gt; "annotate_gemfile"1.9.3p448 :031 &gt; Bundler.definition.sources[0].path =&gt; #&lt;Pathname:.&gt;1.9.3p448 :032 &gt; Bundler.definition.sources[0].options =&gt; {"path"=&gt;"."}1.9.3p448 :033 &gt; Bundler.definition.sources[0] =&gt; source at .GitA Bundler::Source::Git object represents a Git repository that provides the source code for a defined gem dependency.2.0.0p247 :018 &gt; Bundler.definition.sources[0].class =&gt; Bundler::Source::Git2.0.0p247 :019 &gt; Bundler.definition.sources[0].name =&gt; "bootstrap-sass"2.0.0p247 :020 &gt; Bundler.definition.sources[0].uri =&gt; "https://github.com/thomas-mcdonald/bootstrap-sass.git"2.0.0p247 :021 &gt; Bundler.definition.sources[0].ref =&gt; "master"2.0.0p247 :022 &gt; Bundler.definition.sources[0].branch =&gt; nil2.0.0p247 :023 &gt; Bundler.definition.sources[0].options =&gt; {"revision"=&gt;"16da2ffb1fb98672f498b482c318db0cfb20a054", "uri"=&gt;"https://github.com/thomas-mcdonald/bootstrap-sass.git"}2.0.0p247 :024 &gt; Bundler.definition.sources[0].submodules =&gt; nil2.0.0p247 :025 &gt; Bundler.definition.sources[0].version =&gt; nilAs you can see, the ‘name’ attribute defines the gem that is dependent on this specific Git repository.Ruby VersionYour Gemfile may include a specific Ruby version, which is expressed as a Bundler::RubyVersion object in the definition. Heroku requires the Ruby version for projects you are deploying to their platform.# Gemfileruby '2.0.0'# Console2.0.0p247 :001 &gt; Bundler.definition.ruby_version =&gt; #&lt;Bundler::RubyVersion:0x007fe8c890a908 @version="2.0.0", @engine="ruby", @input_engine=nil, @engine_version="2.0.0"&gt;DependenciesThis is the meat of the Gemfile, the dependencies which are represented as Bundler::Dependency objects.1.9.3p448 :003 &gt; Bundler.definition.dependencies[0] =&gt; &lt;Bundler::Dependency type=:runtime name="annotate_gem" requirements="&gt;= 0"&gt;1.9.3p448 :004 &gt; Bundler.definition.dependencies[1] =&gt; &lt;Bundler::Dependency type=:development name="bundler" requirements="~&gt; 1.3"&gt;1.9.3p448 :005 &gt; Bundler.definition.dependencies[2] =&gt; &lt;Bundler::Dependency type=:development name="rake" requirements="&gt;= 0"&gt;1.9.3p448 :006 &gt; Bundler.definition.dependencies[3] =&gt; &lt;Bundler::Dependency type=:development name="rspec" requirements="~&gt; 2.14.1"&gt;It appears that dependencies do not specify a source if they are provided from a Ruby Gems server. Only if they are sourced from a Path or Git repository.# Dependencies from my gem in development1.9.3p448 :021 &gt; Bundler.definition.dependencies[0] =&gt; &lt;Bundler::Dependency type=:runtime name="annotate_gem" requirements="&gt;= 0"&gt;1.9.3p448 :022 &gt; Bundler.definition.dependencies[0].source =&gt; source at .1.9.3p448 :023 &gt; Bundler.definition.dependencies[1] =&gt; &lt;Bundler::Dependency type=:development name="bundler" requirements="~&gt; 1.3"&gt;1.9.3p448 :024 &gt; Bundler.definition.dependencies[1].source =&gt; nil# Bootstrap-Sass dependency from another project2.0.0p247 :022 &gt; Bundler.definition.dependencies[10].class =&gt; Bundler::Dependency2.0.0p247 :023 &gt; Bundler.definition.dependencies[10] =&gt; &lt;Bundler::Dependency type=:runtime name="bootstrap-sass" requirements="&gt;= 0"&gt;2.0.0p247 :024 &gt; Bundler.definition.dependencies[10].groups =&gt; [:default]2.0.0p247 :025 &gt; Bundler.definition.dependencies[10].source.class =&gt; Bundler::Source::Git"
    } ,
  
    {
      "title"    : "Yard Documentation",
      "category" : "",
      "tags"     : "Yard",
      "url"      : "/2013/08/yard-documentation/",
      "date"     : "2013-08-31 21:50:47 -0700",
      "content"  : "Here are my own notes for using Yard to provide the Ruby API documentation and other notes for your application.InstallationFirst add the Yard gem to your Gemfile, preferably in the development group if applicable.group :development do  # Yard  # YARD is a Ruby Documentation tool  # https://github.com/lsegal/yard  gem "yard", "~&gt; 0.8.7"endRunningYou can use Yard to generate documentation by just running ‘Yard’ from the root of your application.$ yardFiles:          36Modules:        10 (   10 undocumented)Classes:        26 (   21 undocumented)Constants:       0 (    0 undocumented)Methods:       140 (   54 undocumented) 51.70% documentedYou can also run a server that updates dynamically as you add documentation.$ yard server&gt;&gt; YARD 0.8.7 documentation server at http://0.0.0.0:8808[2013-08-31 14:28:15] INFO  WEBrick 1.3.1[2013-08-31 14:28:15] INFO  ruby 2.0.0 (2013-06-27) [x86_64-darwin12.4.1][2013-08-31 14:28:15] INFO  WEBrick::HTTPServer#start: pid=41901 port=8808ConfigurationYou can run the ‘yardoc’ command with options that cause it to parse certain directories for documentation. With Rails applications it appears that this isn’t necessary. Rather than add options or flags after the yard command each time, you can configure a .yardopts file with the arguments you would normally use from the command line.Yard will make use of your README.md file as the index page for the documentation, but to include other files you could configure a .yardopts file like so:-README.mdCHANGELOG.mdThis makes it possible for the CHANGELOG to show up under the ‘File List’ section.I prefer to have my own hierarchy of markdown files in /doc, with generated documentation in /doc/app. This way I can completed delete the doc/app folder without affecting my other markup files in the root of /doc.--output-dir doc/app-doc/DevelopmentTasks.mdCHANGELOG.mdREADME.mdHere is a good example of a more elaborately configured .yardopts file. You can also run ‘yardoc –help’ to discover other options to add to the file."
    } ,
  
    {
      "title"    : "Exploring Bundler Commands",
      "category" : "",
      "tags"     : "rubygems, bundler, Thor",
      "url"      : "/2013/08/exploring-bundler-commands/",
      "date"     : "2013-08-30 01:11:49 -0700",
      "content"  : "You may be used to using ‘bundle install’ or ‘bundle exec’ often, but here are some commands you might have forgotten about or never heard of.Bundle InitYou don’t have to create your own Gemfile manually for new Ruby based projects. Bundle Init creates a new one for you.$ bundle initWriting new Gemfile to /Users/myuser/Projects/hey_guys/Gemfile$ ls -la Gemfile-rw-r--r--  1 myuser  mygroup  64 Aug 29 17:40 GemfileBundle ConsoleFor purer Ruby projects, this is useful. Start an IRB session in the context of the current bundle.$ bundle consoleResolving dependencies...1.9.3p448 :001 &gt; require 'rake' =&gt; true1.9.3p448 :002 &gt; Rake =&gt; RakeBundle OpenAfter you have configured your default text editor, which could be Vim, Emacs, Textmate, or Sublime, you can use ‘bundle open’ to quickly open your editor with the root directory for the gems source code loaded.$ bundle open rakeResolving dependencies...Bundle GemBundler can even help you get started with the development of a new gem.$ bundle gem smash_pumpkin      create  smash_pumpkin/Gemfile      create  smash_pumpkin/Rakefile      create  smash_pumpkin/LICENSE.txt      create  smash_pumpkin/README.md      create  smash_pumpkin/.gitignore      create  smash_pumpkin/smash_pumpkin.gemspec      create  smash_pumpkin/lib/smash_pumpkin.rb      create  smash_pumpkin/lib/smash_pumpkin/version.rbInitializating git repo in /Users/redconfetti/Sites/annotate_gemfile/smash_pumpkinBundle InjectBundle Inject is an undocumented feature added on November 29, 2012, in version 1.3.0.pre, implemented by Engine Yard likely for their own automation. This command allows you to add gems to your Gemfile from the command line. Great jorb Engine Yard!$ bundle injectbundle inject requires at least 2 arguments: "bundle inject GEM VERSION ...".Bundler defines this command, as well as the others, in Bundler::CLI. This file defines the command line interface for bundle commands (bundle install, bundle update, bundle exec, bundle gem,etc) using Thor. Thor command support standard command line style options and flags.Here is an example of the default intended use of the command.$ bundle inject poltergeist 1.3.0Fetching gem metadata from https://rubygems.org/......Fetching gem metadata from https://rubygems.org/..Resolving dependencies...Added to Gemfile:  poltergeist (= 1.3.0)The resulting definition added to my Gemfile was very descriptive.# Added at 2013-08-29 17:54:59 -0700 by my_user_name:gem 'poltergeist', '= 1.3.0'I explored the code and it doesn’t appear that there are options to include special arguments such as the branch or git repository. It does however support multiple gem argument sets like so:$ bundle inject poltergeist 1.3.0 pry 0.9.12.2Fetching gem metadata from https://rubygems.org/......Fetching gem metadata from https://rubygems.org/..Resolving dependencies...Added to Gemfile:  poltergeist (= 1.3.0)  pry (= 0.9.12.2)The result being:# Added at 2013-08-29 18:09:41 -0700 by redconfetti:gem 'poltergeist', '= 1.3.0'gem 'pry', '= 0.9.12.2'"
    } ,
  
    {
      "title"    : "Paperclip URL and Path",
      "category" : "",
      "tags"     : "paperclip, s3",
      "url"      : "/2013/08/paperclip-url-and-path/",
      "date"     : "2013-08-28 20:04:13 -0700",
      "content"  : "I’m trying to configure my application so that it stores files in S3 by default when my application is running in the Production Rails environment, with local file storage and a customized file path for development and test environments. Here is my configuration.Paperclip DefaultsYou can view the default options by opening the Rails console and inspecting Paperclip::Attachment.default_options. I’m using Paperclip 3.5.1.pry(main)&gt; Paperclip::Attachment.default_options=&gt; {:convert_options=&gt;{}, :default_style=&gt;:original, :default_url=&gt;"/:attachment/:style/missing.png", :escape_url=&gt;true, :restricted_characters=&gt;/[&amp;amp;$+,\/:;=?@&lt;&gt;\[\]\{\}\|\\\^~%# ]/, :filename_cleaner=&gt;nil, :hash_data=&gt;":class/:attachment/:id/:style/:updated_at", :hash_digest=&gt;"SHA1", :interpolator=&gt;Paperclip::Interpolations, :only_process=&gt;[], :path=&gt;":rails_root/public:url", :preserve_files=&gt;false, :processors=&gt;[:thumbnail], :source_file_options=&gt;{}, :storage=&gt;:filesystem, :styles=&gt;{}, :url=&gt;"/system/:class/:attachment/:id_partition/:style/:filename", :url_generator=&gt;Paperclip::UrlGenerator, :use_default_time_zone=&gt;true, :use_timestamp=&gt;true, :whiny=&gt;true, :check_validity_before_processing=&gt;true}Overriding DefaultsYou can override the defaults in config/initializers/paperclip.rb using the following example which configures Paperclip to use S3 in production, with the ImageMagick path we use on the production server (running Ubuntu instead of MacOSX):if Rails.env.production?  # See http://rubydoc.info/gems/paperclip/Paperclip/Storage/S3  Paperclip.options[:image_magick_path] = "/usr/bin/"  Paperclip::Attachment.default_options.merge!({    :storage =&gt; :s3,    :s3_credentials =&gt; "#{Rails.root}/config/s3.yml",    :bucket =&gt; YAML.load_file("#{Rails.root}/config/s3.yml")[Rails.env]['bucket'],    :url =&gt; ":s3_domain_url"  })endHere is my configuration for the local dev/test environments:# Config for Non-production Environmentsunless Rails.env.production?  Paperclip::Attachment.default_options.merge!({    :url =&gt; "/system/:rails_env/:class/:attachment/:id_partition/:style/:filename",    :path =&gt; ":rails_root/public:url"  })endRemember that the :path and :url have to align so that the file path and URL path match and the file is served by your web server. It’s best to modify the path only if the local filesystem prefix is different than the ‘public’ folder in the root of your Rails application directory."
    } ,
  
    {
      "title"    : "Open Source Ideas",
      "category" : "",
      "tags"     : "",
      "url"      : "/2013/08/open-source-ideas/",
      "date"     : "2013-08-25 22:47:39 -0700",
      "content"  : "I’ve become aware of how important it is to provide a portfolio of things to share with prospective employers. Having a Github profile that shows off all the Gists and public repositories you’ve contributed to serves as a perfect portfolio piece.Most of the work I’ve done has been on private systems however, and I’ve discarded the code, because I don’t own it and don’t want legal trouble. So what can I do that is practical, helpful, and/or fun!?Here is my list of pet project ideas that I plan on doing in the future.  Pop Culture Faker - There is a tool that outputs fake names, business names, phone numbers, addresses, etc. called Faker. Often I find myself using names like ‘Bob Barker’, or ‘Joffrey Baratheon’ in my tests. It would be cool to make an alternative version of Faker (or FFaker) that pulls from common names of celebrities, fictional characters, etc.  Gemfile Annotator - I remember hearing about a gem that would annotate your Rails models. I want to make one that adds the name, description, and Github project URL for each gem inside of your Gemfile, like so:# Figaro# Simple Rails app configuration# https://github.com/laserlemon/figarogem "figaro""
    } ,
  
    {
      "title"    : "Precompiling Rails 4 Assets When Deploying to Heroku",
      "category" : "",
      "tags"     : "heroku, rails4, asset pipeline",
      "url"      : "/2013/08/precompiling-rails4-assets-when-deploying-to-heroku/",
      "date"     : "2013-08-25 00:13:01 -0700",
      "content"  : "I’m working on a Rails 4.0.0 application, using Ruby 2.0.0 for a code challenge I’m working on. Part of this challenge is to deploy my application to Heroku. I haven’t done this before, as I’m accustomed to deploying to a VPS with Capistrano.Upon my first deploy I discovered that my assets weren’t compiling. It wasn’t even mentioned in the output while deploying. I reviewed the Heroku article on the Rails asset pipeline, but this didn’t offer me any details to resolve my issue.I discovered that I should add the rails_12factor gem to my production gem group in the Gemfile. Here’s a pretty annotated version that I used.# Productiongroup :production do  # Rails 12factor  # Makes running your Rails app easier. Based on the ideas behind 12factor.net  # Needed for support of Asset Pipeline with Heroku  # https://github.com/heroku/rails_12factor  gem 'rails_12factor'endAfter doing this I ran the rake task to precompile assets, committed the changes to my repository, then deployed. This resolved the issue, at least in the short term. Having to precompile assets before each deploy isn’t very efficient though, so I ran the task to clobber all the assets. If you don’t clear all the precompiled assets using ‘clobber’, Heroku will not attempt to precompile the assets.rake assets:precompilerake assets:clobberI tried many other asset pipeline settings in config/application.rb and config/environments/production.rb that were recommended in various StackOverflow threads, but nothing was working. I don’t recall when, but at some point I finally started to see that Heroku was trying to precompile assets when I deployed.       Your bundle is complete! It was installed into ./vendor/bundle       Cleaning up the bundler cache.-----&gt; Writing config/database.yml to read from DATABASE_URL       Error detecting the assets:precompile task-----&gt; Discovering process typesI ran the command to detect the rake tasks on the remote server, and ‘assets:precompile’ was showing up. I didn’t understand why it’s saying that it can’t detect the task when it’s right there on the remote server.$ heroku run rake -TRunning `rake -T` attached to terminal... up, run.1071rake about                  # List versions of all Rails frameworks and the environmentrake assets:clean           # Remove old compiled assetsrake assets:clobber         # Remove compiled assetsrake assets:environment     # Load asset compile environmentrake assets:precompile      # Compile all the assets named in config.assets.precompileAfter further investigating I found this post. It turns out that if your applications configuration variables need to be present during the compilation of the “slug” being compiled, an add-on called user-env-compile might help your application during deployment.I’m using Figaro to load application configuration values, including the asset hostname.# config/application.rbconfig.action_controller.asset_host = 'http://' + Figaro.env.hostnameThis must be the reason it was failing to attempt the precompiling of assets during deployment.$ heroku labs:enable user-env-compile -a myappI installed user-env-compile and now it’s working just fine."
    } ,
  
    {
      "title"    : "Resetting Paths for Homebrew",
      "category" : "",
      "tags"     : "homebrew, command line, cmdline",
      "url"      : "/2013/08/resetting-paths-for-homebrew/",
      "date"     : "2013-08-22 19:31:38 -0700",
      "content"  : "I recently needed to install a program on my Mac using Homebrew. I was instructed to run ‘brew update’, and then the ‘brew doctor’ command which resulted in this message:Warning: /usr/bin occurs before /usr/local/binThis means that system-provided programs will be used instead of thoseprovided by Homebrew. The following tools exist at both paths:    gcov-4.2    git    git-cvsserver    git-receive-pack    git-shell    git-upload-archive    git-upload-packConsider amending your PATH so that /usr/local/binoccurs before /usr/bin in your PATH.I am using Zsh instead of Bash, and checked my .bashrc, .bash_profile, .zshenv, and .zshrc files. None of those expressed the path with the /usr/bin path expressed before the /usr/local/bin.I also noticed that when using ‘echo $PATH’ the paths were being duplicated. I saw that in my .zshrc I was setting the path in the correct order, but something else was setting the paths in the incorrect order…and taking precendence.It turns out that there is a file - /etc/paths - which controls the default paths for all users on the system. I used ‘sudo nano /etc/paths’ to edit my configuration to reflect the following:/usr/local/bin/usr/bin/bin/usr/sbin/sbinI opened a new terminal and ran ‘brew doctor’ again.$ brew doctorYour system is ready to brew."
    } ,
  
    {
      "title"    : "Time Management",
      "category" : "",
      "tags"     : "time management",
      "url"      : "/2013/07/time-management/",
      "date"     : "2013-07-30 05:25:04 -0700",
      "content"  : "I’ve recently became aware of a time management technique known as the Pomodoro Technique. You time a period of work for 25 minutes, then take a short break, then do another period again. This helps you gauge the amount of work you’re getting done in a period of time, and is supposed to help with mental agility.My friend uses Vitamin R as an app on his Mac to remind him of how much time he has left during a time period."
    } ,
  
    {
      "title"    : "Ruby Strftime",
      "category" : "",
      "tags"     : "dates, times",
      "url"      : "/2013/07/ruby-strftime/",
      "date"     : "2013-07-26 22:16:42 -0700",
      "content"  : "Instead of piecing together Ruby strftime strings to use for various formats each time, I’m making this post to store common variations for me to reference later.I used the legend posted by annaswims on ApiDock.com to piece these together. Thanks Anna.# Pretty AbbreviatedTime.now.strftime("%a %b %d, %Y %l:%M:%S %p %Z") # =&gt; "Fri Jul 26, 2013  3:06:04 PM PDT"# Pretty LongTime.now.strftime("%A %B %d, %Y %l:%M:%S %p %Z") # =&gt; "Friday July 26, 2013  3:06:53 PM PDT"# Short but HumanTime.now.strftime("%-m/%d/%y - %-l:%M:%S %p %Z") # =&gt; "7/26/13 - 3:10:15 PM PDT"# Logger StyleTime.now.strftime("%m/%d/%y - %H:%M:%S %Z") # "07/26/13 - 15:13:53 PDT"# ISO8601 formatTime.now.utc.strftime('%FT%H:%MZ') # =&gt; "2013-07-26T22:15Z"# DateTime format used with ActiveRecordTime.now.utc.strftime('%F %H:%M:%S') # =&gt; "2013-07-26 22:19:09""
    } ,
  
    {
      "title"    : "Uptime Monitoring and Alerts",
      "category" : "",
      "tags"     : "",
      "url"      : "/2013/07/uptime-monitoring-and-alerts/",
      "date"     : "2013-07-26 00:34:25 -0700",
      "content"  : "Just happened to hear about these solutions recently.  Pingdom  PagerDuty"
    } ,
  
    {
      "title"    : "Installing Rails 3.2.13",
      "category" : "",
      "tags"     : "Rails 3",
      "url"      : "/2013/07/installing-rails-3-2-13/",
      "date"     : "2013-07-16 03:00:40 -0700",
      "content"  : "Rails 4 is out now, and installs by default. You might need to install Rails 3 for a project. This is how you do it.gem install --version '3.2.13' rails"
    } ,
  
    {
      "title"    : "POW RVM ZSH",
      "category" : "",
      "tags"     : "rvm, pow, zsh",
      "url"      : "/2013/07/pow-rvm-zsh/",
      "date"     : "2013-07-15 00:07:38 -0700",
      "content"  : "I’m using a Rails 3 app, and my colleague updated the RVM config to use Ruby 2.0.0. I was having issues getting POW to work with the app. I’m using ZSH as my shell also.The following command resolved my issue.rvm env . -- --env &gt; .powenvProps to Linus on StackOverflow for this solution."
    } ,
  
    {
      "title"    : "Devise_For with Skip",
      "category" : "",
      "tags"     : "devise",
      "url"      : "/2013/07/devise_for-with-skip/",
      "date"     : "2013-07-11 22:26:51 -0700",
      "content"  : "I just stumbled upon the options for devise_for which let you auto-generate the routes that are needed for a certain devise resource (user), with certain categories of routes skipped.For example, if I want to define routes for my User, I can define:devise_for :usersThis results in the routes for these three categories:  Sessions - Sign in, Sign out  Passwords - Password reset options  Registrations - Creating new user, updating existing user, or destroying your user accountYou can leave one of these categories out of the route definition by using skip. For instance if you want only the Sign-in and Sign-out options, you could define this in your routes.rb file:devise_for :users, :skip =&gt; [:registrations, :passwords]"
    } ,
  
    {
      "title"    : "Project / Task Management Applications",
      "category" : "",
      "tags"     : "planning, analysis, project management",
      "url"      : "/2013/07/project-task-management-applications/",
      "date"     : "2013-07-07 23:11:31 -0700",
      "content"  : "I’ve worked on various projects that used various task management applications hosted in the cloud (software as a service). I hear about new ones every so often, so I decided to note them here for future reference.  Pivotal Tracker - Anyone trying to adopt the agile / scrum method of development has likely used this.  BaseCampHQ.com - This is the first Rails application. The reason Ruby on Rails exists. Simple and elegant.  Wrike.com - Very flexible. Can be used to multiple people, in different organizations, matching any special hierarchy of tasks.  PlanScope.io  Asana.com"
    } ,
  
    {
      "title"    : "Refinery Extension Not Named After Model",
      "category" : "",
      "tags"     : "refinery-cms",
      "url"      : "/2013/06/refinery-extension-not-named-after-model/",
      "date"     : "2013-06-18 06:01:25 -0700",
      "content"  : "A project I’m working on currently relies on Refinery CMS to administrate the pages. Instead of building our own separate admin area for our own custom models, we’re continuing to use Refinery for our non-page models as well.Refinery and it’s extensions are generated under their own namespace to ensure that they play nice with any system you install Refinery into. It can provide page management inside of an existing Rails app you have, or it can act as the center of the entire website. I’m pretty sure the main concept is that it leaves the view/layout presentation up to you, but provides the page administration back-end for you.If you have special models that you want Refinery to manage as well, you can generate a Refinery extension, which is essentially a Rails engine created under vendor/extensions. Something that I really didn’t like however was how every new model you want to add gets it’s own extension folder. Since the extensions are namespaced, you could add a new extension called ‘book’ and end up with the model under vendor/extensions/books/app/models/refinery/book/book.rb, and defined as Refinery::Books::Book.I found out later though that you can add new resources to existing extensions. Now instead of having a large tree/hierarchy of files displayed in my project file view, it can be compacted under one single folder, with all the interrelated models under the same namespace. I can see that this same paradigm applies to the Refinery-Blog plugin with posts, comments, and categories configured under the same extension.Extension with Independent NameOne of the things that bothered me here is that you cannot generate an extension using a name not associated with a model. For instance, the Refinery-Blog plugin mentioned above is called ‘Refinery-Blog’, but there is no ‘blog’ model. There are just posts, comments, categories, etc. The plugin is configured with the post admin page being the defined URL for the plugin itself, as a ‘post’ is the centerpiece of a ‘blog’.For someone that isn’t familiar with the logic behind the extension code generated, this can be frustrating.I’ve found the following method to accomplish this using the generator however.First, create a folder for your new extension. For this example we’ll call the extension ‘shapes’, with ‘square’ being first resource we plan on adding to the extension. You’ll have to create and populate certain files so that the generator can modify the existing files as it’s designed to do. Do replace ‘shapes’ in these examples with the name of your extension where applicable.  Create folder ‘vendor/extensions/shapes/’  Create folder ‘vendor/extensions/shapes/config’  Create file ‘vendor/extensions/shapes/config/routes.rb’  Create file ‘vendor/extensions/shapes/lib/refinerycms-shapes.rb’Make sure your config/routes.rb file has the following inside it.Refinery::Core::Engine.routes.append do  # engine logic goes hereendAfter this is done, I ran the following command to generate my first resource within the extension I created by hand.rails g refinery:engine square size:integer --extension shapes --namespace shapesIt created the new resource without any errors. Now I can re-creating the resources that were previously created under their own extensions, so that they’re all under my new extension. I expect this will be cleaner, and more appropriate to how they should be added."
    } ,
  
    {
      "title"    : "Splitting a Branch with Git",
      "category" : "",
      "tags"     : "git",
      "url"      : "/2013/06/splitting-a-branch-with-git/",
      "date"     : "2013-06-05 19:18:38 -0700",
      "content"  : "There are times that a task you are working on results in an extremely huge amount of changes. Although you may have been careful, and tested each modification out well, there is always a possibility that something will cause an issue in production. If your branch contains modifications that can be released in separately, without interdependencies, it’s a good idea to split the feature branch into separate releases.First you’ll want to interactively rebase your branch, squash all commits into a single commit, and then amend the remaining commit so that it’s the most recent.git checkout my_feature_branchgit fetchgit rebase -i origin/mastergit commit --amend --reset-authorYou can confirm that your last commit which contains all the changes you’ve provided in your feature branch is the last one using ‘git log’.Next, create a new branch from your rebased feature branch using a name that describes the first portion of modifications you’re wanting to split off from your finished feature branch.git checkout -b new_comments_and_docsThen reset your branch to the commit that comes before your squashed commit. This is practically the state of the last commit in the master branch that you rebased from.git reset HEAD^If you run ‘git status’ now, you’ll see the list of unstaged/modified files, and untracked/new files that contain your work from this branch. It’s a good idea to take this list of files and separate them into groups for the split branches you plan on creating, using ‘git diff’ on the modified files to review the changes you made. This will help you avoid mistakenly forgetting to include certain files during the process.Once you’re ready, simply use ‘git add’ on the files that contain the changes you wish to keep in the current split from your feature branch.After you’ve added the files/modifications you wish to keep in this branch, and committed them, run the following commands to clear remaining modifications and untracked files.git checkout *git clean -fYou now have a split version of your feature branch. Checkout your feature branch and perform the steps above for the other changes you wish to split into separate branches."
    } ,
  
    {
      "title"    : "Application Builders",
      "category" : "",
      "tags"     : "builder",
      "url"      : "/2013/06/application-builders/",
      "date"     : "2013-06-05 07:11:12 -0700",
      "content"  : "Everytime I setup a new Rails application I have to go through the configuration and change many things. It’s as if there is a specific configuration that I prefer. For instance, I like using the Twitter Bootstrap framework for my front-end…at least just to get started. I like to use Rspec and Cucumber for testing. The list goes on.I just stumbled upon this argument that the ‘rails’ executable provides when generating a new Rails application.$ rails --helpUsage:  rails new APP_PATH [options]Options:  -r, [--ruby=PATH]              # Path to the Ruby binary   -b, [--builder=BUILDER]        # Path to a application builder (can be a filesystem path or URL)It appears that I can configure many options in some sort of file, hosted in a Gist file under my Github account, which I can use for each new project I begin. Awesome! I’ll have to explore this later, but for now here is a good article on the subject:Rails 3 Application BuildersI found that this article was from 2010, so documentation is likely a little better out there. Then I stumbled onto this Rails Composer which asks you questions to help you setup a new Rails application. It’s like a Rails generator on steroids.While I was trying to follow it’s instructions to run the generator, I kept getting an SSL error like so:      apply  https://raw.github.com/RailsApps/rails-composer/master/composer.rb/Users/jsmith/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/net/http.rb:799:in `connect': SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (OpenSSL::SSL::SSLError)    from /Users/jsmith/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/net/http.rb:799:in `block in connect'    from /Users/jsmith/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/timeout.rb:54:in `timeout'    from /Users/jsmith/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/timeout.rb:99:in `timeout'I found the recommendation to run the following to install a CURL CA bundle. After installing this I added the export command to my .zshrc file (zsh equivalent of the .bashrc file).brew install curl-ca-bundleAfter I did this, then opened a new terminal window, the generator worked just fine.rails new myapp -m https://raw.github.com/RailsApps/rails-composer/master/composer.rb -T -O"
    } ,
  
    {
      "title"    : "Technical Debt",
      "category" : "",
      "tags"     : "technical debt",
      "url"      : "/2013/06/technical-debt/",
      "date"     : "2013-06-03 18:43:05 -0700",
      "content"  : "If I were to pick one area of advice for any aspiring business men seeking their Master of Business Administration degree, with the intent of working for a company that involves developers, I recommend that you explore this concept. If you’re unaware of this possibility, your project might eventually end up drastically behind.Technical Debt"
    } ,
  
    {
      "title"    : "Why Ruby Was Named After a Gemstone",
      "category" : "",
      "tags"     : "ruby, perl",
      "url"      : "/2013/06/why-ruby-was-named-after-a-gemstone/",
      "date"     : "2013-06-03 16:54:30 -0700",
      "content"  : "Matz: Ruby is named after the precious gemstone, it’s not an abbreviation of anything. When I started the language project, I was joking with a friend that the project must be code-named after a gemstone’s name (àla Perl). So my friend came up with “ruby”. It’s a short name for a beautiful and highly valued stone. So I picked up that name, and it eventually became the official name of the language.Taken from An Interview with the Creator of Ruby by Bruce Stewart"
    } ,
  
    {
      "title"    : "Über-Securing Ubuntu 12.04 LTS with Mod-Security + Ruby on Rails 3.2.13",
      "category" : "",
      "tags"     : "security, mod_security, ubuntu, DDOS, linux, hosting, ssh",
      "url"      : "/2013/06/uber-securing-ubuntu-12-04-lts-precise-pangolin/",
      "date"     : "2013-06-01 08:29:51 -0700",
      "content"  : "By Marshall SontagI recently setup a linode server for a new client who wanted the best security practices installed.Most linux security guides instruct you to disable password authentication and enable SSH key authentication for SSH and use iptables to allow or block certain ports. But I found this incredible guide that takes it several steps further to prevent IP spoofing, DDOS attacks and much more.How to secure an Ubuntu 12.04 LTS server - Part 1 The BasicsIt also incorporates mod-security rules from the Open Web Application Security Project, which I just learned about through this tutorial.Note: Most of it installed without issue. But the fstab change stopped by server from booting. You’ve been warned!UPDATE: After deploying my Rails app to the server, I was getting 403 Forbidden errors. Naturally, I assumed it was mod-security, and I assumed there was some kind of conflict with Rails. I remembered there was a log in /var/log/apache2/modsec_audit.log.In the log, I first saw this:Message: Access denied with code 403 (phase 1). Match of "streq %{SESSION.IP_HASH}" against "TX:ip_hash" required. [file "/etc/modsecurity/activated_rules/modsecurity_crs_16_session_hijacking.conf"] [line "35"] [id "981059"] [msg "Warning - Sticky SessionID Data Changed - IP Address Mismatch."]Looks like it has something to do with Rails sessions. I opened up /etc/modsecurity/activated_rules/modsecurity_crs_16_session_hijacking.conf and commented out line 35, which looked like this:#SecRule TX:IP_HASH "!@streq %{SESSION.IP_HASH}" "phase:1,id:'981059',t:none,block,setvar:tx.sticky_session_anomaly=+1,msg:'Warning - Sticky Ses$Then I reloaded Apache and got this error:Message: Access denied with code 403 (phase 1). Match of "streq %{SESSION.UA_HASH}" against "TX:ua_hash" required. [file "/etc/modsecurity/activated_rules/modsecurity_crs_16_session_hijacking.conf"] [line "36"] [id "981060"] [msg "Warning - Sticky SessionID Data Changed - User-Agent Mismatch."]So I commented out that line, which looked like this:#SecRule TX:UA_HASH "!@streq %{SESSION.UA_HASH}" "phase:1,id:'981060',t:none,block,setvar:tx.sticky_session_anomaly=+1,msg:'Warning - Sticky Ses$Finally, after reloading again, everything worked perfectly.UPDATE 2: I spoke too soon. After submitting the form for registration of an account on my freshly-deployed app, I got another 403 error. This was the culprit:Message: Access denied with code 403 (phase 2). Pattern match "(^[\"'`\xc2\xb4\xe2\x80\x99\xe2\x80\x98;]+|[\"'`\xc2\xb4\xe2\x80\x99\xe2\x80\x98;]+$)" at ARGS:utf8. [file "/etc/modsecurity/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf"] [line "64"] [id "981318"] [rev "2.2.5"] [msg "SQL Injection Attack: Common Injection Testing Detected"] [data "\xe2"] [severity "CRITICAL"] [tag "WEB_ATTACK/SQL_INJECTION"] [tag "WASCTC/WASC-19"] [tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/CIE1"] [tag "PCI/6.5.2"]Checking the “/etc/modsecurity/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf” file, I found this:# -=[ String Termination/Statement Ending Injection Testing ]=-## Identifies common initial SQLi probing requests where attackers insert/append# quote characters to the existing normal payload to see how the app/db responds.#SecRule REQUEST_COOKIES|REQUEST_COOKIES_NAMES|REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "(^[\"'`&amp;acute;&amp;rsquo;&amp;lsquo;;]+|[\"'`&amp;acute;&amp;rsquo;&amp;lsquo;;]+$)" "phase:2,rev:'2.2.5',capture,t:none,t:urlDecodeUni,block,msg:'SQL Injection Attack: Common Injection Testing Detected',id:'981318',logdata:'%{TX.0}',severity:'2',tag:'WEB_ATTACK/SQL_INJECTION',tag:'WASCTC/WASC-19',tag:'OWASP_TOP_10/A1',tag:'OWASP_AppSensor/CIE1',tag:'PCI/6.5.2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sql_injection_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{tx.0}"Interesting. Something about my submission was seen as a “critical” SQL injection attack involving appended quote characters. Commented that SecRule out and this was the next error:Message: Warning. Operator GE matched 1 at TX. [file "/etc/modsecurity/activated_rules/modsecurity_crs_60_correlation.conf"] [line "29"] [id "981202"] [msg "Correlated Attack Attempt Identified: (Total Score: 9, SQLi=, XSS=) Inbound Attack ( Inbound Anomaly Score: ) + Outbound Application Error (The application is not available - Outbound Anomaly Score: 4)"] [severity "ALERT"]Naturally, I commented that out:# Correlated Attack Attempt##SecRule &amp;amp;TX:'/AVAILABILITY\\\/APP_NOT_AVAIL/' "@ge 1" \#"chain,phase:5,id:'981202',t:none,log,pass,skipAfter:END_CORRELATION,severity:'1',msg:'Correlated Attack Attempt Identified: (Total Score: %$#SecRule &amp;amp;TX:'/WEB_ATTACK/' "@ge 1" "t:none"Then I got a dozen of these errors:Message: Rule 7fd309fc0280 [id "950901"][file "/etc/modsecurity/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf"][line "77"] - Execution error - PCRE limits exceeded (-8): (null).Looked up that line and it was labeled “SQL Tautologies”. Commented that out and got this:Message: Warning. Match of "eq 1" against "&amp;amp;ARGS:CSRF_TOKEN" required. [file "/etc/modsecurity/activated_rules/modsecurity_crs_43_csrf_protection.conf"] [line "31"] [id "981143"] [msg "CSRF Attack Detected - Missing CSRF Token."]Message: Access denied with code 403 (phase 4). Pattern match "^5\\d{2}$" at RESPONSE_STATUS. [file "/etc/modsecurity/activated_rules/modsecurity_crs_50_outbound.conf"] [line "53"] [id "970901"] [rev "2.2.5"] [msg "The application is not available"] [severity "ERROR"] [tag "WASCTC/WASC-13"] [tag "OWASP_TOP_10/A6"] [tag "PCI/6.5.6"]Message: Warning. Operator GE matched 4 at TX:outbound_anomaly_score. [file "/etc/modsecurity/activated_rules/modsecurity_crs_60_correlation.conf"] [line "40"] [id "981205"] [msg "Outbound Anomaly Score Exceeded (score 4): The application is not available"]Commented out those last 3 lines, and it worked! I expect that I’ll still find more rules that conflict with the default behavior of Rails.Isn’t it fascinating that Ruby on Rails triggers so many of the Open Web Application Security Project’s security rules?"
    } ,
  
    {
      "title"    : "Downloadable Documentation",
      "category" : "",
      "tags"     : "documentation",
      "url"      : "/2013/05/downloadable-documentation/",
      "date"     : "2013-05-30 18:20:00 -0700",
      "content"  : "Some people want to download the documentation for the languages they’re using. This is needed when an internet connection isn’t available (like using a laptop on a plane), or even for the sake of speed.Here are two sources of downloadable documentation.  Ruby on Rails Documentation  Ruby documentation"
    } ,
  
    {
      "title"    : "History of Internationalization in Software",
      "category" : "",
      "tags"     : "unicode",
      "url"      : "/2013/05/history-of-internationalization-in-software/",
      "date"     : "2013-05-29 18:09:34 -0700",
      "content"  : "Here are two articles that were recommended by co-workers today.  History of Character Encoding  The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) - by Joel Spolsky"
    } ,
  
    {
      "title"    : "Mobile Application Performance Monitoring and Management",
      "category" : "",
      "tags"     : "mobile",
      "url"      : "/2013/05/mobile-application-performance-monitoring-and-management/",
      "date"     : "2013-05-28 19:45:57 -0700",
      "content"  : "It seems like the industry is all astir about mobile these days. I’m thinking of jumping into such interests.Heard about this today. It’s like New Relic for mobile apps.https://www.crittercism.com/"
    } ,
  
    {
      "title"    : "Use Ruby to Develop iOS or Mac OSX",
      "category" : "",
      "tags"     : "ios, mac-osx",
      "url"      : "/2013/05/use-ruby-to-develop-ios-or-mac-osx/",
      "date"     : "2013-05-22 01:53:31 -0700",
      "content"  : "I haven’t evaluated this yet, but another developer at my local Ruby meetup group said that this has been used in production and fairs pretty well.“RubyMotion is a revolutionary toolchain that lets you quickly develop and test native iOS and OS X applications for iPhone, iPad and Mac, all using the awesome Ruby language you know and love.”"
    } ,
  
    {
      "title"    : "Uninstalling Command Line Tools for Xcode",
      "category" : "",
      "tags"     : "xcode",
      "url"      : "/2013/05/uninstalling-command-line-tools-for-xcode/",
      "date"     : "2013-05-20 20:51:42 -0700",
      "content"  : "I ran into a problem trying to install Ruby 2.0.0 via RVM over the weekend. When I got to work the next day and needed to do work using Ruby 1.8.7, I ran into issues. This led to updating RVM using ‘rvm get stable’, and then trying to reinstall Ruby 1.8.7.I was then prompted that the version of Xcode I’m using is older, and thus needs to be updated. I tried to look for the command to uninstall it, just to ensure that the new installation (possibly via the App Store) is clean. I found this command to work for Mac OSX 10.8.3 (Mountain Lion).sudo /Library/Developer/4.1/uninstall-devtools -mode=allIf you have a much older version of XCode, the command might be:sudo /Developer/Library/uninstall-devtools --mode=allAlso, you might have a full version of XCode installed under /Applications/Xcode.app/, in which case you’ll want to simply drag and drop it into your trash to uninstall it. I did this and RVM finally indicated that there was no remaining outdated version of XCode. As you can see it defaults by checking in the /Applications/Xcode.app/ folder for developer tools.Installing requirements for osx, might require sudo password.Error: No developer directory found at /Applications/Xcode.app/Contents/Developer. Run /usr/bin/xcode-select to update the developer directory path.Strange thing is that for me, even after reinstalling the Command Line Tools for XCode 4.6.2 and then restarting my machine, I still am receiving this error:Error: No developer directory found at /Applications/Xcode.app/Contents/Developer. Run /usr/bin/xcode-select to update the developer directory path.Already up-to-date.I’m not really sure what the new path is. I’ve found that it’s best to simply install the full Xcode, so I’ve done that. No further errors regarding the developer directory path."
    } ,
  
    {
      "title"    : "Setting Rspec as the Default",
      "category" : "",
      "tags"     : "generators, workflow",
      "url"      : "/2013/05/setting-rspec-as-the-default/",
      "date"     : "2013-05-19 05:19:49 -0700",
      "content"  : "When setting up a new Rails application you’ll likely want to make Rspec the default test framework for new models that are generated with scaffolding. This is usually handled by default by the Rspec gem after you install it. It’s possible to explicitly set this however, as well as other configurations for generators.This is explained in more details in the Customizing Your Workflow section of the Rails generator documentation. You even have the option of turning off the generation of stylesheets if preferred."
    } ,
  
    {
      "title"    : "Remote Pair Programming",
      "category" : "",
      "tags"     : "pair programming, remote pair programming, coding presentation",
      "url"      : "/2013/04/remote-pair-programming/",
      "date"     : "2013-04-22 17:48:59 -0700",
      "content"  : "I really find pair programming to be annoying. It seems like a waste of time as compared to doing peer code review over a Git branch that has been squashed. But I really can’t knock something totally unless I’ve tried it for a while.Some people shared these resources today which I wanted to archive here. At least with remote pair programming you still get to have control of your computer, instead of sitting aside and watching idly. Here are some remote collaborative coding tools. These could also be useful for people wanting to remotely teach others how to code certain things.  SubEthaEdit  Sublime Collaboration - Plugin for the Sublime Text Editor  Mad Eye - Web based collaborative coding tool"
    } ,
  
    {
      "title"    : "Languages Supported by Github Flavored Markdown",
      "category" : "",
      "tags"     : "yardoc, github, markdown",
      "url"      : "/2013/04/languages-supported-by-github-flavored-markdown/",
      "date"     : "2013-04-12 20:57:57 -0700",
      "content"  : "NOTE: This post updated on 11/26/2017I’m currently configuring the Yard documentation tool for use withRuby/Rails projects. I could see that it’s possible to create a.yardopts file in the main directory for your Rails application, andsimply add command line arguments to the file.I just discovered that you can add a list of files, likely placed under the‘doc’ directory, to your .yardopts file, and those files will be included inyour generated documentation set. This is perfect for changelogs, readmefiles, and other high level documentation. After installing the Redcarpet gem,you can name these files with the ‘.md’ extension to useMarkdown formatting on your documentation.After further investigation I discovered that Yard supportsGithub Flavored Markdown, with support for syntax highlighting of anumber of different languages. This is accomplished by wrapping your code withlines that consist of three backticks, with the first line suffixed by thelanguage name.``` rubythis = "Ruby Code"puts "This is #{this}"```Unfortunately the Github docs refer you to this hightlight.js test pagefor the list of supported languages.Github uses Linguist to perform language detection and syntax highlighting.Here a list of common languages that can be used with the backtick (seefull list in Linguist - languages.yml).  actionscript3  apache  applescript  asp  brainfuck  c  cfm  clojure  cmake  coffee-script, coffeescript, coffee  cpp - C++  cs  csharp  css  csv  bash  diff  elixir  erb - HTML + Embedded Ruby  go  haml  http  java  javascript  json  jsx  less  lolcode  make - Makefile  markdown  matlab  nginx  objectivec  pascal  PHP  Perl  python  profile - python profiler output  rust  salt, saltstate - Salt  shell, sh, zsh, bash - Shell scripting  sql  scss  sql  svg  swift  rb, jruby, ruby - Ruby  smalltalk  vim, viml - Vim Script  volt  vhdl  vue  xml - XML and also used for HTML with inline CSS and Javascript  yaml"
    } ,
  
    {
      "title"    : "Coding Games",
      "category" : "",
      "tags"     : "javascript, code games",
      "url"      : "/2013/04/coding-games/",
      "date"     : "2013-04-11 20:30:59 -0700",
      "content"  : "A few weeks ago I heard about this FightCode website that lets youprogram robots that compete against other coders who code their own robots. Ituses Javascript, so it should be accessible to many web developers. They evenhave a Facebook page you can like.Recently a co-worker also mentioned a new programming game called NodeWar.It appears to be under development still, but could prove to be awesome."
    } ,
  
    {
      "title"    : "Customize your IRB",
      "category" : "",
      "tags"     : "irb",
      "url"      : "/2013/03/customize-your-irb/",
      "date"     : "2013-03-22 17:36:54 -0700",
      "content"  : "Stephen Ball of RakeRoutes.com has a cool post on how to customize your IRBenvironment.Customize your IRB"
    } ,
  
    {
      "title"    : "htaccess tester",
      "category" : "",
      "tags"     : "htaccess",
      "url"      : "/2013/03/htaccess-tester/",
      "date"     : "2013-03-01 08:43:17 -0800",
      "content"  : "I’m not sure how one would use this, but it looks like it’s supposed to beuseful.http://htaccess.madewithlove.be/"
    } ,
  
    {
      "title"    : "Using Find Each to Process Batches",
      "category" : "",
      "tags"     : "batch processing",
      "url"      : "/2013/02/using-find-each-to-process-batches/",
      "date"     : "2013-02-28 20:49:14 -0800",
      "content"  : "I just found out that there is a find_each method provided byActiveRecord which loops through an array of models that are retrieved inbatches of 1000 at a time.The find is performed by find_in_batches with a batch size of 1000 (or asspecified by the :batch_size option).User.find_each(:start =&gt; 2000, :batch_size =&gt; 5000) do |user|  user.do_somethingend"
    } ,
  
    {
      "title"    : "Development Time",
      "category" : "",
      "tags"     : "time, estimate",
      "url"      : "/2013/02/development-time/",
      "date"     : "2013-02-28 02:02:05 -0800",
      "content"  : "It seems common that development tasks or projects take much more time thanexpected. My manager recently pointed these out to me:The 90/90 Rule - “The first 90 percent of the code accounts for the first90 percent of the development time. The remaining 10 percent of the codeaccounts for the other 90 percent of the development time.”— Tom Cargill, Bell LabsHofstadter’s Law - “Hofstadter’s Law: It always takes longer than youexpect, even when you take into account Hofstadter’s Law.”— Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid"
    } ,
  
    {
      "title"    : "Minecraft Mods",
      "category" : "",
      "tags"     : "minecraft, mods, craftbukkit, console",
      "url"      : "/2013/02/minecraft-mods/",
      "date"     : "2013-02-10 02:30:53 -0800",
      "content"  : "I’ve been playing Minecraft for a little while now.Want to see what else this thing can do, so I want to get access to consolecommands. This is a challenge it seems, so I’m going to document how it’s donehere.I’m currently using Minecraft version 1.4.7. I just downloaded the latestbuild/snapshot (possibly unstable yet likely compatible) fromMinecraft-Console by simo415 on Github. A prerequisite to this modrunning is modloader, which states that it’s only for version 1.4.7.I’m using a Mac. I downloaded the modloader source files, then followedthe instructions to unpack the contents of the minecraft JAR file into atemporary directory.cd ~mkdir mctmpcd mctmpjar xf ~/Library/Application\ Support/minecraft/bin/minecraft.jarNext I copied the contents of the modloader source files into the temporarydirectory, overwriting all files. I then ran the following to remove somefiles and repackage the minecraft JAR file.rm META-INF/MOJANG_C.*jar uf ~/Library/Application\ Support/minecraft/bin/minecraft.jar ./cd ..rm -rf mctmpIt wasn’t clear how I install the Minecraft Console mod after performing this,but another website helped me see that I simply needed to drop theMinecraft_Console_Snapshot.zip file into~/Library/Application Support/minecraft/mods, which I renamed as‘Minecraft_Console.zip’ and restarted the program. I could see that in thatdirectory a ‘console’ folder showed up with configuration files and logs, so Iknew the plugin was loading.The ‘GuiAPI’ plugin is optional, and it required some sort of ‘Forge’ softwareto be present, so I decided not to explore this. I obtained theSinglePlayerCommands-MC1.4.7_V4.5.jar and ran the file, which presented aninstaller that auto-detected where to install the files. I did this andrestarted the program, but the command’s don’t seem to work. I really wantedthis because it seems to provide commands that are very helpful from theperspective of a single player… like reporting where my position is using‘//pos’ (which didn’t work).With Minecraft Console installed, I can use the backslash key to bring up theconsole, however I find that I can simply use the t command to talk likenormal…and this still respects commands starting with forward slash such as/time set 0. I also found that the forward slash key also brought up a nicelooking console that was large yet less intrusive to the game.The time set command didn’t work however, but instead responded with “Youdon’t have permission to set the time”. I connected to my server usingRemoteBukkit and used ‘/op myusername’ to give myself Op privileges. Afterdoing this I was able to set the time, and other commands."
    } ,
  
    {
      "title"    : "Obtain MySQL Query Statistics using Explain",
      "category" : "",
      "tags"     : "mysql, explain",
      "url"      : "/2013/02/obtain-mysql-query-statistics-using-explain/",
      "date"     : "2013-02-07 00:56:31 -0800",
      "content"  : "Sometimes it really counts to restructure the queries made to your MySQLdatabase, especially so that they do make use of indexes which are present onthe table.You can obtain information on which keys are being used with a query by usingthe EXPLAIN statement before your SELECT statement. Here are someexamples of it’s output.mysql&gt; EXPLAIN SELECT * FROM USERS WHERE area_id = 2;+----+-------------+---------+------+---------------+------+---------+------+------+-------------+| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra       |+----+-------------+---------+------+---------------+------+---------+------+------+-------------+|  1 | SIMPLE      | USERS   | ALL  | NULL          | NULL | NULL    | NULL |    6 | Using where |+----+-------------+---------+------+---------------+------+---------+------+------+-------------+1 row in set (0.03 sec)mysql&gt; EXPLAIN SELECT * FROM USERS WHERE group_id = 16515319;+----+-------------+---------+------+---------------------------+--------------------------+---------+-------+------+-------+| id | select_type | table   | type | possible_keys             | key                      | key_len | ref   | rows | Extra |+----+-------------+---------+------+---------------------------+--------------------------+---------+-------+------+-------+|  1 | SIMPLE      | USERS   | ref  | index_users_on_group_id   | index_users_on_group_id  | 4       | const |    1 |       |+----+-------------+---------+------+---------------------------+--------------------------+---------+-------+------+-------+1 row in set (0.00 sec)"
    } ,
  
    {
      "title"    : "Git Branching Model",
      "category" : "",
      "tags"     : "",
      "url"      : "/2013/02/git-branching-model/",
      "date"     : "2013-02-06 19:57:45 -0800",
      "content"  : "I just want to put this here for future reference.There is a version control branching model known as Git-Flow, which is verysimilar to the model used on the team I work with. SeeA Successful Git Branching Model. This seems to work well for teams thatmake several separate commits to the ‘develop’ branch, with differentversioned releases provided to the ‘release branch’ that may or may not havebeen tested and put through a quality assurance process, and finally onlymajor updates (not releases) merged into the ‘master’ branch and tagged withthe appropriate version number.My team doesn’t make small updates here and there on the develop branch. Wehave our own feature branches, which have all the small micro commits made tothem locally with whatever notes we choose to make for each. Once we’re donewith our work, we squash the commit into a single monolithic commit using ‘gitrebase’ then merge this into the ‘develop’ branch. This squash makes theprocess of reviewing the changes with the lead developer easier to do usingGitX.To squash we do a rebase with the remote ‘develop’ branch.git rebase -i origin/developAfter running this rebase command, our configured text editor opens. All ofthe commits that are not part of the ‘develop’ branch are displayed with‘pick’ shown before them, in order of oldest to newest commit.pick 2df148b combined commentspick 32e2471 Added description to rake taskspick 17ffc55 updated comment for config taskpick f0c4c6a added descriptive comments# Rebase 3012af2..f0c4c6a onto 3012af2## Commands:# p, pick = use commit# r, reword = use commit, but edit the commit message# e, edit = use commit, but stop for amending# s, squash = use commit, but meld into previous commit# f, fixup = like "squash", but discard this commit's log message# x, exec = run command (the rest of the line) using shell## These lines can be re-ordered; they are executed from top to bottom.## If you remove a line here THAT COMMIT WILL BE LOST.## However, if you remove everything, the rebase will be aborted.## Note that empty commits are commented outTo squash everything together we simply replace ‘pick’ with ‘s’ (or ‘squash’)for all but the first of the commits. After saving and closing the file, therebase process continues, various conflicts must be resolved and committedbefore using ‘git rebase –continue’. Once all the commits are squashedtogether with no further conflicts, the text editor pops open again and we areprompted to create a single commit comment.After this is complete, we merge our feature branch with it’s single commitinto the ‘develop’ branch and push remotely. Next we merge this into the‘release’ branch, then into the ‘master’ branch. This is kind of silly, reallyfor our team with this process we only need a ‘master’ branch. Our featurebranches go through the Q&amp;A and code review process with the leaddeveloper, so really ‘master’ is all that’s necessary.So in effect, what we do is closer to the Github-Flow. Our lead developerprovided me with this link and we’re switching to this model soon, cutting outthe ‘release’ and ‘develop’ branches. Here is a slideshow by Zach Holman ofGithub elaborating further - How GitHub uses GitHub to Build GitHub."
    } ,
  
    {
      "title"    : "Referencing Gem Source Code",
      "category" : "",
      "tags"     : "gem, gem source, unpack",
      "url"      : "/2013/02/referencing-gem-source-code/",
      "date"     : "2013-02-06 05:11:46 -0800",
      "content"  : "It’s often difficult to work with Ruby Gems that your Rails applicationdepends on because the source code for the gem itself is packed away in a gemdirectory. I’ve often found myself using the command ‘rvm gemdir’ to outputthe path to the gem directory that my application is using, changing to thatdirectory, and opening the source using Textmate. This is a time consumingprocess.Instead, it’s useful to simply unpack a gem into your Rails application sothat it loads from the vendor/gems directory. I’m currently using thefollowing command to unpack the RefineryCMS gems into my Rails app forreference.gem unpack refinerycms --version 2.0.9 --target vendor/gemsgem unpack refinerycms-core --version 2.0.9 --target vendor/gemsgem unpack refinerycms-dashboard --version 2.0.9 --target vendor/gemsThese unpacked gems are not referenced in my Gemfile, so I expect thereshouldn’t be any conflicts. The source is just there for my referencingpleasure."
    } ,
  
    {
      "title"    : "You can be a programmer too!",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/12/you-can-be-a-programmer-too/",
      "date"     : "2012-12-28 02:52:52 -0800",
      "content"  : "I’ve been telling people to check out CodeSchool.com because it has well laid out interactive courses that you can take to learn advanced web development technologies (jQuery, Coffeescript, Rails, etc).However, it doesn’t have the prerequisite courses on HTML, CSS, Javascript, and Ruby.It turns out that CodeAcademy.com covers those languages.Of course not just anyone can be a web developer, but if you’re nerdy and this stuff excites you, then go for it. I have a job working in San Francisco as a professional developer, doing Ruby on Rails programming. No college. Just experience. Just takes will and determination, and the effort to get experience even if it means taking a pay cut for a while.If you’re looking for something a little more low level, like algorithms or an intro to computer science, check out Udacity."
    } ,
  
    {
      "title"    : "Spree Extension Development Environment using RVM",
      "category" : "",
      "tags"     : "Spree, extension",
      "url"      : "/2012/12/spree-extension-development-environment-using-rvm/",
      "date"     : "2012-12-25 10:30:38 -0800",
      "content"  : "I’ve found that there is trouble working with a Spree extension when your gem set does not include the gems included with the Spree gem itself. I discovered this after generating a Spree extension, confining the extension to it’s own gem set using RVM, and then running ‘bundle install’ based on the Gemfile/gemspec configuration of just the extension itself.To overcome this, I recommend making a folder named ‘spree’, then configuring that folder to use a shared ‘Spree’ gem set.$ mkdir spree$ cd spree$ rvm --rvmrc --create 1.9.3-p327@spree$ cd ..$ cd spree===================================================================================== NOTICE                                                                           ====================================================================================== RVM has encountered a new or modified .rvmrc file in the current directory       == This is a shell script and therefore may contain any shell commands.             ==                                                                                  == Examine the contents of this file carefully to be sure the contents are          == safe before trusting it! ( Choose v[iew] below to view the contents )            =====================================================================================Do you wish to trust this .rvmrc file? (/Users/jason/Sites/spree/.rvmrc)y[es], n[o], v[iew], c[ancel]&gt; yesNext, install the Rails and Spree gems, generate a Rails application, install Spree into that application. You will use this application to explore Spree, experiment with it, etc. It’s main purpose is to install the gems that are dependencies of the Spree gem.$ gem install rails -v 3.2.9$ gem install spree -v 1.3.0$ rails _3.2.9_ new my_store$ spree install my_storeIn the same directory, generate the Spree extension.$ spree extension myextension      create  spree_myextension      create  spree_myextension/app      create  spree_myextension/app/assets/javascripts/admin/spree_myextension.js      create  spree_myextension/app/assets/javascripts/store/spree_myextension.js      create  spree_myextension/app/assets/stylesheets/admin/spree_myextension.css      create  spree_myextension/app/assets/stylesheets/store/spree_myextension.css      create  spree_myextension/lib      create  spree_myextension/lib/spree_myextension.rb      create  spree_myextension/lib/spree_myextension/engine.rb      create  spree_myextension/lib/generators/spree_myextension/install/install_generator.rb      create  spree_myextension/script      create  spree_myextension/script/rails      create  spree_myextension/spree_myextension.gemspec      create  spree_myextension/Gemfile      create  spree_myextension/.gitignore      create  spree_myextension/LICENSE      create  spree_myextension/Rakefile      create  spree_myextension/README.md      create  spree_myextension/config/routes.rb      create  spree_myextension/config/locales/en.yml      create  spree_myextension/.rspec      create  spree_myextension/spec/spec_helper.rb      create  spree_myextension/Versionfile        ********************************************************************************        Your extension has been generated with a gemspec dependency on Spree 1.3.0.        Please update the Versionfile to designate compatibility with different versions of Spree.        See http://spreecommerce.com/documentation/extensions.html#versionfile        Consider listing your extension in the official extension registry http://spreecommerce.com/extensions"        ********************************************************************************Now that the extension is created, you’ll need to make a minor modification to the configuration of the extensions Gemfile by forcing it to use the ‘edge’ branch version of the ‘spree_auth_devise’ gem. This requires simply adding the “, :branch =&gt; ‘edge’” to the end of the existing definition in the Gemfile for the extension. This step ensures that you do not receive any errors during the next step.gem 'spree_auth_devise', :git =&gt; "git://github.com/spree/spree_auth_devise", :branch =&gt; 'edge'Now you will need to generate the dummy Rails application which is used by your Rspec tests. As you are generating an extension that is meant to integrate with an existing Rails application environment, with the Spree gem installed, this is needed to ensure that you can rely on the Rails and Spree libraries being present during the tests.$ bundle exec rake test_appThor has already been required. This may cause Bundler to malfunction in unexpected ways.Generating dummy Rails application...Setting up dummy database...Now, you can troubleshoot issues you run into while developing the extension by dropping into the dummy applications Rails console. The dummy application is located under ‘spree_myextension/spec/dummy’. You should keep this application configured so that it’s configured as a stock Rails application with Spree installed, with your Rspec tests generating test data in the database on the fly.At most you should modify this Rails application so that it has the necessary modifications which you have documented for the user to make upon installing your extension, as well as the initializers or other files that your gem has generators for.Lastly you can initialize the new extension to sync up with a Git repository. I recommend using Bitbucket if you’re not developing a public extension, as they host unlimited private repositories for teams of up to 5 users."
    } ,
  
    {
      "title"    : "Creating a Gem",
      "category" : "",
      "tags"     : "gem",
      "url"      : "/2012/12/creating-a-gem/",
      "date"     : "2012-12-25 09:50:03 -0800",
      "content"  : "In the past gems were created manually, or generated using the echoe gem (last release Sept 21, 2011), or the Jeweler gem (last release November 7, 2011).Since then it appears that the most automated way to create a gem is by using Bundler, via the ‘bundle gem’ command.$ bundle gem my_tools      create  my_tools/Gemfile      create  my_tools/Rakefile      create  my_tools/LICENSE      create  my_tools/README.md      create  my_tools/.gitignore      create  my_tools/my_tools.gemspec      create  my_tools/lib/my_tools.rb      create  my_tools/lib/my_tools/version.rbInitializating git repo in /Users/jsmith/Sites/my_tools"
    } ,
  
    {
      "title"    : "Ruby File Modes",
      "category" : "",
      "tags"     : "file",
      "url"      : "/2012/12/ruby-file-modes/",
      "date"     : "2012-12-21 01:14:20 -0800",
      "content"  : "When working with files, you can open them in one of several modes.File.new("/file/path.txt", "w")You can find the description of these modes in the IO documentation."
    } ,
  
    {
      "title"    : "Return FALSE or Raise Error?",
      "category" : "",
      "tags"     : "ruby, exception handling",
      "url"      : "/2012/12/return-false-or-raise-error/",
      "date"     : "2012-12-20 18:35:44 -0800",
      "content"  : "I was working on a gem a couple months ago, and it came time for my boss to do a code review before we install the gem on another teams system. My boss pointed out that there were areas where I was returning FALSE, and baking in a lot of conditional statements and other handling, instead of using Ruby’s built in feature of error handling, which is designed to bubble exceptions up the call stack. He informed me that in situation that are not expected to occur, it’s best to raise an exception to halt execution and report the issue. He even recommended that I read Exceptional Ruby, a book devoted to the subject of proper exception handling.I didn’t understand that Ruby exceptions bubble up to the previously calling scripts, and thus can be captured and handled further up the stack. My boss pointed out that since my gem would be used only by a special controller setup on this separate system, in the service of providing an API, I could incorporate exception handling at the controller level which would handle different types of errors.We ended up defining several custom exception classes, used for different types of error which might occur. For instance, errors resulting from unexpected API calls would raise the custom MyAPI::UsageError (which inherits from standard RuntimeError), while expectations placed on their system while interfacing with its classes would raise one of the standard errors.Part of the Exceptional Ruby guide informed me that you don’t always have to use a begin..rescue..end block. You can simply insert a rescue block at the end a method, thus rescuing all statements before it. As you can see, we simply rescued the types of exceptions caused by the system calling the API so that it would simply return the error in the response, instead of raising the error in the remote systems Airbrake logs.def handler  raise MyApi::UsageError, "Request must be HTTP POST" unless request.post?  @response = Kabam::GmoApi::Server.handler(params[:json_request])  render :text =&gt; @response.to_jsonrescue MyApi::InvalidInputError, MyApi::UsageError =&gt; e  error_response = MyApi::Response.new(:status =&gt; 'failure', :result =&gt; e.message)  render :text =&gt; error_response.to_jsonendFor reference, here is the hierarchy of standard Ruby exceptions which you can use, or inherit from for your own custom exception classes.Exception NoMemoryError ScriptError   LoadError   NotImplementedError   SyntaxError SignalException   Interrupt StandardError   ArgumentError   IOError     EOFError   IndexError   LocalJumpError   NameError     NoMethodError   RangeError     FloatDomainError   RegexpError   RuntimeError   SecurityError   SystemCallError   SystemStackError   ThreadError   TypeError   ZeroDivisionError SystemExit fatal"
    } ,
  
    {
      "title"    : "When Testing Seems Pointless",
      "category" : "",
      "tags"     : "testing, tdd, unit-testing",
      "url"      : "/2012/12/when-testing-seems-pointless/",
      "date"     : "2012-12-19 02:51:53 -0800",
      "content"  : "I remember when I was first exposed to the concept of test driven development (TDD), it seemed like you were writing a test that did the same thing as the function itself. This really left me perplexed as to why everyone was raving about it’s value.Take for instance the following method:class SomeClass  def self.todays_date    Time.now.strftime("%Y-%m-%d")  endendAll this method does is return the date in ‘YYYY-MM-DD’ format. This might be used to name a log file, or in an ActiveRecord finder method call.The unit test for this method, using RSpec, would look like this:describe ".todays_date" do  it 'returns todays date in YYYY-MM-DD format' do    result = Contest.todays_date    result.should == Time.now.strftime("%Y-%m-%d")  endendDoesn’t that just seem silly? Yes!But one thing to remember about tests is that they ensure that parts of your application do what you expect them to do. It’s only with simple methods like this that you have tests that are so simple that they seem useless. However, even in this case, the test shown above is not a total waste. With this test in place, I can trust that any other part of my application which needs to use this method can do so and expect the same result. This test is my enforcer, ensuring that the contract between that method and the rest of my code is maintained, a contract which says SomeClass.todays_date will always return todays date in ‘YYYY-MM-DD’ format.Ensuring that the modules, classes, and objects you’ve designed provide the expected interface, perform the expected actions, and return the expected results, makes it so that you can move on and code other parts of your system without worrying if you should handle some situation where another entity might fail. You can focus on one unit at a time, and switch to the context of the dependencies and integration between the units when necessary, without having to think of them all at once within the limited memory of your human mind.For more complex methods, the test helps you catch errors as you create the method, and in the future when you modify the method. The tests even act as a form of documentation, as they provide an example of how the rest of your code might interface with your method.There is surely a learning curve to unit testing like this, and integration testing which ensures your units work together as expected. Once you develop the skills necessary to employ testing in your application, you’ll realize that the peace of mind obtained once your system becomes a large system is very valuable. It allows you to be more agile, not needing to be extra careful. Able to bring on new developers that aren’t completely familiar with your code like you are. Refactoring major parts of the system are also easier, as the tests point out every area of the application which isn’t behaving in a way which the rest of the application expects."
    } ,
  
    {
      "title"    : "Using Rspec to Test Controllers",
      "category" : "",
      "tags"     : "rspec, controller",
      "url"      : "/2012/12/using-rspec-to-test-controller/",
      "date"     : "2012-12-13 01:46:41 -0800",
      "content"  : "Here are some tips that will help you with Controller tests in Rspec.Common Response Methods# Get HTTP response code with message. Example: "302 Found"response.status# Get HTTP response code. Example: 200response.response_code# Get response bodyresponse.body# Get location header, used with redirectsresponse.locationCommon Matchers# Check for successful response, same as response.success?.should be_trueresponse.should be_success# Check if a specific template was renderedresponse.should render_template("edit")# Test if the controller method redirects to a specific path/urlresponse.should redirect_to(posts_url)# Check a global variable assigned in the controller methodassigns(:owner_id).should eq(current_user.id)Mocking or Stubbing PartialsIn this example I’m using Mocha with Rspec v1.3.2. I refer to the controller itself in this Controller test as ‘controller’. The ‘render’ or ‘render_to_string’ methods are part of the controller itself. In this example it’s rendering a partial to a string, and including it in a JSON hash being returned to an AJAX call.# Controller method uses render_to_string to render a partial to HTML string, includes in JSON responsecontroller.expects(:render_to_string).with(:partial =&gt; 'comment_block', :locals =&gt; {:post =&gt; post}).returns("comment block content").at_least_onceIt’s not advisable that you use a helper directly inside of a controller, and thus you shouldn’t need to stub one from within a controller method spec. Helpers should be used within views, otherwise your “helper” method should exist in a model, or in a utility library in /lib, so it’s available in the controller or elsewhere.Although this post isn’t on View testing, this article helps explain how to mocking partials and helpers in views."
    } ,
  
    {
      "title"    : "Good Guy Greg",
      "category" : "",
      "tags"     : "testing, rspec",
      "url"      : "/2012/12/good-guy-greg/",
      "date"     : "2012-12-11 21:48:15 -0800",
      "content"  : ""
    } ,
  
    {
      "title"    : "Using Rails 2.3.8",
      "category" : "",
      "tags"     : "rails, Rails-2.3.8, bundler",
      "url"      : "/2012/12/using-rails-2-3-8/",
      "date"     : "2012-12-03 19:57:38 -0800",
      "content"  : "I’m working on a project that is stuck on Rails 2.3.8 due to the size and complexity of the codebase. Upgrading it would be a nightmare. I recently ran into an issue with the database_cleaner gem, which isn’t rolling back transactional queries properly. I’m not sure if the issue is with the gem, or perhaps some configuration with the system (ActiveRecord) which is causing the issue. Because of this, I’m wanting to create a dummy Rails 2.3.8 application so that I can reproduce the issue on a fresh, simple, vanilla Rails application.I created a new ‘rails238’ directory and switched to it, then created a new gemset via RVM.rvm --rvmrc --create 1.8.7@rails238I then installed Rails 2.3.8.gem install --version '2.3.8' railsAfter this finished, I ran into an error when I would try to create a new Rails app.$ rails -d mysql funtownauto/Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:55: uninitialized constant ActiveSupport::Dependencies::Mutex (NameError)    from /Users/jsmith/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'    from /Users/jsmith/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'    from /Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/gems/activesupport-2.3.8/lib/active_support.rb:57    from /Users/jsmith/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'    from /Users/jsmith/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'    from /Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/gems/rails-2.3.8/lib/rails_generator.rb:31    from /Users/jsmith/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'    from /Users/jsmith/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'    from /Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/gems/rails-2.3.8/bin/rails:15    from /Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/bin/rails:19:in `load'    from /Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/bin/rails:19    from /Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/bin/ruby_noexec_wrapper:14This was resolved by downgrading the default Rubygems to version 1.4.2.gem update --system 1.4.2I ran through the instructions to setup Bundler with a Rails 2.3.8 system, manually created the ‘Gemfile’ in the root directory of the project, then ran ‘bundle install’.This included RSpec for Rails 1.3.4.source :rubygemsgem 'rails', '2.3.8'gem 'mysql2', '~&gt; 0.2.11'gem 'rdoc'gem 'bundler'group :development, :test do  gem 'rspec', '~&gt; 1.3.2'  gem 'rspec-rails', '~&gt; 1.3.4'  gem 'database_cleaner', '0.8.0'  gem 'fabrication', '~&gt; 1.3.2'endI installed Rspec, then tried to list the rake tasks available, I would receive an error regarding RDoc.$ script/generate rspecConfiguring rspec and rspec-rails gems in config/environments/test.rb ...      exists  lib/tasks      create  lib/tasks/rspec.rake      create  script/autospec      create  script/spec      create  spec      create  spec/rcov.opts      create  spec/spec.opts      create  spec/spec_helper.rb$ be rake -T | grep specrake aborted!no such file to load -- rake/rdoctask/Users/jsmith/Documents/rails238/funtownauto/Rakefile:8:in `require'/Users/jsmith/Documents/rails238/funtownauto/Rakefile:8/Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/bin/ruby_noexec_wrapper:14(See full trace by running task with --trace)It turns out that the config in the Rakefile conflicts with the latest Rdoc (version 3.12). I had to replace “require ‘rake/rdoctask’” with:require 'rdoc/task'This resolved the rake issue.require 'rdoc/task'Now I try to run the default Rspec test script, but run into an issue with the MySQL gem.$ bundle exec rake spec!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.rake aborted!no such file to load -- mysql/Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:156:in `require'/Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:156:in `require'/Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:521:in `new_constants_in/Users/jsmith/.rvm/gems/ruby-1.8.7-p371@rails238/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:156:in `require'Still stuck on this issue with the MySQL gem. I have MySQL2 gem installed, which works on the other non-new project, but still this error persists. This Stackflow article seems related, but the suggested solutions don’t help."
    } ,
  
    {
      "title"    : "Rspec Executable Not Found",
      "category" : "",
      "tags"     : "rvm, rspec",
      "url"      : "/2012/11/rspec-executable-not-found/",
      "date"     : "2012-11-28 01:14:27 -0800",
      "content"  : "I’m working on an older Rails 2.3.8 application that is way too complicated and without tests to make it worth upgrading to Rails 3 or higher. Because of this we must use RSpec-Rails 1.3.4, with RSpec 1.3.2.I was just trying to run a single test from the command line like so:$ bundle exec rspec spec/models/post.rbbundler: command not found: rspecInstall missing gem executables with `bundle install`I tried to uninstall and reinstall the gems, but still it didn’t work. I am using RVM, so this might be part of why this command isn’t working.It turns out that older versions of RSpec used ‘spec’ instead of ‘rspec’ as the executable name.$ which spec/Users/jsmith/.rvm/gems/ruby-1.8.7-p371@myproject/bin/spec"
    } ,
  
    {
      "title"    : "Changing the Default Text Editor",
      "category" : "",
      "tags"     : "git, text-editor",
      "url"      : "/2012/11/changing-the-default-text-editor/",
      "date"     : "2012-11-19 21:30:07 -0800",
      "content"  : "Certain command line utilities drop into an external text editor program to accept certain types of input. For instance, when using the command ‘crontab -e’ to edit your cron table, your default text editor program will be opened up with the current cron table configuration. The same also applies to the Git versioning system when using the interactive rebase mode. This helps the program avoid supporting it’s own text editor, and allows the user to specify their preferred text editor.To specify the default text editor, simply edit or place the following definition inside of the .bash_profile file in your home directory. This example uses ‘/usr/local/bin/mate -w’ to specify that the Textmate editor be used. You may configure this value to reflect the path for Vim, Nano, or any other text editor you wish to use.export EDITOR="/usr/local/bin/mate -w"It’s also possible to explicitly configure Git to use a specific text editor, thus overriding the default ‘EDITOR’ value specified in the command line environment. This is useful if you only want to change the behaviour of Git, and not affect the rest of your environment.git config --global core.editor "mate -w"UPDATE - 03/28/2013:I recently switched to Sublime 2 text editor. After installing the application I created a symlink like so:ln -s "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl" /usr/local/bin/sublAfter this was completed I added the following to my shell config file (.bash_rc / .zshrc):# Text Editorexport EDITOR=/usr/local/bin/sublIf you plan on using Sublime with utilities that expect you to save and close the file before the utility continues, you’ll need to configure a subl_wait script as outlined here.To use Sublime Text with Git during processes like an interactive rebase, configure it as the text editor using this command:git config --global core.editor "subl -n -w""
    } ,
  
    {
      "title"    : "Metaclass",
      "category" : "",
      "tags"     : "metaprogramming, metaclass",
      "url"      : "/2012/09/metaclass/",
      "date"     : "2012-09-19 19:19:03 -0700",
      "content"  : "I ran into an instance of meta programming in Ruby today, in the Exceptional Ruby book I’m reading for work. It seems that the theme this week is “you don’t know Ruby as well as you could”.I might be wrong in my understanding here, but this is what I understand thus far:Ruby stores methods for an object in it’s class, not the object itself. Objects only really store their attributes/variables in memory. However there exists some unseen entity known as the metaclass which belongs to each object, and it can possibly store methods which belong to that object, but not necessarily to that objects class.class Person  def speak    puts "Hello There!"  endendjohn = Person.newbob = Person.newclass &lt;&lt; john  def bark    puts "Ruff! Ruff!"  endend&gt;&gt; john.speak=&gt; Hello There!&gt;&gt; bob.speak=&gt; Hello There!&gt;&gt; john.bark=&gt; Ruff! Ruff!&gt;&gt; bob.barkNoMethodError: undefined method `bark' for #The reference to ‘class « john’ opens a code block where methods are defined in the metaclass for ‘john’, and not the ‘Person’ class.A more thorough understanding of this is explored in this blog post - Metaprogramming in Ruby: It’s All About the Self"
    } ,
  
    {
      "title"    : "Using Super with Ruby class methods",
      "category" : "",
      "tags"     : "superclass",
      "url"      : "/2012/09/using-super-with-ruby-class-methods/",
      "date"     : "2012-09-18 21:06:32 -0700",
      "content"  : "One of the awesome things about Ruby is that you can over-ride methods you define, or even over-write methods that are built into Ruby.This may not be unique with Ruby, but you can also over-ride super class methods in your defined subclass and use ‘super’ to execute the logic defined in the super class version of that method.class ScumbagSteve  def hello    puts "Hey, can I borrow $5."  endendclass GoodGuyGreg &lt; ScumbagSteve  def hello    super    puts "...I'll pay you back tomorrow with interest."  endend&gt;&gt; guy = GoodGuyGreg.new=&gt; #&lt;GoodGuyGreg:0x100346e70&gt;&gt;&gt; guy.helloHey, can I borrow $5....I'll pay you back tomorrow with interest.=&gt; nil"
    } ,
  
    {
      "title"    : "Ruby Coloured Glasses",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/09/ruby-coloured-glasses/",
      "date"     : "2012-09-18 19:46:48 -0700",
      "content"  : "I’m sorry Taryn. My friend just pointed your site out to me. I swear it was a coincidence. I like your background by the way."
    } ,
  
    {
      "title"    : "Duplicate associated records when using FactoryGirl",
      "category" : "",
      "tags"     : "factory_girl",
      "url"      : "/2012/09/issues-with-duplicate-associated-records-when-using-factorygirl/",
      "date"     : "2012-09-09 23:26:46 -0700",
      "content"  : "When I decided to start using tests as part of my development practice, I had the choice of using the default fixture system, or using one of the recommended fixture alternatives, also known as factories. I decided upon using FactoryGirl given it’s popular mention on the web, and one of the projects at work was using it.I had read much about the horrors if using fixtures, with the most memorable opinion of them being that they were ‘brittle’. This, and many other complaints, caused me to skip using fixtures and jump directly to using FactoryGirl.FactoryGirl has been pretty great. The one issue I’ve found however is that the methods for creating associations between parent and child records, and scripting the generation of those records, has proven to be poorly documented and thus difficult to work with.After a bit of investigation I gained the understanding that the ‘association’ attribute used with a factory will cause the parent factory to be generated. If you need the presence of child records in your test, then you need to use the ‘after_create’ callback with a code block that generates the children records. So the ‘association’ option goes up (parent), not down (child).This appears to be intended for creating multiple child records in a has_many relationship. Often, I really don’t like having ‘Article 1’, ‘Article 2’, ‘Article 3’, etc. be the name for my content generated. I want to be able to define a handful (or more) example records that are either used alone, or associated with generated records.Recently on another project I had a unique relationship in place. This project calls for ‘words’ which have child ‘definitions’, and the definitions have parent ‘publications’, but the ‘words’ do not have any association with ‘publications’. I really didn’t know how to handle this. I’d rather keep it simple, not so complicated. I just want FactoryGirl to create a record, and associated records, without creating duplicates (or errors where the duplicate record cannot be created due to unique value constraints).So today I found the holy grail of overcoming this issue. I wish it was part of the official FactoryGirl documentation, because seriously this seems common enough of an issue for me that I’d expect that others have the issue. Anyway, I found the answer in this StackOverflow question.You can code your factories so that they find the other factory that already exists, and makes the association, or generates a new one. Not only is this possible through this rather simple solution, but you can also implement more advanced creation code.So in my case I’m building a glossary system that has a ‘definition’ model which has two parents, ‘phrase’ and ‘publication’. The following code implements this solution for creating a single ‘phrase’ parent of the ‘definition’.As you can see my specialized version of the ‘definition’ factory, named ‘definition_cheese_and_spinach_omelette’ uses the get_phrase_named() method to generate the ‘Omelette’ phrase it should belong to. It will always associate with the phrase that has the name ‘Omelette’, whether it exists already or not.Another part of the beauty here is that I was also able to add coding to this method which generates the letter and ‘cached-slug’ when the Phrase with name submitted doesn’t already exist."
    } ,
  
    {
      "title"    : "Finding Records without Specific Child in Many-to-Many Relationship",
      "category" : "",
      "tags"     : "mysql, many-to-many",
      "url"      : "/2012/07/finding-records-without-specific-child-in-many-to-many-relationship/",
      "date"     : "2012-07-16 21:57:49 -0700",
      "content"  : "Okay. Here is a tricky challenge. Let’s say you are coding a blog system where Posts may have many Tags, and a tag can have many posts. Your database would have a ‘posts’ table, a ‘tags’ table, and a ‘post_tags’. With Ruby on Rails this would be configured for an ActiveRecord model using the has_many through method.has_many :tags, :through =&gt; :post_tagsI only want posts which have an absence of a relationship with a specific record, which is the tag record representing ‘horrible’. How do I query for a list of posts which are absolutely without a specific tag? Like say I have a ‘horrible’ tag, and I want all posts which are not tagged with ‘horrible’. How would I accomplish this?I’m not limiting myself to coding using an ActiveRecord relational query chain. I’m trying to accomplish this via MySQL using three test tables. I’ve identified that there is hope in accomplishing this using a full outer join, however such a query is not supported by MySQL. I’ve read other articles that have suggested using a union between a right and left outer join, but this didn’t provide me with the records containing the null values I expected.I suspect that the solution would first involve devising a query that iterates over each tag for each post, and where a record does not exist in the post_tags table it there is a NULL value for post_tags.id. After this is accomplished could a ‘WHERE’ statement be added which filters results to those which have the tag.id for ‘horrible’, which have a NULL value for post_tags.id.Further searching and I found a solution that isn’t related to what I expected. Using a ‘NOT EXISTS’ option in the WHERE clause makes it possible to insert a query which returns a result. If a result is returned, the parent query includes the result."SELECT p.id, p.titleFROM posts pWHERE NOT EXISTS (    SELECT p.id FROM tags t    WHERE t.post_id = p.id    AND t.tag_name IN ('horrible'))"This query is designed for a one-to-many relationship between two tables, where the ‘tags’ table includes the post_id and the tag in ‘tag_name’. This is at least a little closer, but doesn’t cover my many-to-many relationship requirement."
    } ,
  
    {
      "title"    : "Listing Gems from Rails Console",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/06/listing-gems-from-rails-console/",
      "date"     : "2012-06-20 21:59:03 -0700",
      "content"  : "Got this from Stack Overflow, figured it could come in handy at some point in the future.Gem.loaded_specs.values.map {|x| "#{x.name} #{x.version}"}"
    } ,
  
    {
      "title"    : "Add a Serialized Hash Attribute to a Factory_Girl Definition",
      "category" : "",
      "tags"     : "factory_girl, hash",
      "url"      : "/2012/06/add-a-serialized-hash-attribute-to-a-factory_girl-definition/",
      "date"     : "2012-06-11 20:25:13 -0700",
      "content"  : "I recently declared an ActiveRecord model which stores a serialized Hash inside of a text field. When I tried to setup a factory for this model using FactoryGirl, I received many syntax errors. This is because FactoryGirl attributes expect a single value or a certain form of code block.factory :post do    title        "Example Post"    body         "This is the body of the example post"    meta         { "version" =&gt; 2 }    created_at   "2012-06-01 17:53:13"  endTo include a hash as an attribute of a factory, declare the Hash separately and then simply assign it directly in the factory definition.meta_hash = { :version =&gt; 2 }  factory :post do    title        "Example Post"    body         "This is the body of the example post"    meta         meta_hash    created_at   "2012-06-01 17:53:13"  endAs Joshua Clayton pointed out, one could also do the following:factory :post do  title        "Example Post"  body         "This is the body of the example post"  meta         { { version: 2 } }  # or  meta({ version: 2 })  created_at   "2012-06-01 17:53:13"end"
    } ,
  
    {
      "title"    : "List Sorted Methods in Ruby",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/06/list-sorted-methods-in-ruby/",
      "date"     : "2012-06-11 18:06:48 -0700",
      "content"  : "I often use ‘methods’ to get a list of methods available for an object in Ruby, but it can be a pain trying to look through the list for what I want. I wish it outputed in a sorted list straight down the page. This template will help you achieve that. Maybe I should override the ‘methods’ method. Hm…"object".methods.sort.each do |method| puts method endIf you want to get only methods with a certain string inside them, use this:"object".methods.sort.each do |method| puts method if method.to_s.index('search_string') end"
    } ,
  
    {
      "title"    : "Updating a Serialized Object from a Web form",
      "category" : "",
      "tags"     : "serialize",
      "url"      : "/2012/06/updating-a-serialized-object-from-a-web-form/",
      "date"     : "2012-06-06 18:19:01 -0700",
      "content"  : "You may run into a situation where you create some sort of standard Ruby class that you want to associate with an ActiveRecord model. The serialize method allows you to store an object inside of a text field for an ActiveRecord object.With Rails 2.3 support for models nested within forms was added, but it’s clear that this support isn’t compatible with serialized objects. In my example below I have a Post model, which represents a simple blog post. The serialized object is instantiated from a custom class called ‘Metadata’, which stores metadata for the post like it’s type and version.class Post &lt; ActiveRecord::Base  serialize(:meta, Metadata)  accepts_nested_attributes_for :metaendclass Metadata  # Type of Post  attr_accessor :type  # Version of Post  attr_accessor :version  # builds new instance using hash  def initialize(params = {})    self.errors     = Array.new    self.type       = params[:type] unless params[:type] == nil    self.version    = params[:version] unless params[:version] == nil  endendI tried to setup the Post to accept nested attributes for my serialized field, which resulted in the following error:&gt; post = Post.newArgumentError: No association found for name 'serialized_field'. Has it been defined yet?I tried to setup a form using the ‘simple_fields_for’ method used by Simpleform (the equivalent of fields_for.&lt;%= simple_form_for @post do |f| %&gt;  &lt;%= f.input :title %&gt;  &lt;%= f.input :body, :as =&gt; 'text' %&gt;  &lt;%= f.simple_fields_for :meta do |m| %&gt;    &lt;%= m.select :type, options_for_select(@post_types, @post.meta.type) %&gt;    &lt;%= m.input :version %&gt;  &lt;% end %&gt;&lt;% end %&gt;This only resulted in an error with the ‘update_attributes’ method provided by ActiveRecord. A more detailed Gist is available here.&gt; post.update_attributes(:meta =&gt; { :type =&gt; 'awesome' })ActiveRecord::SerializationTypeMismatch: meta was supposed to be a Metadata, but was a HashThis causes me to suspect that Rails is not yet designed to handle the update of serialized objects via a nested hash included with the parameters submitted by the form. I can see that what happens is that the nested parameter hash itself is assigned to the ‘meta’ field for the object, instead of the values for each hash key being applied to the custom object.The solution that works is instead of defining the ‘simple_fields_for’ block as part of the parent object which the form is being built for, simply insert it as its own floating object inside your form. In the above example the ‘simple_fields_for’ method was called and passed a block within the Post form. This results in the fields being defined as part of the Post in the HTML form.&lt;input id="post_meta_version" name="post[meta][player]" size="50" type="text"&gt;Next in your controller, assign/update the parameters for the custom object separately.# PUT /posts/1def update  @post = Post.find(params[:id])  respond_to do |format|    if @post.update_attributes(params[:post])      # Update Metadata and save again      @post.meta.update_attributes(params[:metadata])      @post.save      format.html { redirect_to @post, notice: 'Post was successfully updated.' }      format.json { head :no_content }    else      format.html { render action: "edit" }      format.json { render json: @post.errors, status: :unprocessable_entity }    end  endend"
    } ,
  
    {
      "title"    : "RSpec Controller Tests Receiving &#39;No route matches&#39; Error",
      "category" : "",
      "tags"     : "rspec, namespaced controller",
      "url"      : "/2012/05/rspec-controller-tests-receiving-no-route-matches-error/",
      "date"     : "2012-05-25 18:24:17 -0700",
      "content"  : "I’m developing a Rails engine gem for the company I’m working for, which will provide an API for the applications we’re using.  The gem I’m creating will be used with a Rails 3.0.9 system, using Rspec-Rails version 2.10.1. I had a route to my API interface setup in the config/routes.rb file like so:Rails.application.routes.draw do  match '/companyname/api_name' =&gt; 'CompanyName/ApiName/ControllerName#apimethod'endWhen I added a ‘get’ request call to my controller test, I was getting this error:Failure/Error: get :apimethodActionController::RoutingError:  No route matches {:controller=&gt;"company_name/api_name/controller_name", :action=&gt;"apimethod"}I spent a great deal of time trying to figure out how to get my test to work. Different versions of Rspec, redefining my route using nested scopes, etc.It turns out I just needed to redefine my route in underscore case so that RSpec could match it with an existing route that was defined.match '/companyname/api_name' =&gt; 'company_name/api_name/controller_name#index'I guess Rspec controller tests use a reverse lookup based on underscore case, and not camelcase). Rails will setup and interpret the route if you define it in either case though.Seems so simple now that I know the answer. Hopefully I’ll save someone else time with this post."
    } ,
  
    {
      "title"    : "Cubase Installation Failure",
      "category" : "",
      "tags"     : "cubase, package scripts, install failure",
      "url"      : "/2012/05/cubase-installation-failure/",
      "date"     : "2012-05-23 03:48:01 -0700",
      "content"  : "I recently ran into issues installing Cubase 4 on my Mac running Snow Leopard. I uninstalled Cubase 5 Essential,thinking that this was causing a conflict, and thus stopping me from installing an older version. This wasn’t the caseI tried to install Cubase 5 Essential again, and I got the same type of error with it’s installer. I received Cubase 6in the mail today and tried to install it…only to receive the same type of error:5/23/12 12:09:29 AM installd[483] PackageKit: Install Failed: PKG: post-install scripts for "de.steinberg.vstsounds.halionsonicseadvancedcontent"Error Domain=PKInstallErrorDomain Code=112 UserInfo=0x1005f1690 "An error occurred while running scripts from the package 'vstsounds_HALion Sonic SE Advanced Content.pkg'." {    NSFilePath = "./postinstall";    NSLocalizedDescription = "An error occurred while running scripts from the package \U201cvstsounds_HALion Sonic SE Advanced Content.pkg\U201d.";    NSURL = "./Contents/Packages/vstsounds_HALion%20Sonic%20SE%20Advanced%20Content.pkg -- file://localhost/Volumes/Cubase%206/Cubase%206%20for%20Mac%20OS%20X/Cubase%206.mpkg/";    PKInstallPackageIdentifier = "de.steinberg.vstsounds.halionsonicseadvancedcontent";}5/23/12 12:09:29 AM com.apple.ReportCrash.Root[541] 2012-05-23 00:09:29.688 ReportCrash[541:2803] Saved crash report for installd[540] version ??? (???) to /Library/Logs/DiagnosticReports/installd_2012-05-23-000929_localhost.crash5/23/12 12:09:30 AM Installer[439]  Install failed: The Installer encountered an error that caused the installation to fail. Contact the software manufacturer for assistance.After many attempts to repair the permissions and the disk itself using the Disk Utility, I identified the cause ofthe issue after inspecting the crash report that the Cubase 6 installer provided. It turns out that Steinberg usesRuby scripts to install packages. I had renamed the symlink located at /usr/bin/ruby as /usr/bin/ruby.old, and createda new one that pointed to /opt/local/bin/ruby (the location of the Ruby interpreter I had previously installed usingMacPorts).After removing this symlink, and restoring the old one (which pointed to/System/Library/Frameworks/Rubyframework/Versions/Current/usr/bin/ruby), the installation of Cubase 6 was successful.HORRAY!"
    } ,
  
    {
      "title"    : "Generators Not Working in Rails 2.3.8",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/05/generators-not-working-in-rails-2-3-8/",
      "date"     : "2012-05-16 01:14:15 -0700",
      "content"  : "I’m currently working on a gem that is going to use a generator to create files in a Rails 2.3.8 application. One of the applications we’re still using is using Rails 2.3.8, so I have to make a gem compatible with that version of Rails.I installed Bundler v1.0.22 and configured it to work with the Rails app, and then followed many instructions and various configurations to get my generator classes to load. Every time I would try to run the generator however it simply gave me the error “Couldn’t find ‘hello’ generator”.I eventually found out that gems loaded via Git or Path via Bundler fail to load the generators. I was able to confirm this by loading the Devise gem via Git URI, and it’s generators failed to load. As I’m currently developing a gem, I need to be able to load it in dynamically via Git or via direct path…so this sucks.I found that I could use the ‘gem server’ command to run a local gem server, so I’ve been using the following commands to package up my gem and install it to the default system RubyGems (I’m using RVM), after I’ve updated the version for the gem in the gemspec (or version.rb file) in the gem source directory.$ gem build ~/Documents/gems/my-gem/my-gem.gemspec$ gem install --local my-gem-0.0.2.gemSuccessfully installed my-gem-0.0.21 gem installedInstalling ri documentation for my-gem-0.0.2...Building YARD (yri) index for my-gem-0.0.2...Installing RDoc documentation for my-gem-0.0.2...I then go into the Gemfile for my Rails 2.3.8 app and update the version, each time like so. As you can see I have a ‘source’ command for Bundler to obtain gems from my locally running Gem server.source "http://0.0.0.0:8808/"gem 'my-gem', '0.0.2'I run a ‘bundle install’, then run ‘bundle exec ruby script/generate’ to see if the generator defined in my gem is registering with the Rails app. Unfortunately so far the Devise generators are registering, but mine are not. I’m still investigating.To remove the previous un-successful gems, I use this command.$ gem uninstall my-gem -v 0.0.1Successfully uninstalled my-gem-0.0.1Further investigation just revealed that somehow my gems are being installed, but are empty (no files). It’s obvious now why my generators aren’t registering, they aren’t even declared in a file. I found that I needed to make the commits to my Git repository for my gem, and push the changes, and then run the ‘gem build’ command from within the gem directory itself.Prior to this it got these errors:$ gem build ~/Documents/gems/my-gem/my-gem.gemspecfatal: Not a git repository (or any of the parent directories): .gitfatal: Not a git repository (or any of the parent directories): .gitfatal: Not a git repository (or any of the parent directories): .gitWARNING:  no homepage specified  Successfully built RubyGem  Name: my-gem  Version: 0.0.3  File: kabam-gmo-api-rails2-0.0.8.gemIf I run ‘gem build my-gem.gemspec’ from inside of the gem folder, these errors did not occur. I simply rebuilt my gem, and another gem I also developed which it depends on , installed them in the default system gem set (which makes them available via my gem server). Then I ran ‘bundle install’ on my Rails 2 app, then ‘bundle exec ruby script/generate’ and now I see my generator.[UPDATE] Sept 11, 2012:I’m finally deploying my app, which relies on this gem I’ve developed with a Rails 2 generator. We don’t yet have a gem server setup, so I’ll have to rely on the application loading the gem via Bundler from the Git repository. As noted above, the generators I’ve included aren’t listed as available when I run ‘bundle exec script/generate’, nor are they executable when trying to run ‘bundle exec script/generate kabam_gmo_api_install’Further investigation shows that gems loaded from a gem server are placed in an accessible path, however gems originating locally or from git are loaded under a bundler gems path.$ bundle list kabam-gmo-api-rails2/Users/jsmith/.rvm/gems/ruby-1.8.7-p358@myapp/bundler/gems/gmo-api-rails2-7296b5229c7c$ bundle list rspec/Users/jsmith/.rvm/gems/ruby-1.8.7-p358@myapp/gems/rspec-1.3.2I suspect that this alternative gem path just isn’t present in the environment when bundler installs via Git or local.I found an article by Yehuda Katz that explains the internals of Bundler further. This issue just isn’t worth the time and effort to resolve.I’ve just included instructions for building the gems from source, installing to Gem path, running ‘bundle install’ with just the install gem names, running generators, restoring the Gemfile configuration to use Git repo URI’s, and running ‘bundle install’ again."
    } ,
  
    {
      "title"    : "Establishing New Ruby Environment in a Folder using RVM",
      "category" : "",
      "tags"     : "rvm",
      "url"      : "/2012/05/establishing-new-ruby-environment-in-a-folder-using-rvm/",
      "date"     : "2012-05-15 17:58:16 -0700",
      "content"  : "I know this is documented on the official RVM website, but I hate having to look it up over and over again each time I want to create a new RVMRC file.$ mkdir -p ~/projects/rails2test$ cd ~/projects/rails2test$ rvm --rvmrc --create 1.8.7@rails2test$ cd ..$ cd rails2test=============================================================================== NOTICE                                                                     ================================================================================ RVM has encountered a new or modified .rvmrc file in the current directory == This is a shell script and therefore may contain any shell commands.       ==                                                                            == Examine the contents of this file carefully to be sure the contents are    == safe before trusting it! ( Choose v[iew] below to view the contents )      ===============================================================================Do you wish to trust this .rvmrc file? (/Users/jmiller/Documents/rails2-apps/.rvmrc)y[es], n[o], v[iew], c[ancel]&gt; yI’m needing to setup a Rails 2.3.8 system, so I can test my gem for compatibility between it and Rails 3.0.9.I stumbled onto an article with suggestions for how to install RubyGems for Rails 2.3.8. This seems to run with errors, but the last command seemed to complete without errors other than ‘README’ not found:$ rvm all do gem install -v 1.4.2 rubygems-update$ rvm gem update --system 1.4.2$ update_rubygems$ rvm all do gem install -v 2.3.8 rails$ rails --versionRails 2.3.8$ ruby --versionruby 1.8.7 (2012-02-08 patchlevel 358) [i686-darwin10.8.0]"
    } ,
  
    {
      "title"    : "History of the Canonical Gem Host for Ruby Gems",
      "category" : "",
      "tags"     : "",
      "url"      : "/2012/05/history-of-the-canonical-gem-host-for-ruby-gems/",
      "date"     : "2012-05-14 18:41:23 -0700",
      "content"  : "The default repository for downloading gems using RubyGems was originally RubyForge.org. This was likely because the RubyGems project was hosted only from RubyForge. This meant that when you ran ‘gem install rails’, your RubyGems installation was configured to download the gem from ‘gems.rubyforge.org’. In August of 2008 Github started gaining popularity amongst the Ruby community after it started providing it’s own gem server via gems.github.com. This resulted in many Ruby developers configuring RubyGems to use the Github server as a secondary source of gems.In August of 2009 a new gem hosting repository came onto the scene known as GemCutter, aiming to resolve issues caused by how Github and RubyForge were handling hosting of gems. In September they decided to move the service to RubyGems.org. In October of Github discontinued building and serving gems from gems.github.com, and RubyGems.org became the official default host for Ruby gems."
    } ,
  
    {
      "title"    : "Using Serialize Option with ActiveRecord Objects",
      "category" : "",
      "tags"     : "rails3.1, forms",
      "url"      : "/2012/04/using-serialize-option-with-activerecord-objects/",
      "date"     : "2012-04-25 19:01:26 -0700",
      "content"  : "Documentation seems to be more available on how to build forms with checkboxes or a multiple select field for ActiveRecord objects that have a has_manyor has_many_and_belongs_to association with other ActiveRecord objects.This article shows you how provide a multiple select form based on a customdefined array, with the selected options stored in a single attribute of yourActiveRecord object.Lets say you are working on a form for a blog post that needs a multi-selectfield of statically defined adjectives, with the one or many adjectives savedto one field for the post.def self.adjectives  [    'awesome',    'phenomenal',    'terrific',    'fantastic',    'amazing',    'outstanding',    'stupendous',    'great',    'incredible',    'magnificent',    'impressive',    'excellent',    'sensational',    'fantasmagoric',    'legendary',    'marvelous'  ]endNext, inside of your model, insert a line indicating the name of the string ortext field you’re going to use to store the serialized values from the form.class Post &lt; ActiveRecord::Base  serialize :positive_adjectives, ArrayendIn the view file for your form, insert the following tag to create a selecttag which loads all the options with the previously selected ones saved to thepost field in a single field, serialized in YAML format.&lt;%= select_tag 'post[positive_adjectives]', options_for_select(Post.adjectives, @post.positive_adjectives), { :multiple =&gt; true, :size =&gt; 10 } %&gt;It appears that there are methods, possibly native ones for Rails 3.2.2soon, for storing your objects in the database in JSON format instead of YAML."
    } ,
  
    {
      "title"    : "Save the Tests, Don&#39;t Throw Them Away",
      "category" : "",
      "tags"     : "testing, tdd",
      "url"      : "/2012/04/save-the-tests-dont-throw-them-away/",
      "date"     : "2012-04-20 17:48:02 -0700",
      "content"  : "So it’s been several weeks since I started using test driven development. I’musing FactoryGirl instead of fixtures, because I’ve heard that fixtures arelimiting. I’d rather just write Factories from the beginning. I’m also usingstandard Test::Unit based unit and functional tests. Haven’t touched onintegration testing yet.As I’ve gone along and written these tests, I’ve learned how to do thingseffectively and am carving out my own style.For instance you could either test for a link with the content ‘Edit’ on thepage, or you could add an ID or class to the link and test for the presence ofthat link with that class. I found that I’d rather do both just to ensure thatthe button is or is not present in a certain circumstance.assert_select "a.btn", { :count =&gt; 0, :text =&gt; "Edit"}, "Edit button shouldn't be present for sent request"assert_select "a.btn", { :count =&gt; 0, :text =&gt; "Delete"}, "Delete button shouldn't be present for sent request"assert_select "a.edit-request", false, "Edit button shouldn't be present for sent request"assert_select "a.delete-request", false, "Delete button shouldn't be present for sent request"It may seem like a lot more coding is necessary for the tests than the codeitself which it is testing. This is true, and is one of the reasons I wasleery about writing tests. But here is the thing I wasn’t aware of, at leastnot in the way I understand it now.First off, it may look like a lot more code, but really it’s just a lot ofduplicated code that varies. Like in the above example, it’s really two typesof tests applied to two different buttons on the page. One type tests toensure a link with the ‘btn’ class (used by Twitter Bootstrap) with certaintext content isn’t present, and the other checks to make sure a link with aspecific class name isn’t present. I did this so that if someone else changesthe text of the button to say ‘Edit Request’, the class test will still catchif the link/button is present when it’s not supposed to. Now that I have thistype of test in place, when I need it again I can just copy and paste thesetests for the correct syntax, then modify them to meet the needs of the newpage I’m testing. So ultimately, it’s not that much more coding. It’s kind oflike when a person looks at a mixing console in a recording studio and thinks“Wow, how can that guy understand what all those knobs and buttons do?”. Oncethey realize that you just have to understand one column of those knobs andbuttons, and that each other column applied to a different instrument in themusic mix, all of a sudden understanding it becomes extremely simplified. It’sthe same thing with testing.Another point is that you don’t have to write tests for every single littlething. For my application, requests that have been sent to a remote systemlater should not be edited or deleted. I don’t want people trying to usebuttons that shouldn’t be showing on the screen, which is why I wrote thetests above. I know that I’d receive complaints from the users using theinterface if those buttons are showing, and if they result in error whensomeone attempts to use them in the wrong context…or worse if they result ina sent request being modified, and thus an accurate history for that requestis compromised instead of protected. However I found that when I was editingone of these requests, and the data I entered was invalid, a select form fieldthat relied on a collection of options rendered as a text field instead of aselect field. This is one of those special bugs that doesn’t necessarilycompromise a core function of the system. It’s not going to result in somemajor failure or side effect that would warrant a test, so I’ve chosen to justfix the bug and move on without a test for that scenario. If the issue doespop up in practice more than I expect, then I’ll write a test to avoid ithappening again, but for now I’m picking and choosing my battles based on myexperience and expectations.The main point of this post that I wanted to make however is that you’re doingit anyway. If you’re not using test driven development, you’re testing yourmodels in the Rails console, or opening your browser and testing the appwithin the development environment. For model method testing, once you closeyour terminal window the coding you wrote in the IRB console is gone forever.The same principle of loss applies to browser based tests. You have to adjustthe records in your development environment often, and go through a specialsequence of events just to get the right state in your development environmentwith a browser, just to test one single result. This is EXTREMELY timeconsuming and laborious. With unit tests you can test the result of eachmethod, and are actually more likely to implement tests using rare cases youwould be too lazy to test for otherwise. With functional tests, theenvironment needed to properly test a specific scenario is much easier tosetup and maintain, and is performed in seconds instead of minutes (or evenhours).I’m not yet opinionated regarding other testing options such as Rspec,Cucumber, etc. however I definitely see the benefit of picking up a habit ofwriting tests as the solution to a major waste of time later on after yourproject has grown. I have much less anxiety regarding unexpected bugs, and Iknow that once one is identified it can be fixed and a test can be written forit if necessary."
    } ,
  
    {
      "title"    : "Factory Girl Associations and Records Persisting Across Tests",
      "category" : "",
      "tags"     : "rails3.1, testing, factory_girl, tdd",
      "url"      : "/2012/04/factory-girl-associations-records-persisting-across-tests/",
      "date"     : "2012-04-11 22:32:23 -0700",
      "content"  : "I just recently started to adopt test driven development practices. Theproject I’m working on needs to get done soon, and I didn’t want to get heldup learning Rspec. After much consulting with other developers at thecompany I work for, I had decided to use basic Test::Unit tests withFactoryGirl factories instead of fixtures, and adopt Shoulda if a scenarioarises where the options it provides (contexts) are needed.So far things have been running well, and I’m starting to understand just howimportant testing is. You don’t have to write tests for every single thing youdo, but if you implement some sort of feature that you seriously don’t want tobreak at some point in the future, setup a test for it. Once you setup a testfor one type of feature, you can re-use the code later for similar testing. Sodon’t worry about how long it takes the first time around, it will pay offlater when that function isn’t broken because you caught it. I didn’t realizeit, but errors you didn’t expect it to directly catch, like the dreaded“undefined method ‘foo’ for nil:NilClass” exception, also popup periodicallyand alert you that you broke something, even though your test wasn’t built tocatch those. This is nice because you might change something in a model, andthen all of a sudden something in a view is broken.Earlier today I had a new functional test I wrote fail because it wasexpecting a view to render an index of child records that Factory Girl wasn’tcreating. For this example ‘User’ has multiple ‘Posts’, and the post recordsbelonging to the user weren’t being generated. I expected that FactoryGirl wasActiveRecord aware, and would simply create the dependent post records, butthat’s not the case. Much research online, sifting through articles with theolder syntax used by previous version of FactoryGirl, led to much confusion.For a bit I was thinking that one needs to declare associations for children,instead of parents, and then use Factory.create on the highest level parent sothat all the children records are generated before your test. This wasn’t thecase.It turns out that you should only use associations to define the relationshipinside of a child factory for it’s parent, not the other way around. If you doit the other way around, you’ll end up getting ‘stack level too deep’ errors.I expected that perhaps there would be some sort of way of defining that afactory should create or build the children records, which are definedseparately, but for practicality it doesn’t seem this is the case. Instead,Factory Girl expects you to use the ‘after_create’ callback to causeassociated children records to be created. I guess this makes sense, as itwould be too redundant to create multiple factories in a separate file, muchlike you define child fixtures. Its more encapsulated to generate the childrenwith the parent in the same code block.factory :user do  association :group  name "John Smith"  created_at "2011-04-11 12:00:00"  factory :user_with_posts do    # default to 5 posts    ignore do      posts_count 5    end    after_create do |user, evaluator|      FactoryGirl.create_list(:post, evaluator.posts_count, user: user)    end  endendThe above declaration would allow one to create a user with 5 posts bydefault, or create one with 15 posts instead. Ironically enough, I figuredthis out by referring to the official FactoryGirl GETTING STARTED docs,after searching elsewhere on the internet.FactoryGirl.create(:user).posts.length # 0FactoryGirl.create(:user_with_posts).posts.length # 5FactoryGirl.create(:user_with_posts, posts_count: 15).posts.length # 15I’ve been creating factories instead of fixtures, using factories exclusivelyin my application. I assumed that somehow when I ran tests that Test::Unitand/or FactoryGirl would automatically create and destroy the records whichare created for each test, so that there is a clean slate each time anindividual test is run. Further investigation pointed to the term being‘transactional’, with a deprecated ‘use_transactional_fixtures’ setting thatwas declared as either TRUE or FALSE for ActiveSupport::TestCase. It appearsthis is the default now for tests.Once I added a factory that generates a parent with children records, I hadanother controller test report an error where the assert_select didn’t findthe form with ID I had expected. That ID was for one of the children records,with a form expected using id “edit_message_1”, but was instead getting“edit_message_41”. Further investigation suggested that records are persistingacross tests.Then I inspected log/test.log, and saw that there were transactional commandsoccurring with BEGIN and ROLLBACK commands used by MySQL.   (0.1ms)  BEGIN   (0.1ms)  SAVEPOINT active_record_1  SQL (0.2ms)  INSERT INTO `posts` (`title`, `body`, `created_at`, `updated_at`) VALUES ('Foo', 'This is Foo', '2012-04-12 03:56:24', '2012-04-12 03:56:24')   (0.1ms)  RELEASE SAVEPOINT active_record_1   (0.1ms)  SAVEPOINT active_record_1  SQL (0.2ms)  DELETE FROM `posts` WHERE `posts`.`id` = 1   (0.1ms)  RELEASE SAVEPOINT active_record_1   (0.4ms)  ROLLBACKAnd yet for each ID of each record created by Factory Girl the number wasincremented each time. I was perplexed why the tests were transactional,however the ID’s were being incremented. I’m using MySQL 5.5.19, with InnoDBtables, so the transactional commands being used should be supported.I then spoke with a co-worker and he informed me that the tests do usetransactions, so the records are removed after each test. The transactionalqueries however do not stop the MySQL database from auto-incrementing the IDfor the other additional records. He advised that I simply not write the teststo rely on a specific ID, but instead rely on something static in the viewlike the class name for an element, or that there is the correct number ofelements for a given class.Further more he recommended not relying on view testing so much via theFunctional/Controller tests and to instead do more of that via integration oracceptance tests, such as those using Capybara to do a full-stack test fromthe browser perspective."
    } ,
  
    {
      "title"    : "Generating Test File Stubs for Existing Models, Views, and Controllers",
      "category" : "",
      "tags"     : "rails3.1, testing, rspec, tdd",
      "url"      : "/2012/04/generating-rspec-tests-for-existing-models-views-controllers/",
      "date"     : "2012-04-03 13:10:12 -0700",
      "content"  : "I’ve noticed that if you install certain testing gems, like Factory Girl, orRspec, that your Rails application will create test files for these librariesinstead of using the defaults. Even further you can configure the generatorsused by your Rails app in /config/application.rb# Configure generators values. Many other options are available,# be sure to check the documentation.# http://edgeguides.rubyonrails.org/generators.html#customizing-your-workflowconfig.generators do |g|  g.stylesheets false  g.test_framework :rspec  g.fallbacks[:rspec] = :test_unit  g.fixture_replacement :factory_girlendI’ve been anxious however in deciding which testing tools to learn and usewith my project. If I choose the wrong one, then all the scaffold generatedtest code will be generated for the test framework I might choose to quitusing at some point.This is not completely correct though, as I’ve discovered.I found that the following commands will generate the empty spec files.rails generate rspec:modelrails generate rspec:viewrails generate rspec:controllerEven better though, if you’re looking for scaffold style files to be put inplace, use the following syntax to generate scaffold code.rails generate rspec:scaffold Post title:string body:textIf you decide to use basic Test::Unit based tests, instead of going withRspec, you can also reconfigure your app to use Test::Unit again withgenerators, and then use the rake commands to generate the files that weregenerated via rspec.$ rails gUsage: rails generate GENERATOR [args] [options]General options:  -h, [--help]     # Print generator's options and usage  -p, [--pretend]  # Run but do not make any changes  -f, [--force]    # Overwrite files that already exist  -s, [--skip]     # Skip files that already exist  -q, [--quiet]    # Suppress status outputPlease choose a generator below.TestUnit:  test_unit:controller  test_unit:helper  test_unit:integration  test_unit:mailer  test_unit:model  test_unit:observer  test_unit:performance  test_unit:plugin  test_unit:scaffold"
    } ,
  
    {
      "title"    : "Rails 3 and Subclasses Method",
      "category" : "",
      "tags"     : "rails3.1",
      "url"      : "/2012/03/rails-3-and-subclasses-method/",
      "date"     : "2012-03-26 18:38:14 -0700",
      "content"  : "I was just trying to create coding that reflectively loads the subclasses of aclass I’ve defined. The idea is that as new subclasses are added, the scriptI’m writing can detect which ones are present and inform a remote API thatsupport for a specific API feature is available.I had executed the method once on the class, and it did return the name of thesubclass that I had defined and checked for the existence of in the Railsconsole environment. Then I added other subclasses, reloaded (reload!), andran the method once again. This time I got nothing but an empty array returned.It turns out that Rails 3 uses autoloading for classes…so the subclasseshave to be referenced at some point, and thus loaded into memory, before thesubclasses method will include them in the list."
    } ,
  
    {
      "title"    : "Locate and Updatedb with Homebrew",
      "category" : "",
      "tags"     : "os x lion, findutils, homebrew",
      "url"      : "/2012/03/locate-and-updatedb-with-homebrew/",
      "date"     : "2012-03-26 14:08:59 -0700",
      "content"  : "UPDATE: I ran into errors and decided to not use the findutils provided byHomebrew. I simply setup the following alias in .bash_profile and this did thetrick. This is using the built in locate database provided with Mac OS X SnowLeopard.alias updatedb='sudo /usr/libexec/locate.updatedb'I used to use MacPorts to ensure that my command line environment on my Macwas almost exclusively using MacPort provided binaries, not the built inbinaries and libraries that are packaged with Mac OS X.I had heard of Homebrew, but MacPorts seemed to work fine for me. Then Irealized that Homebrew does the same thing, but installs software in/usr/local, which doesn’t require sudo. The benefits of Homebrew seem to besimplicity, lack of intrusiveness, and speed. I’m likely going to use itas the package manager in my Rails developer toolkit in the future.I just noticed that I am not able to use the ‘locate’ command to search forcertain matching filenames on my system. I love using this option piped intogrep to find what I’m looking for, such as the path to a particular gem I’mneeding to inspect the code for.I installed the ‘findutils’ package that includes ‘locate’ via Homebrew.$ brew install findutils==&gt; Downloading http://ftpmirror.gnu.org/findutils/findutils-4.4.2.tar.gz######################################################################## 100.0%==&gt; ./configure --prefix=/usr/local/Cellar/findutils/4.4.2 --program-prefix=g--disable-debug==&gt; make installWarning: Non-libraries were installed to "lib".Installing non-libraries to "lib" is bad practice.The offending files are:/usr/local/Cellar/findutils/4.4.2/lib/charset.alias==&gt; Summary/usr/local/Cellar/findutils/4.4.2: 19 files, 1.2M, built in 68 secondsI thought that the warning regarding non-libraries being installed to “lib”stopped the package from being installed properly, but it turns out that theexecutables were installed with symlinks placed in /usr/local/bin (which is inmy path) and pointing to the actual installed binaries. Instead of ‘locate’and ‘updatedb’, the commands are ‘glocate’ and ‘gupdatedb’.As advised by Grogs, I updated my .bash_profile file to set theLOCATE_PATH to point to the database in my local users tmp directory.I didn’t want to have to setup a running cron daemon on my Mac, and I’m justfine with running the updatedb command manually when needed, so I simply addedaliases to build and locate using the proper executable filenames.alias updatedb="gupdatedb --localpaths='/Users/jmiller' --output='/Users/jmiller/tmp/locatedb'"alias locate="glocate"export LOCATE_PATH="~/tmp/locatedb"Before this would work though, I did need to create a ‘tmp’ folder in my homedirectory.mkdir ~/tmpUPDATE:This wasn’t successful however. I started to get an error:$ updatedb/usr/bin/sort: string comparison failed: Illegal byte sequence/usr/bin/sort: Set LC_ALL='C' to work around the problem./usr/bin/sort: The strings compared were `/USERS/JMILLER/LIBRARY/APPLICATION SUPPORT/TEXTMATE/BUNDLES/SCSS.TMBUNDLE/COMMANDS/INCREASE NUMBER.TMCOMMAND' and `/USERS/JMILLER/LIBRARY/APPLICATION SUPPORT/TEXTMATE/BUNDLES/SCSS.TMBUNDLE/COMMANDS/INSERT COLOR302200246.TMCOMMAND'.I’m going to just use the locate/updatedb options which come packaged with MacOS X."
    } ,
  
    {
      "title"    : "Foreign Key References when Generating Model",
      "category" : "",
      "tags"     : "migrations",
      "url"      : "/2012/03/foreign-key-references-when-generating-mode/",
      "date"     : "2012-03-23 18:15:26 -0700",
      "content"  : "I forget the proper syntax for a model generation command that includes areference to another models id (foreign key).Here is an example you can use to remember:rails g model Post user:references title:string body:textSince the ‘user’ model already exists, Rails knows that this should be theuser_id field that it generates. I guess it’s not a big deal, you could justdo ‘user_id:integer’, but what fun is that?"
    } ,
  
    {
      "title"    : "Edit Devise User without Password",
      "category" : "",
      "tags"     : "rails, devise",
      "url"      : "/2012/03/edit-devise-user-without-password/",
      "date"     : "2012-03-20 16:38:43 -0700",
      "content"  : "I recently setup a custom controller to edit/update my Admin accounts, which are authenticated using Plataformatec’s Devise gem.I found an article in the Devise Wiki that mentions using some sort of‘update_without_password’ method to update the model without requiring thepassword. In this case I’m not requiring the user to provide their ownpassword to edit their info. I’m allowing them to do it straight out.The solution that I found was to simply remove the ‘password’ and‘password_confirmation’ from the parameter set if both are blank.# remove password parameters if blankif params[:admin]['password'].blank? &amp;amp;&amp;amp; params[:admin]['confirmation'].blank?  params[:admin].delete('password')  params[:admin].delete('password_confirmation')end"
    } ,
  
    {
      "title"    : "Factory Girl Not Generating Factories with Scaffold",
      "category" : "",
      "tags"     : "rails3.1, factory_girl",
      "url"      : "/2012/03/factory-girl-not-generating-factories-with-scaffold/",
      "date"     : "2012-03-19 14:18:44 -0700",
      "content"  : "I just started a new Rails 3.2 project, and to ensure that the proper testfiles are generated using Shoulda or Factory_Girl, I’ve installed those gemsand configured the application to generate the test files using these gems.Added to config/application.rb:  # Configure generators values.  # http://guides.rubyonrails.org/generators.html  config.generators do |g|    g.stylesheets false    g.test_framework :shoulda    g.fallbacks[:shoulda] = :test_unit    g.fixture_replacement :factory_girl  endEach time I would try to create a new scaffold, it would use shoulda togenerate the test unit file, but would generate a YAML fixture.invoke active_recordcreate db/migrate/20120319180004_create_posts.rbcreate app/models/post.rbinvoke shouldacreate test/unit/post_test.rbcreate test/fixtures/posts.ymlOver a year ago there was a gem needed to ensure that generators werepresent to generate Factory_Girl factories instead of YAML fixtures, but thecode for those generators was moved to the official Factory_Girl gem, sothat’s not the cause of this issue.It turns out that I had configured factory_girl_rails in my Gemfile only underthe ‘test’ group, and not the ‘development’ group as well.group :development, :test do  gem 'shoulda'  gem 'factory_girl'  gem 'factory_girl_rails'endAfter configuring these under both test and development, the scaffoldgenerator created the factory under ‘test/factories’ as I had expected."
    } ,
  
    {
      "title"    : "Ruby Comparison Operator =~",
      "category" : "",
      "tags"     : "comparison operator, ruby",
      "url"      : "/2012/03/ruby-comparison-operator/",
      "date"     : "2012-03-07 18:26:34 -0800",
      "content"  : "I saw this in some code recently, wasn’t sure what it did.It basically returns TRUE or FALSE if there is a regular expression match,with the regular expression coming after the ‘=~’."
    } ,
  
    {
      "title"    : "Invalid Gemspec Error Regarding Invalid Date Format",
      "category" : "",
      "tags"     : "rails3.1, rubygems",
      "url"      : "/2012/02/invalid-gemspec-error-invalid-date-format/",
      "date"     : "2012-02-22 18:30:45 -0800",
      "content"  : "I installed factory_girl (2.6.0) for a project I am working on recently, andall of a sudden I started getting errors with RubyGems when I would try to runa rake task, such as:Invalid gemspec in[/opt/local/lib/ruby/gems/1.8/specifications/capistrano-2.11.2.gemspec]:invalid date format in specification: "2012-02-22 00:00:00.000000000Z"Invalid gemspec in[/opt/local/lib/ruby/gems/1.8/specifications/capistrano-2.9.0.gemspec]:invalid date format in specification: "2011-09-24 00:00:00.000000000Z"I went through the long process of uninstalling all my gems, running anupdate on RubyGems using ‘gem update –system’ and then reinstalling themagain via ‘bundle install’. Still the gems were uninstalled, yet thespecification errors were still occurring.I tried to run ‘gem cleanup’ or ‘gem pristine –all’ to get rid of the error.Eventually I was able to resolve the issue, but I don’t remember exactly how Idid it. Then today I go to work on another workstation, and the same thingoccurs. It turns out that the invalid strings just need to be removed from the specification files.As the errors pointed to files in /opt/local/lib/ruby/gems/1.8/specifications/(I’m using MacPorts), running these commandsresolved the issue for me.cd /opt/local/lib/ruby/gems/1.8/specifications/sudo find . -type f | sudo xargs perl -pi -e 's/ 00:00:00.000000000Z//'"
    } ,
  
    {
      "title"    : "Deleting Git Branches in Remote Repository",
      "category" : "",
      "tags"     : "git",
      "url"      : "/2012/01/deleting-git-branches-in-remote-repository/",
      "date"     : "2012-01-24 18:08:06 -0800",
      "content"  : "I had recently used a branch to handle all the modifications I was making to asystem for a Rails 3.1 upgrade from Rails 2.4.3. After I merged my changesback into the master branch, I deleted the ‘rails3’ branch locally, but itstill remained on the remote server.I found that ‘git push origin :branch_name’ will delete the repository fromthe remote server if the branch has been removed locally.$ git push origin :rails3To git@example.com:myrepo.git - [deleted]         rails3"
    } ,
  
    {
      "title"    : "Rails 3 on WHM / cPanel VPS Server",
      "category" : "",
      "tags"     : "capistrano, passenger, rails3.1, cpanel",
      "url"      : "/2012/01/rails-3-on-whm-cpanel-vps-server/",
      "date"     : "2012-01-08 13:14:58 -0800",
      "content"  : "cPanel is working towards making Rails 3 applications run natively withPassenger, setup via the cPanel interface. I’m not really sure if this will beideal, as most organizations deploy their apps to the server using Capistrano,not uploading via FTP or something.I’ve been hosting a number of PHP driven sites, including this blog, from ashared hosting service for quite a while now. Shared hosting is fine forpersonal websites or even small businesses with 4-5 page brochure stylewebsites that do not receive lots of traffic, but they’re not fine if slowperformance or intermittent downtime causes you to loose business (or even therespect of your visitors). In such cases I recommend a VPS, because youcontrol who you’re hosting and thus can ensure optimal uptime and performance.I highly recommend Linode as a VPS provider.I’ve been using the shared hosting for PHP/Wordpress sites, and a VPS to hostthe Ruby on Rails applications I’ve been working on. Really this is expensive,so I’m wanting to consolidate to one VPS for everything.I’ve been forewarned that cPanel does things it’s own way, so if you’re tryingto do something out-of-the-box you can run into issues. I’m aware of this, andthrough this article will let you know if setting up a Rails 3.1.3 hostingenvironment is possible with a WHM / cPanel server (RELEASE version 11.30.5,build 3). I plan on using Gitosis under an account to host repositories,Capistrano for deployment, and Passenger with Apache2 already provided bycPanel.Installing RubyTo stay within the “box” of the cPanel environment, I installed Ruby using thescript provided by cPanel:/scripts/installrubyGitosisTo setup Gitosis you have to first install Python tools.yum -y install python-setuptoolsNext, to install Git, you’ll have to use a special command because cPanel hasconfigured /etc/yum.conf to exclude certain packages, including perl packages,so that they do not break or conflict with the cPanel system. Use thefollowing command to install Git:yum --disableexcludes=main install gitFrom the root home directory, download and install Gitosis.cd /rootgit clone git://eagain.net/gitosis.gitcd gitosispython setup.py installNext create an account to host your Git repositories from the WHM interface.I’ve added a user with the user name ‘git’, and used ‘git.web-app-host.com’ asthe domain (a subdomain under my hosting service domain). Set the password toa very long secure password. You won’t be needing it again, as you’ll be usingan SSH key to authenticate.After you’re done creating the cPanel account which will host therepositories, copy your public key from your local machine to your root usershome direcotry ( /root/ ).scp ~/.ssh/id_rsa.pub root@vps.web-app-host.com:/rootGo back to your SSH session as ‘root’ on the server and run this command toinitialize the Gitosis repository under the ‘git’ user account.root@vps [~]# sudo -H -u git gitosis-init &lt; /root/id_rsa.pubInitialized empty Git repository in /home/git/repositories/gitosis-admin.git/Reinitialized existing Git repository in /home/git/repositories/gitosis-admin.git/NOTE: Do not use the ‘Manage SSH Keys’ option from the cPanel for the Gitacccount, as this will remove the Gitosis-admin repository key from/home/git/.ssh/authorized_keys.Run the following command to make sure the post-update hook is executable. Ifthis isn’t done, then tasks performed by Gitosis after you commit an updatearen’t performed (i.e. creating new repositories).sudo chmod u+x /home/git/repositories/gitosis-admin.git/hooks/post-updateOn your local machine, run the following command to clone the Gitosis-adminrepository, used to manage your repositories on the server, to your localmachine.git clone git@&lt;YOURSERVER&gt;:gitosis-admin.gitThis should look like this:$ git clone git@vps.web-app-host.com:gitosis-admin.gitCloning into 'gitosis-admin'...stdin: is not a ttyremote: Counting objects: 5, done.remote: Compressing objects: 100% (5/5), done.remote: Total 5 (delta 0), reused 5 (delta 0)Receiving objects: 100% (5/5), done.Note: If you are prompted for a password when running this clone command, youlikely have some sort of SSH configuration not setup properly on your localmachine. If you’re using multiple keys with various hosts, check~/.ssh/config and make sure you’re using the proper syntax. Runssh git@&lt;YOURSERVER&gt; -v to get a verbose output of what’s happening when theSSH session is initialized to investigate further.On the remote machine, go ahead and delete your public key from the root usershome directory.rm /root/id_rsa.pubAfter cloning the Gitosis repository to your local machine, you simply modifyand commit changes to the ‘gitosis.conf’ file inside of the ‘gitosis-admin’folder.If you’re configuring new users, simply add their public SSH keys to the‘keydir’ folder with the ‘.pub’ file extension. Refer to these users using thefilename of the public key file without the ‘.pub’ extension.For instance I’ve added a repository called ‘marketsim’, and then added‘marketsim’ to the ‘writable’ setting for the gitosis-admin group.[gitosis][group gitosis-admin]writable = gitosis-admin marketsimmembers = jason@mymacbook.local[repo marketsim]gitweb = nodescription = Market Simulation Appowner = Jason Millerdaemon = noAlternatively I could create a new group with writable access to the‘marketsim’ repository.[gitosis][group gitosis-admin]writable = gitosis-adminmembers = jason@mymacbook.local[group marketsim-team]members = jason@mymacbook.localwritable = marketsim[repo marketsim]gitweb = nodescription = Market Simulation Appowner = Jason Millerdaemon = noI could add ‘newteammember.pub’ in the ‘keydir’ folder, then add‘newteammember’ after ‘jason@mymacbook.local’ separated by a space. This wouldmake another team member part of that group which has write access to therepository.After configuring a new repository, and giving my own local user write accessto that repository, I’ve push the changes via a commit to the remotegitosis-admin repository.NOTE: You may receive the warning:remote: WARNING:gitosis.gitweb.set_descriptions:Cannot find 'yourrepo' in '/home/git/repositories'Ignore this and continue.Now I’m going to initialize my new repository and push it to the remote server.$ cd marketsim$ git init .$ git add .$ git commit -m "initial commit"$ git remote add origin git@vps.web-app-host.com:marketsim.git$ git push origin masterstdin: is not a ttyInitialized empty Git repository in /home/git/repositories/marketsim.git/Counting objects: 3, done.Writing objects: 100% (3/3), 209 bytes, done.Total 3 (delta 0), reused 0 (delta 0)To git@vps.web-app-host.com:marketsim.git * [new branch]      master -&gt; masterDeploying to ServerI’ve created an account with the username ‘marketsi’ to host the deployedapplication (cPanel only allows up to 8 characters for the username). ThenI’ve logged into that account and added my public key via the SSH/Shell Access  Manage SSH Keys section of the cPanel account.For property deployment you’ll need to install the ‘Bundler’ gem so that thedeployment script can install the gems needed for your application. You’llneed to install this as ‘root’ so that the ‘bundle’ script is available under/usr/bin/bundle.$ ssh root@vps.web-app-host.comroot@vps [~]# gem install bundlerFetching: bundler-1.0.21.gem (100%)Successfully installed bundler-1.0.211 gem installedInstalling ri documentation for bundler-1.0.21...Installing RDoc documentation for bundler-1.0.21...root@vps [~]# which bundle/usr/bin/bundleI’ve modified my deploy.rb file for my Rails application like so:require "bundler/capistrano"load "deploy/assets"############################################################## Settingsset :application, "marketsim"default_run_options[:pty] = true  # Must be set for the password prompt from git to workset :use_sudo, falseset :user, "marketsi"  # The server's user for deploysset :deploy_to, "/home/#{user}/rails"set :ssh_options, { :forward_agent =&gt; true }set :domain, "marketsim.org"server domain, :app, :webrole :db, domain, :primary =&gt; true############################################################## Gitset :scm, :gitset :repository,  "git@vps.web-app-host.com:marketsim.git"set :branch, "master"set :deploy_via, :remote_cache############################################################## Passengernamespace :passenger do  desc "Restart Application"  task :restart do    run "touch #{current_path}/tmp/restart.txt"  endendafter :deploy, "passenger:restart"Now to run the script to setup the deployment directories on the remote server.cap deploy:setupThis created a folder under /home/marketsi/rails with the ‘releases’ and‘shared’ folder. Now I’ll actually deploy.cap deployThe gems were installed with no issue by Bundler for me. Hopefully the samegoes for you.PassengerThe next step is to configure Apache to serve the Rails application for mydomain name. Install the Passenger gem via SSH logged in as root:gem install passengerInstall Passenger using the Apache module installation command. Alldependencies should be found and displayed in green.passenger-install-apache2-moduleAt the end of the installation script it provides the Apache configurationsettings which you place in httpd.conf. Since we’re using cPanel, whichover-writes the Apache configuration when the EasyApache system is used torebuild Apache, PHP, and other modules, place this configuration in/usr/local/apache/conf/includes/pre_main_global.conf.# /usr/local/apache/conf/includes/pre_main_global.confLoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-3.0.11/ext/apache2/mod_passenger.soPassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-3.0.11PassengerRuby /usr/bin/rubyNext make a backup of the httpd.conf, run the configuration distiller script, rebuild, and then restart Apache.cp /usr/local/apache/conf/httpd.conf /usr/local/apache/conf/httpd.conf.bak-modrails/usr/local/cpanel/bin/apache_conf_distiller --update/scripts/rebuildhttpdconf/etc/init.d/httpd restartThe cPanel system makes the Apache Document Root for each account map to/home/username/public_html. Because of this you will need to remove the‘public_html’ directory, and then create a symlink from that directory to the‘public’ directory for your applications current release:rm -rf /home/marketsi/public_html/ln -s /home/marketsi/rails/current/public /home/marketsi/public_htmlchown marketsi:nobody public_html/chmod 750 public_html/Next add a .htaccess file in your application under the ‘public’ folder, andmake sure it contains ‘RailsBaseURI /’, as well as a directive with thePassengerAppRoot.RailsBaseURI /PassengerAppRoot /home/marketsi/rails/currentMySQL DatabaseIf your application returns an error page ‘We’re sorry, but something wentwrong.’, check the production.log file on the server. In my case, theapplication was running, but it couldn’t connect to the database with theexisting database.yml settings for production.As cPanel controls the MySQL databases and usernames, you’ll have to create adatabase manually via the cPanel, create the user and assign all privileges toit for the database, and then configure your database.yml appropriately."
    } ,
  
    {
      "title"    : "Configuring Rails 3.1.3 under Sub-URI",
      "category" : "",
      "tags"     : "rails3.1, relative_url_root, sub-uri",
      "url"      : "/2012/01/configuring-rails-3-1-3-under-sub-uri/",
      "date"     : "2012-01-04 02:02:40 -0800",
      "content"  : "In setting up a new Rails app recently I was told that it needed to be servedunder the sub-URI of ‘/info’. I hadn’t done this before with a Rails app, andI expected that it could be tricky.I checked online to see how this is done and found references to the‘relative_url_root’ setting, but then shortly found that this has beendeprecated.I’m using Phusion Passenger with Apache 2, so I inserted the followingconfiguration into my VirtualHost entry for the site.Alias /info /home/myapp/current/public&lt;Location /info&gt;  PassengerAppRoot /home/myapp/current  RailsEnv production&lt;/Location&gt;The Rails application was expecting requests from the root of the site still.I found a StackOverflow article where someone suggested configuring all theroutes under the “/info” scope like so:# config/routes.rbscope "/info" do  root :to =&gt; "welcome#index"  resources :postsendThis worked fine in development mode. I just made sure to pull up the pagesusing http://localhost:3000/info/I had tested this in production before building out the application further,and it seemed to work fine. Later on when I deployed after many updates, Ifound that the application was referencing precompiled assets using ‘/assets/’and not ‘/info/assets/’. Further investigation pointed out that I needed toconfigure assets with a prefix like so:# config/application.rbconfig.assets.prefix = "/info/assets"This seemed like it would help, but this caused assets to be precompiled under‘public/info/assets’.I had previously Googled for ‘rails 3.1 subdirectory path’, not registeringthat the more appropriate keyword is ‘sub URI’ for what I’m trying toaccomplish.It turns out that the best way to do this with Passenger is to mount theapplication to the sub-URI using the proper Apache configuration, and leave itup to the Rack interface to handle serving the requests to the Railsapplication, without using any Rails application configuration for the sub-URI.I removed the scoped routes, and the assets prefix, returning my applicationto it’s default configuration. I then created a symbolic link for ‘info’ inthe websites DocumentRoot, pointing to the ‘public’ folder of my applicationas per the Passenger documentation.ln -s /home/myapp/current/public /home/mysite/public_html/infoI added the appropriate configuration into my VirtualHost entry as advised bythe Passenger documentation, but this only worked for the root of the website,not my admin area I had wanted to serve from /info/admin/. All I got was a 404page from the main site.I found that the following configuration worked perfectly, with the symboliclink still needing to be present.Alias /info /home/myapp/current/public&lt;Location /info&gt;  PassengerAppRoot /home/myapp/current  RackEnv production  RackBaseURI /info&lt;/Location&gt;You might notice that I’m using ‘RackEnv production’ instead of‘RailsEnv production’. This is because I recall at some point previously thatRails 3.0 applications are Rack Applications, and thus you have to use‘RackEnv’ instead for Passenger to load the application in the properenvironment mode.Update 01/04/12: I’m using the TinyMCE-Rails plugin to provide a WYSIWYGeditor for one of the resources in my application. It’s not loading inproduction however (surprise, surprise). I checked into the precompiledJavascript file being served from the live server, and I see it includes thefollowing:window.tinyMCEPreInit=window.tinyMCEPreInit||{base:"/assets/tinymce",query:"3.4.7",suffix:""}The ‘base’ value should be ‘/info/assets/tinymce’. I see that in theTinyMCE-Rails gem the coding for this is:window.tinyMCEPreInit = window.tinyMCEPreInit || {  base:   '&lt;%= Rails.application.config.assets.prefix %&gt;/tinymce',  query:  '&lt;%= TinyMCE::VERSION %&gt;',  suffix: ''};All call to ‘asset_path(‘rails.png’)’ in production returns‘/info/assets/rails-e4b51606cd77fda2615e7439907bfc92.png’ so Rails is honoringthe RackSubURI setting configured for Passenger. The following returns thesame path.The reason why this works is that the Rails asset helpers pull therelative_url_root value from the controller configuration, which must receiveit from the Rack configuration. When deploying the app using Capistrano, suchconfiguration is not present, and thus the correct path cannot be included inthe precompiled assets.The issue was reported via Git hub in issue #3259 and #2435, and afix will was implemented in Rails 3.2, with a possibly backport to Rails3.1.4.It appears that you’ll need to add a configuration to your application.rb orenvironments/production.rb, depending on how your development and productionenvironments are setup.# config/environments/production.rb# Use sub-uri in productionconfig.relative_url_root = '/info'Or possibly configure your deployment script to include the environmentvariable when precompiling.RAILS_RELATIVE_URL_ROOT="/info" bundle exec rake assets:precompileI wanted to test this, but I can’t seem to update to Rails 3.2, or install anew Rails app using edge Rails.rails new testapp --edge...Bundler could not find compatible versions for gem "actionpack":  In Gemfile:    sass-rails (&gt;= 0) ruby depends on      actionpack (~&gt; 3.1.0) ruby    rails (&gt;= 0) ruby depends on      actionpack (4.0.0.beta)I’m just going to configure my app under a subdomain instead of sub-uri fornow."
    } ,
  
    {
      "title"    : "Custom Rake Tasks Not Loading",
      "category" : "",
      "tags"     : "rake",
      "url"      : "/2012/01/custom-rake-tasks-not-loading/",
      "date"     : "2012-01-01 18:57:34 -0800",
      "content"  : "I recently went to create a new Rake task under /lib/tasks in a Railsapplication I’m working on. I didn’t understand why the rake tasks weren’tshowing when I would run rake -T from the command line.When I’d try to run the task itself I would get a ‘Don’t know how to buildtask’ error.I just realized that I was naming my task file with the ‘.rb’ extension, andnot ‘.rake’. Doh!"
    } ,
  
    {
      "title"    : "Troubleshooting ActiveResource Requests",
      "category" : "",
      "tags"     : "ActiveResource, HighRise, REST API",
      "url"      : "/2012/01/troubleshooting-activeresource-requests/",
      "date"     : "2012-01-01 18:46:52 -0800",
      "content"  : "I’m currently working on an app which integrates with the HighRise APIusing the Highrise Ruby wrapper gem. The classes defined by the gem relyon ActiveResource, the Ruby library included with Rails for interfacing withRESTful resources like the HighRise API.Sometimes I’m not sure if the requests being made via the commands I’m usingare making the right calls on the HighRise API.I found this thread on StackOverflow:How do I view the HTTP response to an ActiveResource request?. Thesolution I found helpful was this one onoverriding ActiveResource::Connection so that it outputs the debug output.This worked for me even with Rails 3.1.Just in case this article with the code disappears, here is the initializercode you can use to view the HTTP session data from the console. I’ve added anif statement to make sure the HTTP data is only outputted to the standardoutput in development mode, for security purposes, as well as requiresthe environment variable ‘HTTPDEBUG’.# /config/initializers/connection.rbclass ActiveResource::Connection  # Creates new Net::HTTP instance for communication with  # remote service and resources.  def http    http = Net::HTTP.new(@site.host, @site.port)    http.use_ssl = @site.is_a?(URI::HTTPS)    http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl    http.read_timeout = @timeout if @timeout    # Here's the addition that allows you to see the output    if Rails.env == 'development' &amp;amp;&amp;amp; ENV['HTTPDEBUG']      http.set_debug_output $stderr    end    return http  endendYou can open the Rails console using ‘HTTPDEBUG=true rails c’ to activate theconsole with debugging output displayed in the console mode."
    } ,
  
    {
      "title"    : "Example Rake Task",
      "category" : "",
      "tags"     : "rake",
      "url"      : "/2012/01/example-rake-task/",
      "date"     : "2012-01-01 18:26:28 -0800",
      "content"  : "Here is example rake task code which you can use and modify the next timeyou’re setting up new Rake tasks for a Rails app from scratch. The exampleincludes the syntax for setting the default task, running multiple tasks inorder, and a task which includes multiple arguments. This coding syntax workswith Rails 3.1.# /lib/tasks/mytask.rakenamespace :mytask do  task :default =&gt; 'mytask:full_run'  desc "run all tasks in proper order"  task :full_run =&gt; [:example_task_one, :example_task_two] do    puts "All tasks ran and completed at #{Time.now}"  end  desc "example task without arguments"  task :example_task_one =&gt; :environment do    # task code goes here    puts "Example Task One completed"  end  desc "example task with arguments"  task :example_task_two, [:arg1, :arg2] =&gt; :environment do |t, args|    # if no arguments, display docs    if args.count == 0      puts ''      puts "rake mytask:example_task[arg1,arg2]"      puts "arg1: description of first argument"      puts "arg2: description of second argument"      puts ''      puts "example:"      puts "rake mytask:example_task[123,'456']"      puts ''    else      # task code goes here      puts "Running task with arg1: #{args.arg1}, and arg2: #{args.arg2}"      puts "Example Task Two completed"    end  endendSpecial thanks to Jason Seifer for his Rake Tutorial which made thispossible."
    } ,
  
    {
      "title"    : "Adding a New User in Ubuntu",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/12/adding-a-new-user-in-ubuntu/",
      "date"     : "2011-12-29 18:08:48 -0800",
      "content"  : "Adding UserWhen setting up a new website manually on an Ubuntu server you need toestablish a user account with a home directory, and Bash shell access to theserver.useradd -m testuser -s /bin/bashAfter creating the account you’ll want to assign a password for the account.passwd testuser"
    } ,
  
    {
      "title"    : "Resolving issues with Namespaced Models in Rails 3.1.0",
      "category" : "",
      "tags"     : "rails, namespaced models, rails3.1",
      "url"      : "/2011/12/resolving-issues-with-namespaced-models-in-rails-3-1-0/",
      "date"     : "2011-12-06 19:09:51 -0800",
      "content"  : "I recently was tasked with upgrading an application from Rails 2.3.8 to Rails  I choose to upgrade it to Rails 3.1, because why upgrade once and then haveto do it again later.After upgrading and testing many points of the system locally, I was ready topush the upgraded application to the production server. After pushing it out Istarted to notice that a certain rake task was failing to run via a cronjob Ihad setup. This rake task worked with certain non-ActiveRecord models, which Ihad setup with a hierarchy which utilized inheritance and namespacing.Under Rails 2.3.8 I had a file, /app/models/rets_map/rets_map_base.rb. Theerror I was receiving from the rake task involved some sort of issue loadingthe class from this file.As an experiment I renamed the file as ‘base.rb’ so that it’s path was/app/models/rets_map/base.rb. I figured that Rails 3.1.0 expected thisnaming convention. I was right, kind of…$ rails console/Users/jason/Sites/rj4/rails/app/controllers/site_setup_controller.rb:120: warning: string literal in conditionLoading development environment (Rails 3.1.0)irb(main):001:0&gt; RetsMap=&gt; RetsMapirb(main):002:0&gt; RetsMap::Base=&gt; RetsMap::Baseirb(main):003:0&gt; reload!Reloading...=&gt; trueirb(main):004:0&gt; RetsMap=&gt; RetsMapirb(main):005:0&gt; RetsMap::Base=&gt; RetsMap::Baseirb(main):006:0&gt; reload!Reloading...=&gt; trueirb(main):007:0&gt; RetsMap=&gt; RetsMapirb(main):008:0&gt; RetsMap::BaseLoadError: Expected /Users/jason/Sites/rj4/rails/app/models/rets_map/base.rb to define RetsMap::Base    from /opt/local/lib/ruby/gems/1.8/gems/activesupport-3.1.0/lib/active_support/dependencies.rb:490:in `load_missing_constant'    from /opt/local/lib/ruby/gems/1.8/gems/activesupport-3.1.0/lib/active_support/dependencies.rb:181:in `const_missing'    from /opt/local/lib/ruby/gems/1.8/gems/activesupport-3.1.0/lib/active_support/dependencies.rb:179:in `each'    from /opt/local/lib/ruby/gems/1.8/gems/activesupport-3.1.0/lib/active_support/dependencies.rb:179:in `const_missing'    from (irb):8For some reason after I would tell the console to reload the models, I got anerror that the file didn’t define RetsMap::Base….but it did damnit!!The error was regarding ActiveSupport, so I tried to reinstall the Rails gemand ActiveSupport gem, but this didn’t help.The solution I had found was to upgrade to Rails 3.1.1. After doing this, theerror no longer occurred, even after I had reloaded the models.Ooh, also, I didn’t mention. Previously I was using the following command in/config/application.rb:config.autoload_paths += Dir["#{config.root}/app/models/**/"]As part of my troubleshooting I figured that by default Rails will try to loadmodels from subdirectories if they conform to the proper directory and filenaming required for namespaced models. When you add models to the autoloadpaths configuration, I think it expects that those conventions don’t apply..or maybe this just causes problems. I commented this line out and simply addedeach subdirectory that contained non-namespaced models.config.autoload_paths += %W(#{config.root}/app/models/email/)config.autoload_paths += %W(#{config.root}/app/models/sub/)config.autoload_paths += %W(#{config.root}/app/models/upload/)"
    } ,
  
    {
      "title"    : "Paperclip error with non-image file",
      "category" : "",
      "tags"     : "paperclip, identify, imagemagick, non-image",
      "url"      : "/2011/12/paperclip-error-with-non-image-file/",
      "date"     : "2011-12-05 16:43:25 -0800",
      "content"  : "Recently I updated to Rails 3.1 from 2.3.8 for a project I’m working on.Paperclip version 2.4.5 was working perfectly well for me locally on my Mac OSX 10.7.2 laptop, with ImageMagick version 6.7.3-1.We had just launched the upgraded Rails 3.1 application to our productionserver, which went smoothly, but upon my checklist of pages to test (we don’thave test suite in use yet) I noticed that the file upload was failing.Further investigation showed that the object using paperclip was failing tosave:upload.errors.inspect:#["/tmp/stream20111205-28441-10oj2ck-0.csv is not recognized by the 'identify' command.", "/tmp/stream20111205-28441-10oj2ck-0.csv is not recognized by the 'identify' command."]}&gt;, @base=#&gt;Further investigation helped me identify this ‘identify’ command as anexecutable provided by ImageMagick. I ran this command on the temporary filewhich was located in /tmp, and I got an error such as the one that follows onboth my local machine and in production. The odd thing was that the fileupload worked locally, but was failing remotely.$ identify test-import20111205-1909-1xsbr19-0.csvidentify: no decode delegate for this image format 'test-import20111205-1909-1xsbr19-0.csv' @ error/constitute.c/ReadImage/532.This didn’t make sense. I was uploading a CSV file, not an image. I wasn’teven using the ‘:styles’ hash value in my model with the ‘has_attached_file’expression. Why was it checking to see what type of image the file is?!?!I tried to upgrade and reinstall ImageMagick on the production server, butthis had no effect. This made me suspect that paperclip was the cause of theissue. I also created an initalizer for paperclip under/config/initalizers/paperclip.rb pointing out the image_magick_path, which Ihad seen resolve other issues with ‘identify’ errors.if Rails.env == 'production'  Paperclip.options[:image_magick_path] = "/usr/bin/"endThis didn’t help at all.I tried to reconfigure the application to use Paperclip version 2.4.4 and2.4.3, but that didn’t resolve the issue.Finally I updated my Gemfile to use the latest Github version of Paperclip. Ideployed this update, tested, and finally the issue was resolved.gem 'paperclip', "~&gt; 2.4.5", :git =&gt; 'git://github.com/thoughtbot/paperclip.git'"
    } ,
  
    {
      "title"    : "Issues with RVM",
      "category" : "",
      "tags"     : "rails, os x lion, rvm",
      "url"      : "/2011/11/issues-with-rvm/",
      "date"     : "2011-11-13 20:11:04 -0800",
      "content"  : "I recently decided to check out BrowserCMS, to evaluate how it work anddecide to use it…or RefineryCMS. I didn’t expect that BrowserCMS wouldrequire Ruby 1.9.2. I’ve been running with Ruby 1.8.6 or 1.8.7 for quite awhile now without any issues. It looks like it was time that I installRVM: Ruby Version Manager.I read through the documentation, followed the instructions to ensure thatprerequisite software was installed. I specifically made sure that certaincommands that it stated would be needed were all in my command line path under/opt/local, where the MacPorts all install. I try to maintain a command lineenvironment that’s almost entirely dependent on MacPorts. Prior to ensuringthis I ran into issues where software I’ve tried to install was using oneutility or library provided natively by Mac OS X, while using some otherutility or library I’ve installed separately, conflict due to differences andstop certain software from building properly upon install.I also took note that since I’m using MacPorts, I shouldconfigure my $HOME/.rvmrc file so that RVM uses my MacPort libraries whenbuilding gems.Installation of RubyThe installation of the RVM software itself went smoothly. I felt good knowingthat I was about to learn how RVM works and it will become another tool that Igladly assign to my arsenal of software to be used in the future (and add tomy resume).Then I ran into an issue with something in ‘readline.c’ when I attempted toinstall Ruby 1.8.7.jason@imac ~$ rvm install 1.8.7 --with-openssl-dir=/opt/localInstalling Ruby from source to: /Users/jason/.rvm/rubies/ruby-1.8.7-p352, this may take a while depending on your cpu(s)...ruby-1.8.7-p352 - #fetchingruby-1.8.7-p352 - #extracting ruby-1.8.7-p352 to /Users/jason/.rvm/src/ruby-1.8.7-p352ruby-1.8.7-p352 - #extracted to /Users/jason/.rvm/src/ruby-1.8.7-p352Applying patch 'stdout-rouge-fix' (located at /Users/jason/.rvm/patches/ruby/1.8.7/stdout-rouge-fix.patch)ruby-1.8.7-p352 - #configuringruby-1.8.7-p352 - #compilingERROR: Error running 'make ', please read /Users/jason/.rvm/log/ruby-1.8.7-p352/make.logERROR: There has been an error while running make. Halting the installation.jason@imac ~$ tail -10 /Users/jason/.rvm/log/ruby-1.8.7-p352/make.log...compiling readline/usr/bin/gcc-4.2 -I. -I../.. -I../../. -I../.././ext/readline -DHAVE_READLINE_READLINE_H -DHAVE_READLINE_HISTORY_H -DHAVE_RL_FILENAME_COMPLETION_FUNCTION -DHAVE_RL_COMPLETION_MATCHES -DHAVE_RL_DEPREP_TERM_FUNCTION -DHAVE_RL_COMPLETION_APPEND_CHARACTER -DHAVE_RL_BASIC_WORD_BREAK_CHARACTERS -DHAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS -DHAVE_RL_BASIC_QUOTE_CHARACTERS -DHAVE_RL_COMPLETER_QUOTE_CHARACTERS -DHAVE_RL_FILENAME_QUOTE_CHARACTERS -DHAVE_RL_ATTEMPTED_COMPLETION_OVER -DHAVE_RL_LIBRARY_VERSION -DHAVE_RL_EVENT_HOOK -DHAVE_RL_CLEANUP_AFTER_SIGNAL -DHAVE_REPLACE_HISTORY_ENTRY -DHAVE_REMOVE_HISTORY -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE  -I/opt/local/include -fno-common -arch x86_64 -g -Os -pipe -no-cpp-precomp  -fno-common -pipe -fno-common   -c readline.creadline.c: In function &amp;lsquo;username_completion_proc_call&amp;rsquo;:readline.c:730: error: &amp;lsquo;username_completion_function&amp;rsquo; undeclared (first use in this function)readline.c:730: error: (Each undeclared identifier is reported only oncereadline.c:730: error: for each function it appears in.)make[1]: *** [readline.o] Error 1make: *** [all] Error 1I tried to install ‘readline’ using MacPorts because I read online that thiswas a common issue with Mac OS X users under Snow Leopard. This didn’t help,and in fact I got an error after trying to install readline from source asrecommended in the forum post I found regarding the subject.After further search, I realized that the RVM documentation (which is prettygood I must say) has a page devoted to this issue.Issue Installing Custom GemsLater I had installed Ruby 1.9.2 as well, because I needed it for BrowserCMS.I was trying to install gems for Ruby, but each time it would give me the‘Invalid gemspec … invalid date format in specification’ error that I recallfrom a time when I was using a newer version of RubyGems than the gems I hadinstalled were made for, like:Invalid gemspec in [/opt/local/lib/ruby/gems/1.8/specifications/paperclip-2.4.3.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"I made sure I was running under Ruby 1.9.2, and that the version of RubyGemswould be the one associated with Ruby version 1.9.2, and then upgraded it toversionimac:Sites jason$ rvm 1.9.2imac:Sites jason$ rvm gemdir/Users/jason/.rvm/gems/ruby-1.9.2-p290imac:Sites jason$ rvm rubygems currentRemoving old Rubygems files...Installing rubygems-1.8.10 for ruby-1.9.2-p290 ...Installation of rubygems completed successfully.I tried to check or change which version of gem I was using, and it would tellme it’s using one installed under RVM, but still it would give errors as if itwas using an older version of RubyGems.imac:Sites jason$ which gem/Users/jason/.rvm/rubies/ruby-1.9.2-p290/bin/gemimac:Sites jason$ sudo gem install browsercmsInvalid gemspec in [/opt/local/lib/ruby/gems/1.8/specifications/capistrano-2.9.0.gemspec]: invalid date format in specification: "2011-09-24 00:00:00.000000000Z"I then found out that I had a .gemrc file setup that was loading in my commandline environment, and thus interfering with the dependency loading which RVMprovides.imac:Sites jason$ cd ~imac:~ jason$ cat .gemrcgemhome: /opt/local/lib/ruby/gems/1.8gempath: - /opt/local/lib/ruby/gems/1.8 - /Users/jason/gemsimac:~ jason$I simply renamed this file as .gemrc.bak and this resolved the issue so thatgems I install under Ruby v1.9.2 will use the RubyGem version associated withthe Ruby 1.9.2 installation."
    } ,
  
    {
      "title"    : "Setting up Ubuntu for Rails App via Passenger",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/setting-up-ubuntu-for-rails-app-via-passenger/",
      "date"     : "2011-10-29 22:11:11 -0700",
      "content"  : "These instructions apply to Ubuntu 11.04 (natty).Run the following to install Ruby, the Apache2 web server, Curl DevelopmentHeaders with SSL Support.sudo apt-get updatesudo apt-get install build-essentialsudo apt-get install ruby ruby1.8-devsudo apt-get install apache2 apache2-mpm-prefork apache2-prefork-dev libcurl4-openssl-devNext download Ruby Gems, extract the package, install Ruby Gems, and thencreate a symbolic link from /usr/bin/gem1.8 to /usr/bin/gemcd ~wget http://rubyforge.org/frs/download.php/75309/rubygems-1.8.10.tgztar -zxvf rubygems-1.8.10.tgzcd rubygems-1.8.10sudo ruby setup.rbln -s /usr/bin/gem1.8 /usr/bin/gemWith Ruby Gems installed we can install the Passenger gem.sudo gem install passengerNow we can run the installation of Passenger for Apache2.passenger-install-apache2-moduleAt the end of the build the installation instructions tell you to addsomething like the following to your Apache configuration file.LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-3.0.9/ext/apache2/mod_passenger.soPassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-3.0.9PassengerRuby /usr/bin/ruby1.8Do this by copying the commands, then pasting them into /etc/apache2/modsavailable/passenger.loadsudo nano /etc/apache2/mods-available/passenger.loadAfter saving the file, run the following commands to load the module andrestart the Apache web server.a2enmod passenger/etc/init.d/apache2 restartNow you can create a virtual host file for your site under/etc/apache2/sites-availablesudo nano /etc/apache2/sites-available/yoursite.comThen setup this virtualhost file to load and tell Apache to reload theconfigurationa2ensite yoursite.com/etc/init.d/apache2 reloadFor your application to run you’ll need to install the Rails gem of course.sudo gem install rails"
    } ,
  
    {
      "title"    : "Formtastic use of semantic_form_remote_for",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/formtastic-use-of-semantic-form-remote-for/",
      "date"     : "2011-10-20 15:29:02 -0700",
      "content"  : "With the update to Formtastic version 2.0.0.rc1 the ‘semantic_remote_form_for’method was removed and support was added to ‘remote_form_for’ used like this:&lt;%= semantic_form_for @contact, :remote =&gt; true, :url =&gt; '/contact' do |f| %&gt;This is to conform with the new Rails 3 update where form_remote_for isreplaced with form_for with a remote hash value passed to it as an argument."
    } ,
  
    {
      "title"    : "Exporting Routes in Rails 3",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/exporting-routes-rails/",
      "date"     : "2011-10-20 14:36:54 -0700",
      "content"  : "I’m currently upgrading a project I’m working on from Rails 2.3.8 to Rails 3.1.As part of this upgrade I need to test the entire application for issues,because we haven’t actually written any tests.To help with this, I’d like to export all the routes so that I can test themone by one, and keep track of what I’ve tested and fixed already.Typically I output the routes by using this command from the root of the Railsapp:rake routesIn this case I want to export all the routes into a format which I can post toour wiki as a table. This will require a custom script, but I’m not sure howRails 3 internally stores routes.As a start I found that rake will reveal the source of the ‘routes’ task usingthis command$ rake --where routesrake rails:upgrade:routes           /Users/jason/myapp/vendor/plugins/rails_upgrade/lib/tasks/rails_upgrade_tasks.rake:27rake routes                         /opt/local/lib/ruby/gems/1.8/gems/railties-3.1.0/lib/rails/tasks/routes.rake:2So it appears that what I’m looking for is in/opt/local/lib/ruby/gems/1.8/gems/railties-3.1.0/lib/rails/tasks/routes.rake.I’ve modified this task and added it to my application under/lib/tasks/routes.rake like so:namespace :routes do  desc 'Print out all defined routes in CSV format. Target specific controller with CONTROLLER=x.'  task :csv =&gt; :environment do    Rails.application.reload_routes!    all_routes = Rails.application.routes.routes    if ENV['CONTROLLER']      all_routes = all_routes.select do |route|        route.defaults[:controller] == ENV['CONTROLLER']      end    end    routes = all_routes.collect do |route|      reqs = route.requirements.dup      reqs[:to] = route.app unless route.app.class.name.to_s =~ /^ActionDispatch::Routing/      reqs = reqs.empty? ? "" : reqs.inspect      {:name =&gt; route.name.to_s, :verb =&gt; route.verb.to_s, :path =&gt; route.path, :controller =&gt; route.requirements[:controller], :action =&gt; route.requirements[:action]}    end     # Skip the route if it's internal info route    routes.reject! { |r| r[:path] =~ %r{/rails/info/properties|^/assets} }    # name_width = routes.map{ |r| r[:name].length }.max    # verb_width = routes.map{ |r| r[:verb].length }.max    # path_width = routes.map{ |r| r[:path].length }.max    puts "controller,action,method,path,name"    routes.each do |r|      puts "#{r[:controller]},#{r[:action]},#{r[:verb]},#{r[:path]},#{r[:name]}"    end  endendI can create a CSV file on my desktop, which contains all my routes by simplyrunning this command now:$ rake routes:csv &gt; ~/Desktop/rake-routes.csv"
    } ,
  
    {
      "title"    : "Using URL Helpers in Models or Rake Tasks",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/using-url-helpers-models-or-rake-tasks/",
      "date"     : "2011-10-19 16:41:51 -0700",
      "content"  : "If for some reason you need to use URL helpers which are based on the routesyou’ve defined in Rails 3.1, simply add the following to the model method orrake task:include Appname::Application.routes.url_helpersMake sure you replace ‘Appname’ with the name of your app, which should be thesame name as the root folder for your application. You can also obtain it from/config/application.rb where it is defined like so:module Appname  class Application &lt; Rails::Application  endendIf you’re needing to render a partial inside of a rake task with Rails 3, youcould try using the solution suggested in this article. I had to do thisand I pulled it off by adding the include above to the OfflineTemplate class,and then using this code:Appname::Application.routes.default_url_options = {  :host =&gt; 'www.mydomain.com'}template = OfflineTemplate.newpartial_results_html = template.render_to_string(  :partial =&gt; "shared/search_results_email_html",  :object =&gt; search_object,  :format =&gt; :html)"
    } ,
  
    {
      "title"    : "Building a Query String from a Hash with Rails 3",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/building-query-string-from-hash-rails/",
      "date"     : "2011-10-19 14:35:09 -0700",
      "content"  : "I have a model has a method that generates and stores a cached link to it’sown view for use in mailers. Under Rails 2 the method which generated thislink created the beginning of the URL based on the owner of the object (thisis a multi-domain system I’m working on), however it required that a hash ofparameters be included in the link.Under Rails 2 the ‘options’ hash would be passed to build_query_string insideof my method like so:params = ActionController::Routing::Route.new.build_query_string(options)Under Rails 3 I receive this error:wrong number of arguments (0 for 7)It turns out that under Rails 3 the Hash library includes a to_query method.irb(main):001:0&gt; h = {:blah =&gt; '1', :blah2 =&gt; '2'}=&gt; {:blah=&gt;"1", :blah2=&gt;"2"}irb(main):002:0&gt; h.to_query=&gt; "blah2=2&amp;amp;blah=1"Thanks to mjrussel for posting this on StackOverflow."
    } ,
  
    {
      "title"    : "Rails 3 Autoloading with Namespaced Models",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/rails-autoloading-namespaced-models/",
      "date"     : "2011-10-18 15:50:03 -0700",
      "content"  : "I’m working through an upgrade from Rails 2.3.8 to Rails 3.1, and a set ofname spaced models that I setup are giving errors when I run a certain Raketask that relies on them. I looked into the issue and it appears that I needto learn the way Rails 3 loads models.In /config/application.rb I’m using the following line to auto load allmodels from /app/models and any subdirectories.config.autoload_paths += Dir["#{config.root}/app/models/**/"]For this to work I found that I needed to understand how Rails 3 interpretsthe folder and filenames. Some models weren’t even registering as available,so I created folders for each class and put their files under each folder.This seemed to resolve some errors, but then I was receiving errors when Iwould try to instantiate a new object from one of the defined classes in theRails console:NoMethodError: undefined method `new' for RetsMap::Sys_Local::Res_property::Class_1:ModuleIn my case RetsMap::Sys_Local::Res_property inherits from RetsMap::Base, andRetsMap::Sys_Local::Res_property::Class_1 inherits fromRetsMap::Sys_Local::Res_property. I then tried to see why I was receiving thismention of ‘Module’ at the end of my ‘Class_1’ by starting with RetsMap::Base.irb(main):001:0&gt; RetsMap.class=&gt; Moduleirb(main):002:0&gt; RetsMap::Base=&gt; RetsMap::Baseirb(main):003:0&gt; RetsMap::Base.class=&gt; ModuleSure enough this showed that Rails was interpreting my class as a module.Since these sub-classes inherit from RetsMap::Base, which is loading as aModule, I figured that I needed to start there. I moved the file which definedthe class from /app/models/rets_map/base/ folder to/app/models/rets_map/base.rb and this caused the class to load as a class.irb(main):005:0&gt; RetsMap.class=&gt; Moduleirb(main):006:0&gt; RetsMap::Base.class=&gt; ClassI take it that this means that the folders are meant to store modules, withthe files representing the classes. At the same time, a subdirectory must becreated for each subsequent namespace or else you’ll receive an error that itwas expecting the file to define itself in the namespace of the folder itbelongs to. If you create a file in a directory with the same name as thedirectory, it can define a class for that namespace instead of being loaded asa module."
    } ,
  
    {
      "title"    : "Form Fields not Displaying with Formtastic",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/form-fields-not-displaying-formtastic/",
      "date"     : "2011-10-18 10:48:34 -0700",
      "content"  : "The Rails project I’m currently working on uses Formtastic, a Rails form builder plugin. The projects description says “Formtastic is a RailsFormBuilder DSL (with some other goodies) to make it far easier to createbeautiful, semantically rich, syntactically awesome, readily stylable andwonderfully accessible HTML forms in your Rails applications.” I wasn’t surewhat DSL means, but found in the projects wiki on the About page that itstands for Domain Specific Language.So I’m currently upgrading from Rails 2.3.8 to Rails 3.1, and I found that the form fields were not showing for the pages using the Formtastic semantic_form_for code blocks. I updated my own code so that the equal sign is included after the opening Ruby code tag in the views such as:&lt;%= semantic_form_for @product do |f| %&gt;… instead of …&lt;% semantic_form_for @product do |f| %&gt;This was one of the first steps I performed as advised by the rails 3 upgrade instructions. I just now realized however that inside of the code block are other code blocks for the form fields and the submit button. These too must include the equal sign, which was the reason why my form fields were not displaying.&lt;%= f.inputs :name =&gt; "Author", :for =&gt; :author do |author_form| %&gt;  &lt;%= author_form.input :first_name %&gt;  &lt;%= author_form.input :last_name %&gt;&lt;% end %&gt;&lt;%= f.buttons do %&gt;  &lt;%= f.commit_button %&gt;&lt;% end %&gt;"
    } ,
  
    {
      "title"    : "Adding Event Listeners to Google-Maps-for-Rails Markers",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/10/adding-event-listeners-to-google-maps-for-rails-markers/",
      "date"     : "2011-10-11 11:24:27 -0700",
      "content"  : "I’m currently working on a Ruby on Rails project that was setup under Rails 2,and we’re upgrading it to Rails 3 via a separate branch.We were using a gem called Eschatonto provide Google Maps on certain pages of the website, but it appears thatEschaton is abandoned and actually going to be deleted on October 31, 2011.Because of this I forked the project under my own Github account.After looking around for a suitable replacement we decided onGoogle-Maps-for-Rails, version (1.3.0). Previously with Eschaton we hadjQuery code associated with event listeners that were triggered when themarkers on the map are selected. When selected the items being plotted on themap, which are displayed to the left of the map, were highlighted using CSSafter being clicked on, and page also scrolled down to the item selected onthe map. To reproduce this we need to tie events to the markers using GoogleMaps for Rails (gmaps4rails).After some searching and testing I found this to be the solution. The‘content_for :scripts’ container ensures that the Javascript is inserted inthe bottom of the page via the ‘&lt;%= yield :scripts %&gt;’ that is placed inyour layout. The Javascript is also outputted at the bottom of the page AFTERthe Javascript which the gem outputs that initializes and loads the Google Map.&lt;%= gmaps4rails(@json) %&gt;&lt;% content_for :scripts do %&gt;	&lt;script type="text/javascript" charset="utf-8"&gt;		Gmaps.map.callback = function() {			for (var i = 0; i &lt;  Gmaps.map.markers.length; ++i) {				google.maps.event.addListener(Gmaps.map.markers[i].serviceObject, 'click', function(object) { 					alert('lat: '+object.latLng.Na+' long: '+object.latLng.Oa);				});			}		}	&lt;/script&gt;&lt;% end %&gt;After further coding I found that I needed to reference the MySQL ID of eachof the objects, which is included in the ID of each element on the page. Iupdated my controller to use the following so that the MySQL ID would beavailable in the JSON:@json = @properties.to_gmaps4rails do |property|  "\"id\": \"#{property[0].id}\""endI then needed to figure out how to pass this ID to the function that is passedto the ‘google.maps.event.addListener’. I did this like so:&lt;%= gmaps4rails(@json) %&gt;&lt;% content_for :scripts do %&gt;	&lt;script type="text/javascript" charset="utf-8"&gt;		Gmaps.map.callback = function() {			for (var i = 0; i &lt;  Gmaps.map.markers.length; ++i) {				var marker = Gmaps.map.markers[i].serviceObject				marker.marker_id = Gmaps.map.markers[i].id;				google.maps.event.addListener(marker, 'click', function() {					alert('marker id: '+this.marker_id);				});			}		}	&lt;/script&gt;&lt;% end %&gt;"
    } ,
  
    {
      "title"    : "Issues with Bluetooth in OS X Lion after Upgrade",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/09/issues-with-bluetooth-in-os-x-lion-after-upgrade/",
      "date"     : "2011-09-28 19:08:39 -0700",
      "content"  : "I recently upgraded from OS X Lion (10.7.1) from Snow Leopard so that I couldbe up-to-date and benefit from any good features. Truthfully I liked the oldExpose and Spaces better than this new Mission Control interface for virtualdesktops…but oh well it will do.After upgrading to Lion the one thing that has been most frustrating is thatmy Bluetooth headset doesn’t work anymore. It syncs up with my MacBook Pro,but it doesn’t send audio from the mic nor does it playback audio. I’m using aVXI BlueParrott B250-XT.I’m referring to the instructions on this page to resolve the issue whichare:  Don’t have Power Management configuration issue causing bluetooth option tonot be present.  Unplugged USB devices  Ran Applications &gt; Utilities &gt; Disk Utility and ran a ‘Repair DiskPermissions’ on my primary drive.  Deleted user preference files for Bluetooth(~/Library/Preferences/com.apple.Bluetooth and~/Library/Preferences/com.apple.Bluetooth.plist)  Reset PRAM  Reset Power Management System  Opened Bluetooth Explorer -&gt; Utilities Menu -&gt; Modify Software andDevice Configuration -&gt; Checked:          ‘Recant’ Connected Apple HID Devices      ‘Full Factory Reset’ connected Apple HID devices      Delete link keys from the Bluetooth module      Delete global bluetooth preference file (/L/P/com.apple.Bluetooth.plist)      Remove all favorite devices      Unconfigure all ‘configured’ devices      Restart the Bluetooth daemon (‘blued’) process      This all did not resolve my issue. I then thought to myself, well…the deviceis pairing and connecting. Perhaps it’s a sound issue. I then proceeded tofind some sort of forum post or article explaining how to reset thesound/audio settings which might be corrupted since upgrading to OS X Lion….I’ll update this post once I troubleshoot further."
    } ,
  
    {
      "title"    : "Redirect_to not working",
      "category" : "",
      "tags"     : "http post",
      "url"      : "/2011/09/redirect_to-not-working/",
      "date"     : "2011-09-27 16:37:59 -0700",
      "content"  : "I was just working on a Ruby on Rails controller method that receivesinformation from the previous form via HTTP POST. I coded it so that ifcertain form variables weren’t present it would set a flash message andredirect to the form page. I tried and tried and still the redirect wasn’tworking. I reset my web server, and even restarted my computer, but stil thisdidn’t resolve the issue.I then realized that perhaps redirects aren’t possible with HTTP POST’s, onlyGET requests. I ended up just creating a generic view for displaying errors,and will render that view and then ‘return FALSE’ inside of the if statementwhen an error is detected."
    } ,
  
    {
      "title"    : "Advanced Use of Will_Paginate",
      "category" : "",
      "tags"     : "rails, pagination, will_paginate",
      "url"      : "/2011/09/advanced-use-of-will_paginate/",
      "date"     : "2011-09-23 18:08:56 -0700",
      "content"  : "I’m building an index of contacts, displayed with paginated links provided by will_paginate.The wiki for this plugin advises you on how to do setup your controllermethod, and what to put in the view to obtain a simple set of links, such as:# /app/controllers/contact_controller.rbdef index  @contacts = Contact.paginate :page =&gt; params[:page], :per_page =&gt; 10, :order =&gt; 'created_at DESC'end&lt;!-- /app/views/contact/index.html.erb --&gt;&lt;%= will_paginate @contacts %&gt;What I’m not finding however are more advanced methods of using thewill_paginate plugin. Here are a few things I’ve found.Links at top and bottom of paginated sectionYou can add the paginated links to the top and bottom of your paginatedsection using this syntax:&lt;% paginated_section @contacts do %&gt;  &lt;table id="contacts"&gt;    &lt;%= render(:partial =&gt; "contact_row", :collection =&gt; @contacts) %&gt;  &lt;/table&gt;&lt;% end %&gt;Display Page Entries InfoYou can display text on your page such as ‘Displaying contacts11 - 12 of 12 in total’ by using the following view helper.&lt;%= page_entries_info @contacts %&gt;Current and Total Page NumberIf you want to display the total number of pages in your own way, you can dothis by using the ‘total_pages’ method of the paginated collection.You are viewing page &lt;%= @contacts.current_page %&gt;of &lt;%= @contacts.total_pages %&gt;"
    } ,
  
    {
      "title"    : "Getting File object for Paperclip Attachment via S3",
      "category" : "",
      "tags"     : "rails, csv, paperclip, s3",
      "url"      : "/2011/09/getting-file-object-for-paperclip-attachment-via-s3/",
      "date"     : "2011-09-22 15:34:10 -0700",
      "content"  : "I’m working on a project where we are using the Paperclip plugin for Ruby onRails for file handling and associations with other models.I’m working on a CSV import option right now, using this tutorial to helpme get a head start on how to break the contents of the file up into rows andcolumns. I’m not passing the file directly from a form to the controllermethod, but I’m opening the file that has already been saved after beinguploaded via AJAX.I couldn’t find out how I would get the file itself into an object that I canpass to the parser like so:@parsed_file=CSV::Reader.parse(params[:dump][:file])It turns out that you simply need to refer to the Paperclip attachment andthen use ‘to_file’ like so:require 'csv'@upload = Upload.find(params[:upload_id])@parsed_file = CSV::Reader.parse(@upload.attachment.to_file)"
    } ,
  
    {
      "title"    : "Issues with MacPorts After Upgrading to OS X Lion",
      "category" : "",
      "tags"     : "macports",
      "url"      : "/2011/09/issues-with-macports-after-upgrading-to-os-x-lion/",
      "date"     : "2011-09-16 18:10:00 -0700",
      "content"  : "I realized this morning that I was having dependency issues with ImageMagickon my Mac, which I installed using MacPorts. I had recently upgraded toMac OS X Lion, so it made sense that I needed to update the software toresolve the issues, much like I had when I upgraded to Snow Leopard.I found this article that provided steps for migrating MacPorts for Lion,but I kept getting this error when I tried to uninstall all the packages:warning: Failed to execute portfile from registry for apache2@2.2.17_1+preforkmpm too many nested evaluations (infinite loop?)Warning: Failed to execute portfile from registry for apache2@2.2.17_1+preforkmpm too many nested evaluations (infinite loop?)Warning: Failed to execute portfile from registry for apache2@2.2.17_1+preforkmpm too many nested evaluations (infinite loop?)Warning: Failed to execute portfile from registry for apache2@2.2.17_1+preforkmpm too many nested evaluations (infinite loop?)I searched and searched for a solution, and even tried to uninstall apache2@2.2.17_1+preformkmpm, but it told me that apache2 @2.2.17_1+preformkmpmdepends on itself, and that I should uninstall it. Obviously that wasn’tpossible.Finally I found the migration guide provided by the MacPorts website,which instructed me to install the new MacPorts for OS X Lion before removingand reinstalling the packages. I downloaded the DMG file for MacPorts(MacPorts-2.0.3-10.7-Lion), installed it, and then the packages uninstalledwithout any issues."
    } ,
  
    {
      "title"    : "Error: &#39;unintitialized constant MySQL&#39; with Rails 3 on Snow Leopard Mac",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/05/error-unintitialized-constant-mysql-with-rails-3-on-snow-leopard-mac/",
      "date"     : "2011-05-19 23:05:08 -0700",
      "content"  : "I just installed Rails 3 on my iMac, which is running Snow Leopard. I’m tryingto build a web hosting website/billing system/management system. I configuredthe app to use MySQL in /config/database.yml like so:development:  adapter: mysql  encoding: utf8  database: hosting_development  username: root  password:  host: 127.0.0.1I had to do this because I created the Rails app without specifying that Ididn’t  want sqlite3. I then ran rake db:create and I got this error:rake aborted!uninitialized constant MysqlI found an article online which advised to do the follow, with theexception of the path to mysql_config. I’m using MacPorts for most of thepackages in my development environment.$ sudo gem uninstall mysql$ sudo env ARCHFLAGS="-arch x86_64" gem install mysql ----with-mysql-config=/opt/local/lib/mysql5/bin/mysql_configI then modified the Gemfile in my app with the following. I think this mighthave been what was needed most, not the gem reinstallation. I forgot to dothis until right before it was fixed.# gem 'sqlite3'gem 'mysql'"
    } ,
  
    {
      "title"    : "Installing PHPdoc for Ubuntu for use with Command Line",
      "category" : "",
      "tags"     : "",
      "url"      : "/2011/05/installing-phpdoc-for-ubuntu/",
      "date"     : "2011-05-18 20:21:45 -0700",
      "content"  : "I wanted to install PhpDocumentor for use on my server so that I couldgenerate documentation from the command line. I found this article, whichinstructed me to somehow change the PEAR setting for data_dir. I installedPhpDocumentor in my web root and it just didn’t work and gave me a bunch oferrors in the browser.I uninstalled the package via PEAR (ala ‘pear uninstall phpdocumentor’command), then deleted the folder. I just wanted to install it in the properpath so that it’s available from the command line using ‘phpdoc’.I downloaded the source of PhpDocumentor directly from SourceForge, and it hadphpdoc available in the folder, but I’m not sure which folder to put it in sothat it’s in my path for the command line.Finally I just reset the ‘data_dir’ setting back to the default by using thiscommand:$ sudo pear config-set data_dir /usr/share/php/dataNext I installed the package again via PEAR, just like I should have originallydone.$ sudo pear upgrade PhpDocumentorThis worked like a charm.$ which phpdoc/usr/bin/phpdoc"
    } ,
  
    {
      "title"    : "Ruby on Rails session - Access from PHP",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/12/ruby-on-rails-session-access-from-php/",
      "date"     : "2010-12-14 00:25:37 -0800",
      "content"  : "If you need to access a Ruby on Rails session from a PHP application runningunder the same domain, you can do this by splitting the string in the cookieby the ‘–’. Thanks to Frederick Cheung for pointing this out.Here is coding I added to my PHP script which was running from a path underthe same domain. Unfortunately the data returned is in Marshal format, andthere isn’t a Marshal.load function for PHP to get the values easily.$raw_session_string = $_COOKIE['_app_session'];$data_split = explode ('--' , $raw_session_string);$encoded_session = $data_split[0];$marshal_data = base64_decode($encoded_session);echo "&lt;pre&gt;marshal_data:". print_r($marshal_data,1) ."&lt;/pre&gt;\n";"
    } ,
  
    {
      "title"    : "Obtaining Request Domain Name for Ruby on Rails",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/10/obtaining-request-domain-name-for-ruby-on-rails/",
      "date"     : "2010-10-12 01:19:16 -0700",
      "content"  : "I’m using Rails 2.3.8. To obtain the domain name for the website beingrequested (i.e. mysite.com, mysite.net), just reference ‘request.host’.ruby@host = request.hostYou can only reference request.host in the views, or the controller."
    } ,
  
    {
      "title"    : "Changing Column Order via ActiveRecord Migration",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/08/changing-column-order-via-activerecord-migration/",
      "date"     : "2010-08-15 22:09:40 -0700",
      "content"  : "Is it possible to change the order of the columns in your MySQL (or other database) table using a migration? Lets see.If you check the ActiveRecord::Migration documentation you’ll see there is a method called ‘change_column’ which accepts various options.&lt;tt&gt;change_column(table_name, column_name, type, options)&lt;/tt&gt;:Changes the column to a different type using the same parameters as add_columnAs of Rails 2.3.6 this is now available by using the :after option. You’llhave to include the field type, even though you are not modifying the type.Example:change_column :orders, :tax_rate, :float, :after =&gt; :tax_state"
    } ,
  
    {
      "title"    : "Rails Performance Statistics",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/08/rails-performance-statistics/",
      "date"     : "2010-08-09 02:26:40 -0700",
      "content"  : "Again, as I search for things, I stumble onto new tools. I just found outabout a tool for monitoring the performance of Java and Ruby applicationscalled New Relic.They provide a free service level for Startups and Students even."
    } ,
  
    {
      "title"    : "RailRoad Gem",
      "category" : "",
      "tags"     : "diagram, models, activerecord",
      "url"      : "/2010/08/railroad/",
      "date"     : "2010-08-09 02:07:44 -0700",
      "content"  : "I just discovered that there is a Ruby gem which generates diagrams based onRails models (ActiveRecord). I ran across this website a while back, butdidn’t quite connect the dots. I was just reading an article on placingmodels into their own namespace, and I realized that the diagram it uses as anexample was generated using RailRoad.http://railroad.rubyforge.org/"
    } ,
  
    {
      "title"    : "Annotate Models",
      "category" : "",
      "tags"     : "rails, plugin",
      "url"      : "/2010/08/annotate-models/",
      "date"     : "2010-08-07 22:02:30 -0700",
      "content"  : "There is a rails plugin which adds schema information for the models incomments at the top of your model definition files. It’s really useful. Checkout the instructions on installing and using this plugin at:http://pragdave.pragprog.com/pragdave/2006/02/annotate_models.html"
    } ,
  
    {
      "title"    : "Selenium RC, Firefox 3, and Ubuntu",
      "category" : "",
      "tags"     : "linkedin",
      "url"      : "/2010/07/selenium-rc-firefox-3-and-ubuntu/",
      "date"     : "2010-07-29 18:46:26 -0700",
      "content"  : "I’ve got a system setup which uses Firefox on an Ubuntu machine, with theSelenium RC server (remote control). I had a set of scripts which would runautomatically every 15 minutes, which would prompt Firefox to open and go tothe site and submit certain forms. This stopped working after I ran an updateon some packages in my Ubuntu machine (9.04 Jaunty).I was able to resolve this issue by upgrading fromSelenium RC 1.0.1 to 1.0.3."
    } ,
  
    {
      "title"    : "Undefined method &#39;ref&#39; for ActiveSupport::Dependencies:Module",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/07/unable-to-run-rails-migrations-mysql-gem-on-snow-leopard/",
      "date"     : "2010-07-27 10:19:01 -0700",
      "content"  : "After upgrading to Snow Leopard, and trying to run ‘rake db:migrate’, Ireceived this error once. This seems common to others which have upgraded,especially back when Snow Leopard was released in August of 2009:rake aborted!uninitialized constant MysqlCompat::MysqlRes(See full trace by running task with --trace)I’ve tried to troubleshoot by reinstalling the MySQL gem, and the 64 bitversion of the MySQL server. I’m no longer receiving this error above.When installing the MySQL Gem, I receive a bunch of errors, unless I specifyto not install documentation.$ sudo env ARCHFLAGS="-arch x86_64" gem install mysql -- --with-mysql-config=/opt/local/lib/mysql5/bin/mysql_configBuilding native extensions.  This could take a while...Successfully installed mysql-2.8.11 gem installedInstalling ri documentation for mysql-2.8.1...No definition for next_resultNo definition for field_nameNo definition for field_tableNo definition for field_defNo definition for field_typeNo definition for field_lengthNo definition for field_max_lengthNo definition for field_flagsNo definition for field_decimalsNo definition for time_inspectNo definition for time_to_sNo definition for time_get_yearNo definition for time_get_monthNo definition for time_get_dayNo definition for time_get_hourNo definition for time_get_minuteNo definition for time_get_secondNo definition for time_get_negNo definition for time_get_second_partNo definition for time_set_yearNo definition for time_set_monthNo definition for time_set_dayNo definition for time_set_hourNo definition for time_set_minuteNo definition for time_set_secondNo definition for time_set_negNo definition for time_set_second_partNo definition for time_equalNo definition for error_errnoNo definition for error_sqlstateInstalling RDoc documentation for mysql-2.8.1...No definition for next_resultNo definition for field_nameNo definition for field_tableNo definition for field_defNo definition for field_typeNo definition for field_lengthNo definition for field_max_lengthNo definition for field_flagsNo definition for field_decimalsNo definition for time_inspectNo definition for time_to_sNo definition for time_get_yearNo definition for time_get_monthNo definition for time_get_dayNo definition for time_get_hourNo definition for time_get_minuteNo definition for time_get_secondNo definition for time_get_negNo definition for time_get_second_partNo definition for time_set_yearNo definition for time_set_monthNo definition for time_set_dayNo definition for time_set_hourNo definition for time_set_minuteNo definition for time_set_secondNo definition for time_set_negNo definition for time_set_second_partNo definition for time_equalNo definition for error_errnoNo definition for error_sqlstateI’ve realized that these errors don’t occur if you try to install withoutdocumentation included.$ sudo env ARCHFLAGS="-arch x86_64" gem install mysql --no-ri --no-rdoc ----with-mysql-config=/opt/local/lib/mysql5/bin/mysql_configBuilding native extensions.  This could take a while...Successfully installed mysql-2.8.11 gem installedI doubted if this really was a successful installation due to the errors whenincluding the documentation, but this isn’t the case.You’ll notice that I’m running MySQL from the installation location in/opt/local/lib/mysql5/. This is because I’m using MacPorts, and I definitely donot want to try to run from a mixed environment with some executables and gemsbeing installed under my system folders and library locations, and othersunder the location of the folders where MacPorts installs these things. Why?Because I read that some people have had problems with 32 bit versions of somelibraries and executables still being installed and this causing dependencyconflicts. I’m needing certain packages provided by MacPorts, so I’m trying toensure that my entire environment is based on MacPort packages.jason-imac:bin jason$ file `which ruby`/opt/local/bin/ruby: Mach-O 64-bit executable x86_64jason-imac:bin jason$ file `which mysql`/opt/local/bin/mysql: Mach-O 64-bit executable x86_64I’ve completely uninstalled all the gems I had installed. I’m only working onone new project, so luckily I have no dependencies on all these old gems. Ieven removed all the gems which came with the system by default. Now all thegems are installed based on the MacPorts version of Ruby I’m running.$ sudo gem list -d | grep Installed    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8    Installed at: /opt/local/lib/ruby/gems/1.8When I run a migration I still received an error. I doubted that the MySQL gemis installed properly, but this I can’t be completely sure of. No one else hasreported this error, so I’m really stuck.$ rake db:migrate(in /Users/jason/rj4)rake aborted!undefined method `ref' for ActiveSupport::Dependencies:Module(See full trace by running task with --trace)Finally I realized that this error was the result of some issue with theDevise gem which my co-worker installed for user authentication. I found thisGoogle Groups posting about the same error.I installed devise version 1.0.8 and this resolved the issue.$ sudo gem install devise -v=1.0.8Successfully installed devise-1.0.81 gem installedInstalling ri documentation for devise-1.0.8...Installing RDoc documentation for devise-1.0.8...$ rake db:migrate(in /Users/jason/rj4)rake aborted!Unknown database 'rj4_development'(See full trace by running task with --trace)$ rake db:create(in /Users/jason/rj4)$ rake db:migrate(in /Users/jason/rj4)==  CreateProperties: migrating ===============================================-- create_table(:properties)   -&gt; 0.0712s==  CreateProperties: migrated (0.0713s) ========================================  CreateUsers: migrating ====================================================-- create_table(:users)   -&gt; 0.0967s==  CreateUsers: migrated (0.0969s) ==========================================="
    } ,
  
    {
      "title"    : "Setting up Deployment for Rails using Capistrano, Apache with Passenger and Git",
      "category" : "",
      "tags"     : "rails, capistrano, git, passenger",
      "url"      : "/2010/07/setting-up-deployment-for-rails-using-capistrano-apache-with-passenger-and-git/",
      "date"     : "2010-07-20 23:48:23 -0700",
      "content"  : "I don’t have time right now to learn how to setup Capistrano. I just want arecipe that works and does the job. Here are my notes.1) First install the Capistrano gemsudo gem install capistrano2) Next you need to go into the directory of your Ruby on Rails applicationand capify it:capify .3) Next I recommend this article (I’ll rip off the deploy.rb soon and post ithere)Capistrano Deploy with Git and Passenger4) Once you’ve configured your deploy.rb, run this command to have it setupthe directories on the remote server (releases, shared, logs, etc).cap deploy:setup5) Next run this command to get the list of other capistrano commands you canrun:cap -TThe output should look likecap deploy               # Deploys your project.cap deploy:check         # Test deployment dependencies.cap deploy:cleanup       # Clean up old releases.cap deploy:cold          # Deploys and starts a `cold' application.cap deploy:migrate       # Run the migrate rake task.cap deploy:migrations    # Deploy and run pending migrations.cap deploy:pending       # Displays the commits since your last deploy.cap deploy:pending:diff  # Displays the `diff' since your last deploy.cap deploy:restart       # Restarting mod_rails with restart.txtcap deploy:rollback      # Rolls back to a previous version and restarts.cap deploy:rollback:code # Rolls back to the previously deployed version.cap deploy:setup         # Prepares one or more servers for deployment.cap deploy:start         # start task is a no-op with mod_railscap deploy:stop          # stop task is a no-op with mod_railscap deploy:symlink       # Updates the symlink to the most recently deployed ...cap deploy:update        # Copies your project and updates the symlink.cap deploy:update_code   # Copies your project to the remote servers.cap deploy:upload        # Copy files to the currently deployed version.cap deploy:web:disable   # Present a maintenance page to visitors.cap deploy:web:enable    # Makes the application web-accessible again.cap invoke               # Invoke a single command on the remote servers.cap shell                # Begin an interactive Capistrano session."
    } ,
  
    {
      "title"    : "Rake Tasks",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/07/rake-tasks/",
      "date"     : "2010-07-16 17:37:56 -0700",
      "content"  : "If you’re wanting to know which Rake tasks are available for you to use fromthe command line, simply use the ‘rake -T’ command:$ rake -T(in /Users/jason/railsproject)rake db:abort_if_pending_migrations       # Raises an error if there are pending migrationsrake db:charset                           # Retrieves the charset for the current environment's databaserake db:collation                         # Retrieves the collation for the current environment's databaserake db:create                            # Create the database defined in config/database.yml for the current RAILS_ENVrake db:create:all                        # Create all the local databases defined in config/database.ymlrake db:drop                              # Drops the database for the current RAILS_ENVrake db:drop:all                          # Drops all the local databases defined in config/database.ymlA really useful one is the ‘routes’ option which outputs a list of the routesconfigured.macbook:railsproject jason$ rake routes(in /Users/jason/railsproject)  /:controller/:action/:id  /:controller/:action/:id(.:format)"
    } ,
  
    {
      "title"    : "MySQL Gem Installation on Mac 10.5.8 - 64 bit??",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/07/mysql-gem-installation-on-mac-10-5-8-64-bit/",
      "date"     : "2010-07-16 17:26:14 -0700",
      "content"  : "I’m setting up a new Ruby on Rails application, and tried to run the firstmigration for the creation of the new database. This failed because I didn’thave the MySQL gem installed. I’m using a 64 bit processor (Intel Core 2 Duo)so I installed the 64 bit MySQL for 10.5.8 (Leopard, I haven’t upgraded toSnow Leopard yet).When trying to run the installation command I received an error:$ sudo gem install mysqlPassword:Building native extensions.  This could take a while...ERROR:  Error installing mysql:    ERROR: Failed to build gem native extension./opt/local/bin/ruby extconf.rbchecking for mysql_query() in -lmysqlclient... nochecking for main() in -lm... yeschecking for mysql_query() in -lmysqlclient... nochecking for main() in -lz... yeschecking for mysql_query() in -lmysqlclient... nochecking for main() in -lsocket... nochecking for mysql_query() in -lmysqlclient... nochecking for main() in -lnsl... nochecking for mysql_query() in -lmysqlclient... nochecking for main() in -lmygcc... nochecking for mysql_query() in -lmysqlclient... no*** extconf.rb failed ***Could not create Makefile due to some reason, probably lack ofnecessary libraries and/or headers.  Check the mkmf.log file for moredetails.  You may need configuration options.I looked online for a solution to this, and found that you have to point to the directory where MySQL is installed. I tried:sudo gem install mysql -- --with-mysql-dir=/usr/local/mysqlThis resulted in this error instead:Building native extensions.  This could take a while...ERROR:  Error installing mysql:    ERROR: Failed to build gem native extension./opt/local/bin/ruby extconf.rb --with-mysql-dir=/usr/local/mysqlchecking for mysql_ssl_set()... nochecking for rb_str_set_len()... nochecking for rb_thread_start_timer()... nochecking for mysql.h... nochecking for mysql/mysql.h... no*** extconf.rb failed ***Could not create Makefile due to some reason, probably lack ofnecessary libraries and/or headers.  Check the mkmf.log file for moredetails.  You may need configuration options.Since the error is reporting that it can’t find mysql.h (header file), I takeit that the MySQL installer didn’t include the header files. From the commandline if I go to /usr/local/mysql/include I see the mysql.h right in there.I removed the preference panel option by opening the System Preferences, thenholding CTRL and clicking on the MySQL option. This gave me an option to clickon to remove it. I then deleted /usr/local/mysql and/usr/local/mysql-5.1.48-osx10.5-x86_64sudo rm -rf /usr/local/mysqlsudo rm -rf /usr/local/mysql-5.1.48-osx10.5-x86_64/Someone else mentioned something about using the 32-bit version of MySQL, so Idownloaded it and installed it instead (hoping it doesn’t conflict with theprocessor I’m using). It installed and started up just fine. I ran the commandto install the MySQL Gem again:$ sudo gem install mysql -- --with-mysql-dir=/usr/local/mysqlBuilding native extensions.  This could take a while...Successfully installed mysql-2.8.11 gem installedInstalling ri documentation for mysql-2.8.1...No definition for next_resultNo definition for field_name...No definition for error_sqlstateInstalling RDoc documentation for mysql-2.8.1...No definition for next_resultNo definition for field_name...No definition for error_sqlstateFinally it installed just fine."
    } ,
  
    {
      "title"    : "Wordpress Plugin - Custom Pages?",
      "category" : "",
      "tags"     : "wordpress, plugin, permalinks",
      "url"      : "/2010/06/wordpress-plugin-custom-pages/",
      "date"     : "2010-06-28 22:39:15 -0700",
      "content"  : "My DilemaOkay. I’ve worked on making a Wordpress plugin once. It’s pretty easy to makea plugin which replaces a tag such as [another-plugin-tag parameter="value"]with some sort of other HTML code. For instance it’s pretty straight forwardto replace [iframe http://www.google.com/ 800 600] with an iframe tag.Something I’ve found difficult to find however is how you can create custompages as soon as the plugin is activated, which are accessible using apermalink such as http://www.wordpress-site.com/myplugin/search/ which cansubmit a form to another URL such ashttp://www.wordpress-site.com/myplugin/results/ and then provide the resultswith a URL such as http://www.wordpress-site.com/myplugin/results/id/3/ oranything else pretty like that.And I’m not talking about searching for posts or pages or anything. I’mtalking about extending Wordpress to have functionality which is not blogrelated, while still being a plugin.I installed the ‘Contact Form 7’ plugin to see how it submitted the form, andthen I realized it uses Ajax. Great. I don’t want Ajax.A Hint of a SolutionI searched online looking for something to explain this, because certainlysomeone else must have been scratching their head like I have. No guidesseemed to explain this to me. I’d search for ‘Wordpress plugin permalinks’ andI’d only find plugins that deal with permalinks somehow (not what I waslooking for).And I was ignoring all the documentation on hooks and filters, because I don’twant to filter normal blog content, or hook to some blog content. But I wasmistaken. I do want to hook a function to something. It turns out thatWordpress has a number of actions which it goes through when loading a normalpage, available by name in the Plugin API Action Reference page.At some point of the page loading the permalink style URL, which is basicallymade possible by a mod_rewrite rule which says that any address is processedby index.php. The Wordpress system determines if the URL relates to a page orpost or something, or otherwise provides a 404 style error. Okay, so if I cansomehow tell Wordpress - “Yes! There is a /myplugin/ page”, or “Yes! There isa /myplugin/results/” page, then I’ll have one step of my solution finished.After further researching I found that there is an article on howWordpress processes a request, and it even mentions GET and POSTsubmissions. This was also obviously hard because ‘post’ is the term used torefer to the blog post records, so a search on Google for ‘Wordpress postrequest’ didn’t return something relevant.To Be ContinuedI’m going to continue to investigate how to build the type of plugin whichprovides custom URL’s, without requiring the existence of pages for theseURLs, and also somehow block the creation of pages which use the permalinkstructure used by the plugin.Update: It’s been a while since I posted this, but I found that there arerewrite rules stored somewhere in a serialized format or something in thewp_options table.There are some functions you can use to add or modify the rewrites/routes sothat they point to your custom script. Once a certain rule/route is pointingto your own plugin script, you can do whatever you want with the requests….serve up multiple pages, etc."
    } ,
  
    {
      "title"    : "Ubuntu 9.10 Karmic Koala - VNC resolution limited without monitor",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/02/ubuntu-9-10-karmic-koala-vnc-resolution/",
      "date"     : "2010-02-20 07:29:28 -0800",
      "content"  : "Update 04/23/2010 - I’m not finding a solution to this issue. Sorry. I’velost interest.I recently setup Ubuntu 9.10 on a desktop system, so I could use it as a fileserver. I’m was able to enable the remote desktop feature for it, which isbasically a VNC server.The issue is that once I disconnected a monitor from the computer and set itup next to my router (plugged directly in), and restarted it, VNC would onlywork with a maximum resolution of 640x480.In a forum someone pointed out that this configuration added to/etc/X11/xorg.conf would save the day:Section "Device"  Identifier "VNC Device"  Driver "vesa"EndSectionSection "Screen"  Identifier "VNC Screen"  Device "VNC Device"  Monitor "VNC Monitor"  SubSection "Display"  Modes "1024x768"  EndSubSectionEndSectionSection "Monitor"  Identifier "VNC Monitor"  HorizSync 30-70  VertRefresh 50-75EndSectionI just restarted after my ‘sudo service gdm restart’ command didn’t seem towork. I think this might have something to do with a special Nvidia driver I’musing. Hm…And I thought this most recent article was giving methe holy grail.Eh. I’m going to bed now. It’s 3:29 AM. I’ll slay this dragon later perhaps."
    } ,
  
    {
      "title"    : "PHP Not Parsing on Debian / Ubuntu server with Apache2",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/02/php-not-parsing-on-debian-ubuntu-server/",
      "date"     : "2010-02-10 21:03:59 -0800",
      "content"  : "My friend Marshall was recently having issues getting PHP5 installed andworking on his Ubuntu server, which is a Debian based distribution.We updated all the packages involved…Apache2, php5, libapache2-mod-php5,made sure the module was installed, restarted Apache2, etc. Nothing worked.It turns out that the default php5.conf configuration for Debian / Ubuntu’spackages are using an incorrect syntax. Edit /etc/apache2/mods-available/php5conf to reflect:&lt;FilesMatch \.php$&gt;  SetHandler application/x-httpd-php&lt;/FilesMatch&gt;…instead of…AddType application/x-httpd-php .phpSpecial thanks to this Apache wiki article for pointing this out:http://wiki.apache.org/httpd/DebianPHPI’m just posting this solution here for all the other nerds having the sameissue that aren’t finding this article in Google."
    } ,
  
    {
      "title"    : "Dell Dimension 3000 - Audio is Choppy",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/01/dell-dimension-3000-audio-is-choppy/",
      "date"     : "2010-01-13 18:49:45 -0800",
      "content"  : "At work I have a Dell Dimension 3000 workstation, and for months I’ve put upwith the computer being kind of slow. I just figured it was due to thecomputer being kind of old…but I brought in some headphones so I could dosome serious music listening while I work and just got fed up with the way thesound was choppy. Anytime I’d do anything processor intensive the music I waslistening to in Grooveshark (which I highly recommend you checkout) would sound like crap.So I installed the latest sound driver from Dell.com for the integrated soundcard and still after rebooting it sucked. Also when I start the computer up inthe morning, I would have to wait like 3 minutes at least for all the startupprograms to load. Nothing else would open until this was done.So anyway, I searched for a solution to this issue and found this post:choppy sound on DELL Dimension 3000It turns out that the Primary IDE controller in Windows XP was set to use somesort of PIO mode to communicate with the hard drive on the computer, asopposed to DMA mode. DMA stands for Direct Memory Access, and is totally moreefficient than the PIO mode, Programmed Input-Output, where the centralprocessor transfers data byte for byte or word for word through your system tothe other components (like your sound card).My computer runs blazing fast now in comparison to how it was running before.I’m so glad I checked into this. If you have a Dell Dimension 3000 and it’srunning like crap, definitely try this."
    } ,
  
    {
      "title"    : "Un-Hide Someone in Facebook",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/01/un-hide-someone-in-facebook/",
      "date"     : "2010-01-11 17:40:15 -0800",
      "content"  : "My aunt recently asked me how to un-hide someone from the news feed for herFacebook account.Like many other people before her, she’s pressed the ‘Hide’ button forsomeone, then realized it was a mistake…but couldn’t find out how to unhidethem.To add someone back to your Facebook news feed, simply scroll to the bottom ofthe page and click on the ‘Edit Options’ link for your news feed.After you’ve done this, simply click on the ‘Add to News Feed’ button to addupdates regarding one of your friends, or other pages, back to your Facebooknews feed."
    } ,
  
    {
      "title"    : "Selenium - no display specified",
      "category" : "",
      "tags"     : "",
      "url"      : "/2010/01/selenium-no-display-specified/",
      "date"     : "2010-01-11 14:51:10 -0800",
      "content"  : "I’m not very experienced with X-windows on the Linux platform, so I’m not tooskilled in troubleshooting issues with the display. I recently upgraded anUbuntu system at work to use Ubuntu 9.04 (Jaunty Jackalope), which only hasFirefox 3 available (no package for Firefox 2). I had a Selenium server setuprunning tests, but they stopped working after I upgraded to this newer versionof Ubuntu.I thought that perhaps Selenium wasn’t compatible with version 3 of Firefox,but this isn’t the case. The Selenium website says ‘Firefox 2+’ for browsersrunning on Linux.The error I was receiving when I would run a test was:10:46:19.778 INFO - Preparing Firefox profile...Error: no display specifiedAfter a bunch of research and Googling online, it turned out I just needed torun this before I started my Selenium server:export DISPLAY=:0I hope this saves someone else some time."
    } ,
  
    {
      "title"    : "Common Computer Mistakes",
      "category" : "",
      "tags"     : "",
      "url"      : "/2009/11/common-computer-mistakes/",
      "date"     : "2009-11-02 14:59:02 -0800",
      "content"  : "Whether you are an individual, or a startup business, you’ll more than likelyhave a website or a computer. I’ve had my fair share of experiences withpersonal computers (PCs and Macs), and I’ve also worked at a website hostingcompany, HostDime.I’ve often cringed due to the negligence of individuals and/or companiesregarding the following items. Here are some tips to save you from largelosses.Data BackupsPeople often assume that they can accumulate all their photos, music, videos,documents, and other very important business related files on their computersand it’s all safe and sound. However, this is not really the case. The harddrive inside your computer will eventually deteriorate, if not completely stopworking out of the blue. It’s just a matter of time. Sure, it’s not likelythat this will happen with a brand new Seagate hard drive with a 5 yearwarranty, but it’s surely possible that it could occur at any time. Do youwant to leave the only copies of all your important files up to chance?I recommend that if you’re an individual, go to a store such as Best Buy andpurchase a backup drive, and set up your operating system or backup softwarewhich is packaged with the drive, so that it syncs up data with your computershard drive.If you’re a business, then you might want to setup a file server of some sorton the network, and map an icon on each computer to the drive on this server.Tell your staff to store important files on this drive, or at least updatecopies of their important files on this drive. If their computer crashes,you’ll have a backup, and you’ll be able to easily backup all these importantfiles from the file server to another backup drive just the same. This willkeep you from having to go from computer to computer backing up the files,since they are all in one location on the file server.Operating System / Recovery DiscsThis applies more to those with personal computers, but also to businesses. Ifyou purchase a computer, it will come with either installation discs for theoperating system (typically a version of Windows or Mac OSX), or with special‘Recovery’ discs. Along with these discs there may also be documentation whichincludes registration keys of some sort. Place these in a safe location, anddo not let them get mixed in with all the other junk in your desk.Often when a persons computer crashes (see above on data back ups), or theyget a virus, or anything thats makes the computer unusable, the best solutionis to erase everything from the hard drive and restore the computer to the wayit was when you first got it…a fresh installation of Windows/MacOSX, withthe default programs, just like you just got the computer from the store. Noviruses, no other programs installed.To achieve this, you need to have the discs that came with your computer, andany necessary registration keys for the operating system.If you’ve lost these, then the restoration of your computer to it’s originalstate will not be possible until you either order new restore discs from thecompany you bought your computer from, or purchase new operating system discsand registration keys for the full retail price (or OEM price if you know howto search and buy it cheaper).Domain Name RegistrationA common issue I encounter with some website owners is that they hire someindividual to setup their website, and then the relationship goes sour and thedesigner/developer holds their website hostage. Certainly it’s fine for anindividual to hold the work they’ve done on your website until they are paidfor their services, but to hold the data you’ve paid for already, as well asyour domain name, certainly amounts to a legal travesty.To avoid this situation it is highly recommended that you register or transferyour domain name to a well known domain registration service provider, such asNamecheap, or Register.com. There are surely other large organizationswhich will not hold your domain hostage.Once you’ve transfered your domain name to an account with a reputableregistration organization, make sure you put a very complex password on theaccount, and also ensure that your domains are updated with your contactinformation, and that they are Locked. This will ensure that your accountcannot be hacked into, you are reflected as the owner of the domain(Administrative Contact), and if the domain is locked it cannot be transferedto another company (stolen) by any means.If your domain is in your ownership, it can easily be updated to point to thenameserver addresses of any company which is hosting the website, even if it’sthe hosting account setup by your designer/developer that is providing acomplete website solution to you (website design, development, and hosting).The one thing you don’t want them having control over is your domain however,because unlike the design of your website, the domain cannot be replaced.Website BackupsIt can be very convenient for your website designer/developer to host yourwebsite for you. This gives them more control over the website, they arefamiliar with the features of the hosting, and providing the hosting to yousupplements their income and keeps them in business (design/development workisn’t always available for some).This is perfectly fine, and I’m not intending to cause any alarm, but youcertainly want to have a copy of what you’re paying for …and the only way toachieve this is to periodically obtain backups of your website. Ask yourdesigner/developer if they have access to a control panel, such as cPanel,which allows them to download backups of their website files and databases(if applicable).With these files you can always setup your website elsewhere without thedesigner/developer, or the same hosting company. Even with a reputabledesigner/developer, or hosting company, the server hosting your website useshard drives which may crash at any moment.Even though these companies do try to keep backups for you, most do notguarantee that backups will be available for your data. The best solution isto keep a copy for yourself just in case the worst scenario arises."
    } ,
  
    {
      "title"    : "Rounded Corners",
      "category" : "",
      "tags"     : "",
      "url"      : "/2009/04/rounded-corners/",
      "date"     : "2009-04-24 17:11:18 -0700",
      "content"  : "One of the most popular Web 2.0 practices is rounded corners. How do you getthem without uploading images, and nesting DIV’s, and worrying about othercomplications that can break your precious rounded corners?Answer! jQuery CornersjQuery Corners is compatible with Firefox, Internet Explorer 6+, Safari(including iPhone), Google Chrome, and Opera 9.0.All it takes is a simple jQuery style selector call such as the following:&lt;script&gt;  $(document).ready( function() {    $('.rounded').corners();  });&lt;/script&gt;&lt;div style="background-color:#acc; padding:5px" class="rounded"&gt;Simple Example&lt;/div&gt;You can also experiment further with documented options to change the radius(amount of curve) for the rounded corners, and will even show properly ifthere is a background image specified inside of the object with roundedcorners.Available for download at http://plugins.jquery.com/project/cornersDocumentation provided at http://www.atblabs.com/jquery.corners.html"
    } ,
  
    {
      "title"    : "Database Schema Information",
      "category" : "",
      "tags"     : "mysql, rails",
      "url"      : "/2009/03/database-schema-information/",
      "date"     : "2009-03-13 17:20:50 -0700",
      "content"  : "It can be very useful to have the database table schema information availableto you when you are working on a model in a Ruby on Rails application. Thereis a plugin available which provides the schema information in comments at thetop of each model called Annotate Models Plugin.# == Schema Information# Schema version: 20090215021706## Table name: orders##  id                     :integer(11)     not null, primary key#  order_number           :integer(11)     default(0), not null#  created_on             :datetime#  shipped_on             :datetime#  order_user_id          :integer(11)#  order_status_code_id   :integer(11)     default(1), not null#  notes                  :text#  referer                :string(255)#  order_shipping_type_id :integer(11)     default(1), not null#  product_cost           :float           default(0.0)#  shipping_cost          :float           default(0.0)#  tax                    :float           default(0.0), not null#  auth_transaction_id    :string(255)#  promotion_id           :integer(11)     default(0), not null#  shipping_address_id    :integer(11)     default(0), not null#  billing_address_id     :integer(11)     default(0), not null#  order_account_id       :integer(11)     default(0), not null#  subscription_id        :integer(11)You can install the plugin using the following command from the root of yourRails application.script/plugin install http://repo.pragprog.com/svn/Public/plugins/annotate_modelsAfter you are done installing the plugin, simply run the rake task by usingthis command:rake annotate_models"
    } ,
  
    {
      "title"    : "PHP Compilation",
      "category" : "",
      "tags"     : "php",
      "url"      : "/2005/02/php-compile/",
      "date"     : "2005-02-28 02:22:01 -0800",
      "content"  : "I’m pretty proud of myself. I just configured PHP to compile without anyproblems…well no imap support, but that can wait.I saw that someone asked how to resolve the problem, but had no answer, andthen I realized with the help of an answer from someone else on a messageboardthat you have to install the development version of the libraries to compilecertain support into a program.Here is my chance to give back to the Linux world by helping another newbieout (without acting like I was above him or anything, just a newbie helping anewbie).See Post"
    } ,
  
    {
      "title"    : "MBox and Linux Test Server",
      "category" : "",
      "tags"     : "mbox, linux",
      "url"      : "/2005/02/mbox-and-linux-test-server/",
      "date"     : "2005-02-23 15:25:01 -0800",
      "content"  : "Well. I hooked up the MBox last night, and just like before but even moredisappointing, the damn thing is still creating a digital hum and static,triggered by the movements of the mouse and the processing of programs. I don’tknow if its some sort of electrical interference, a bad USB cable, or both.I hope I can find the solution. The first thing I’m going to do is replace thecable and try to clean the connectors in the MBox.I got the web server running on my little Linux test server. I was hostingredconfetti.net on the server that this website is hosted on for a while,but recently I moved the DNS hosting onto my server, along withredconfetti.net.I currently have various videos hosted off this server. They are availablefrom the old redconfetti.net site - Misc VideosI’m going to continue to work on redconfetti.net as a Linux tutorial site. Iwant to provide to others the solutions to the obstacles I meet and haveovercome. I don’t know if other people will have the same issues I’m having,and I am trying to read the manual, but oh well."
    } ,
  
    {
      "title"    : "PHP/MySQL Bug Tracking",
      "category" : "",
      "tags"     : "bug tracking",
      "url"      : "/2004/09/bug-tracking/",
      "date"     : "2004-09-09 13:51:00 -0700",
      "content"  : "For anyone who needs a free web based Bug Tracking system programmed usingPHP/MySQL, check out Flyspray.I searched very far to find a web based program to track the bugs in thewebsite I work on in ASP/MS-SQL. I know PHP/MySQL so I was able to setup thisbug tracker, and fortunately I can modify it to do things I need it to do.Its features appear to be good enough for tracking bugs in actual software,and it can be setup to suit those debugging web based software."
    } 
  
  ,
  
   {
     
        "title"    : "Categories",
        "category" : "",
        "tags"     : "",
        "url"      : "/categories/",
        "date"     : "",
        "content"  : ""
     
   } ,
  
   {
     
        "title"    : "Docker",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/docker/",
        "date"     : "",
        "content"  : "Back to Cheat SheetsDocker-MachineDocker uses virtual machine(s) (VM) provided by Virtualbox to run your Docker application(s). You can manage the VM’s by using ‘docker-machine’.# List Virtual Machinesdocker-machine ls# Start Docker Virtual Machinedocker-machine start# Stop Docker Virtual Machinedocker-machine stop# Display the shell initialization commandsdocker-machine env# Initialize shell for accessing VM. Run this if 'docker' command unable to connect to daemon.eval $(docker-machine env)# View Docker VM statusdocker-machine status# Get local IP for VMdocker-machine ip# Upgrade Docker Machinedocker-machine stop# docker-machine upgradedocker-machine upgradeDocker# View docker client and server version infodocker version# List Running Containersdocker ps# List All Containersdocker ps -a# Initialize and start an 'nginx' container with "web" as namedocker run -d -P --name web nginx# Initialize a container running in the background with a local directory mounted in the container, based on the nginx containerdocker run -d -P -v $HOME/site:/usr/share/nginx/html --name mysite nginx# View container portsdocker port [container_id]# Start containerdocker start [container_id]# Restart containerdocker restart [container_id]# Stop Containerdocker stop [container_id]# SSH into running Docker container for inspection / debuggingdocker attach [container_id]# Remove Docker container (requires stop to remove)docker stop [container_id]docker rm [container_id]# Display stdout from containerdocker logs [container_id]# Display processes for containerdocker top [container_id]# Copy files/folders from the local filesystem into a containerdocker cp foo.txt mycontainer:/foo.txtdocker cp /Projects/myapp mycontainer:/app# Copy files/folders from the contain to the local filesystemdocker cp [container_name]:/foo.txt foo.txt# Get JSON data on containerdocker inspect [container_id]# View local docker imagesdocker images# Remove docker imagedocker rmi [image_id]# Search for Docker imagesdocker search [image_name]# Download Docker image for later usedocker pull [image_name]# Build Docker image from Git repository (requires Dockerfile)docker build https://github.com/username/reponame.git#master# Tag Docker image in preparation for push to remote repositorydocker tag [image_id] [repository_url]:[port]/[name]:[tag]# Push Docker image to remote repositorydocker push [repository_url]:[port]/[name]:[tag]"
     
   } ,
  
   {
     
        "title"    : "ES2015 Notes",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/notes/es-2015/",
        "date"     : "",
        "content"  : "ES2015CodeSchool - ES2015 - The Shape of Javascript to ComeThe Shape of Javascript to ComeES2015, formerly known as ES6, is the most extensive update to the JavaScript language since the publication of itsfirst edition in 1997.The committee decided to use the year of release, instead of version number.Level 1 - DeclarationsThe exercises will focus on a forum web app. The first feature will be loading users profile into the sidebar of thesite.Declarations with letThe loadProfiles function takes an array of users and adds their profile to the sidebar.&lt;!DOCTYPE html&gt;   &lt;!-- ... --&gt;   &lt;script src="./load-profiles.js"&gt;   &lt;script&gt;     loadProfiles(["Sam", "Tyler", "Brook", "Jason"]);   &lt;/script&gt;&lt;/html&gt;The loadProfiles Functionfunction loadProfiles(userNames) {  if (userNames.length &gt; 3) {    var loadingMessage = "This might take a while...";    _displaySpinner(loadingMessage);  } else {    var flashMessage = "Loading Profiles";    _displayFlash(flashMessage);  }  console.log(flashMessage); // returns undefined  // ... fetch names and build sidebar}Javascript detects undeclared variables and declares them at the top of the current scope. This is known ashoisting.One way to avoid confusion is to use let.let loadingMessage = "This might take a while...";Variables declared with let are not hoisted to the top of the scope. Instead of the hoisting occurring, thus leadingto an undeclared value for the references, you’ll instead get a ReferenceError informing you that the variable isnot defined.Declarations with let in for loopsWhen using var in for loops, there can be unexpected behavior.function loadProfiles(userNames) {  for (var i in userNames) {    _fetchProfile("/users/" + userNames[i], function() {      console.log("Fetched for ", userNames[i]);    });  }}This results in output:Fetched for AlexFetched for AlexFetched for AlexFetched for AlexThe last element of the array is outputted all 4 times because the _fetchProfile method is delayed in it’s executiondue to an AJAX call, so when it references the variable i, the iterations have completed and the value of i  isset to 3 as it’s final value. When the callbacks calls, upon completion of the AJAX request, it references the 3and ends up outputting ‘Alex’ as the name.This is because the var i is hoisted to the top of the function and declared in that scope, and then other referencesto i. If this is replaced with let, a new i variable is created on each iteration.for (let i in userNames) {}Variables declared with let can be reassigned, but cannot be redeclared within the same scope.// no problemlet flashMessage = "Hello";flashMessage = "Goodbye";// problemlet flashMessage = "Hello";let flashMessage = "Goodbye"; // results in a TypeError// no error because defining in a different scopelet flashMessage = "Hello";function loadProfiles(userNames) {  let flashMessage = "Loading profiles";  return flashMessage;};Declarations with constMagic Number - A literal value without a clear meaning. If you end up using the number multiple times, it will lead tounnecessary duplication, which is bad code. People won’t know if these literal values are related or not.By using const we can create a read-only named constant.const MAX_USERS = 3;if (userNames.length &gt; MAX_USERS) {   // ...}You cannot redefine a constant after it has been defined.  Constants also require an initial value.// will result in errorconst MAX_USERS;MAX_USERS = 10;Block ScopedConstants are blocked scoped, which mean they are not hoisted to the top of the function. So if you define somethingwithin an if block, and try to access it from outside, it will return an error.if (userNames.length &gt; MAX_USERS) {  const MAX_REPLIES = 15;} else {  // ...}console.log(MAX_REPLIES); // ReferenceError. MAX_REPLIES is not defined)Level 2 - FunctionsFunctionsDefault ParametersUnexpected arguments might cause errors during function execution. This code runs just fine, because it’s passing anarray to the function as expected.loadProfiles(["Sam", "Tyler", "Brook"]);However what if it was passed no arguments, or an undefined value.function loadProfiles(userNames) {  // TypeError: Cannot read property ‘length’ of undefined  let namesLength =  userNames.length;}A common practice is to validate the presence of arguments in the beginning of the function.let names = typeof userNames !== 'undefined' ? userNames : [];We can make this code better by defining default values for the parameters.function loadProfiles(userNames = []) {  let namesLength = userNames.length;  console.log(namesLength);}Named ParametersThe options object is a widely used pattern that allows user-defined settings to be passed to a function in theform of properties on an object.function setPageThread(name, options = {}) {  let popular = options.popular;  let expires = options.expires;  let activeClass = options.activeClass;};setPageThread("New Version out Soon!", {  popular: true,  expires: 10000,  activeClass: "is-page-thread"});This approach doesn’t make it very clear which options the function expects, and it requires the definition ofboilerplate code to handle the option assignment.Using named parameters for optional settings makes it easier to understand how a function should be invoked.function setPageThread(name, {popular, expires, activeClass}) {  console.log("Name: ", name);  console.log("Popular: ", popular);  console.log("Expires: ", expires);  console.log("Active: ", activeClass);}Now we know which arguments are available. The function call remains the same. Each property of the parameter is mappedto the argument appropriately.It’s NOT okay to omit the options argument altogether when invoking a function with named parameters when no defaultvalue is set for them.// results in TypeError: Cannot read property 'popular' of undefinedsetPageThread("New Version out Soon!");// sets default value, resulting in all becoming undefinedfunction setPageThread(name, {popular, expires, activeClass} = {}) {  console.log("Name: ", name);  console.log("Popular: ", popular);  console.log("Expires: ", expires);  console.log("Active: ", activeClass);}// defaults the value of popular to an empty string// while still defaulting the entire options hash if not providedfunction setPageThread(name, {popular = '', expires, activeClass} = {}) {  console.log("Name: ", name);  console.log("Popular: ", popular);  console.log("Expires: ", expires);  console.log("Active: ", activeClass);}Rest Parameter, Spread Operator, and Arrow FunctionsTags are a useful feature in web applications that have lots of read content. It helps filter results down to specifictopics. Let’s add these to the forum.We want our displayTags function to operate as follows:// variadic functions can accept any number of argumentsdisplayTags("songs");displayTags("songs", "lyrics");displayTags("songs", "lyrics", "bands");Arguments ObjectIn classic Javascript we could have used the arguments object, which is a build-in Array-like object that correspondsto the arguments of a function.This is not ideal because it’s hard to tell which parameters this function expects to be called with. Developers mightnot know where the arguments reference comes from (outside the scope of the function??).function displayTags() {  for(let i in arguments) {    let tag = arguments[i];    _addToTopic(tag);  }}If we change the function signature, it will break our code also.function displayTags(targetElement) {  let target = _findElement(targetElement);  for(let i in arguments) {    let tag = arguments[i]; // becomes broken because the                            // first argument is no longer a tag    _addToTopic(tag);  }}Rest ParameterThe new rest parameter syntax allows us to represent an indefinite number of arguments as an Array. This way,changes to function signature are less likely to break code.The three dots make tags a rest parameter.function displayTags(...tags) {  // tags in an array object  for(let i in tags) {    let tag = tags[i];    _addToTopic(tag);  }}function displayTags(targetElement, ...tags) {  // ...}The rest parameter must always go last in the function signature.Spread OperatorWe need a way to convert an Array into individual arguments upon a function call.getRequest("/topics/17/tags", function(data){  let tags = data.tags;  displayTags(tags); // tags is an Array});Our function is expecting to be called with individual arguments, not a single argument that is an Array. How can weconvert the Array argument into individual elements on the function call?getRequest("/topics/17/tags", function(data){  let tags = data.tags;  displayTags(...tags); // tags is an Array});Prefixing the tags array with the spread operator makes it so that the call is the same as callingdisplayTags(tag, tag, tag).The syntax for rest parameters and the spread operator look the same, but the former is used infunction definitions and the later in function invocations.JavaScript ObjectsJavaScript objects can help us with the encapsulation, organization, and testability of our code.Functions like getRequest and displayTags should not be exposed to caller code.getRequest("/topics/17/tags", function(data){  let tags = data.tags;  displayTags(...tags);});We want to convert code like above, into code like this:let tagComponent = new TagComponent(targetDiv, "/topics/17/tags");tagComponent.render();The TagComponent object encapsulates the code for fetching tags and adding them to a page.function TagComponent(target, urlPath) {  this.targetElement = target;  this.urlPath = urlPath;}TagComponent.prototype.render = function() {  getRequest(this.urlPath, function(data) {    // ...  });}Properties set on the constructor function can be accessed from other instance methods. This is why the reference tothis.urlPath works within the render() method.Issues with Scope in Callback FunctionsAnonymous functions passed as callbacks to other functions create their own scope.function TagComponent(target, urlPath) {  // this scope within the component object is not the same  // as the anonymous function assigned to 'render' below  this.targetElement = target;  this.urlPath = urlPath;}TagComponent.prototype.render = function() {  getRequest(this.urlPath, function(data) {    let tags = data.tags;    // this.targetElement returns undefined    displayTags(this.targetElement, ...tags);  });}Arrow FunctionsArrow functions bind to the scope of where they are defined, not where they are used. This is also known aslexical binding.function TagComponent(target, urlPath) {  this.targetElement = target;  this.urlPath = urlPath;}TagComponent.prototype.render = function() {  // arrow functions bind to the lexical scope  getRequest(this.urlPath, (data) =&gt; {    let tags = data.tags;    displayTags(this.targetElement, ...tags);  });}Level 3 - Objects, Strings, and Object.assignObjects and StringsThe buildUser function returns an object with the first, last, and fullName properties.function buildUser(first, last) {  let fullName = first + " " + last;  return {    first: first,    last: last,    fullName: fullName  }}let user = buildUser("Sam", "Williams");As you can see, we end up repeating the same thing as the key and value here in the return statement.Object InitializerWe can shorten this by using the object initializer shorthand, which removes duplicate variable names.return {first, last, fullName}; // way cleanerThis only works when the properties and values use the same name. It works anywhere a new object is returned, not justfrom functions.let name = "Sam";let age = 45;let friends = ["Brook", "Tyler"];let user = {name, age, friends};Object Destructuring// generates 3 separate variables based on the object returnedlet { first, last, fullName } = buildUser(“Sam”, “Williams”);console.log(first);     // &gt; Samconsole.log(last);      // &gt; Williamsconsole.log(fullName);  // &gt; Sam WilliamsNot all of the properties have to be destructured all the time. We can explicitly select the ones we want.let { fullName } = buildUser("Sam", "Williams");console.log(fullName);In previous versions of JavaScript, adding a function to an object required specifying the property name and thenthe full function definition (including the function keyword);function buildUser(first, last, postCount) {  let fullName = first + " " + last;  const ACTIVE_POST_COUNT = 10;  return {    first,    last,    fullName,    isActive: function() {      return postCount &gt;= ACTIVE_POST_COUNT;    }  }}A new shorthand notation is available for adding a method to an object where the keyword function is no longernecessary.return {  first,  last,  fullName,  isActive() {    return postCount &gt;= ACTIVE_POST_COUNT;  }Template StringsTemplate strings are string literals allowing embedded expressions. This allows for a much better way to dostring interpolation.function buildUser(first, last, postCount) {  let fullName = first + " " + last;  const ACTIVE_POST_COUNT = 10;  // ...}You can instead use back ticks, with a dollar sign and curly brace syntax for interpolated variables.function buildUser(first, last, postCount) {  let fullName = `${first} ${last}`; // back-ticks, NOT single quotes  const ACTIVE_POST_COUNT = 10;  // ...}Template strings offer a new - and much better- way to write multi-line strings.let userName = "Sam";let admin = { fullName: "Alex Williams" };let veryLongText = `Hi ${userName},this is a veryverylong text.Regards,  ${admin.FullName}`;console.log(veryLongText);Object.assignIn this example we’ll add a count-down timer to a forum. The countdown timer displays the time left for users to undotheir posts after they’ve been created. Once the time is up, they cannot undo it anymore.We want to make our timer function reusable so that it can be used by other applications and domains.// simple examplecountdownTimer($('.btn-undo'), 60);// container class specifiedcountdownTimer($('.btn-undo', 60, { container: '.new-post-options'}));// container class and time unitscountdownTimer(  $('.btn-undo', 60, {    container: '.new-post-options',    timeUnit: 'minutes',    timeoutClass: '.time-is-up'  }));For functions that need to be used across different applications, it’s okay to accept an options object instead ofusing named parameters.// too many options, difficult to interpret calls to this functionfunction countdownTimer(target, timeLeft, {container, timeUnit, clonedDataAttribute, timeoutClass, timeoutSoonClass, timeoutSoonSeconds} = {}) {  // ...}// easier to customize to different applicationsfunction countdownTimer(target, timeLeft, options = {}) {  // ...}Some options might not be specified by the caller, so we need to have default values.function countdownTimer(target, timeLeft, options = {}) {  let container = options.container || ".timer-display";  let timeUnit = options.timeUnit || "seconds";  let clonedDataAttribute = options.clonedDataAttribute || "cloned";  let timeoutClass = options.timeoutClass || ".is-timeout";  let timeoutSoonClass = options.timeoutSoonClass || ".is-timeout-soon";  let timeoutSoonTime = options.timeoutSoonSeconds || 10;}This works, but the default strings and numbers are all over the place, which makes the code hard to understand anddifficult to maintain.Using a local object to group default values for user options is a common practice and can help write moreidiomatic JavaScript. We want to merge options and defaults. Upon duplicate properties, those from optionsmust override properties from defaults.The Object.assign method copies properties from one or more source objects to a target object specified asthe first argument.function countdownTimer(target, timeLeft, options = {}) {  let defaults = {    container: ".timer-display",    timeUnit: "seconds",    clonedDataAttribute: "cloned",    timeoutClass: ".is-timeout",    timeoutSoonClass: ".is-timeout-soon",    timeoutSoonTime: 10  };  // we pass a {} because the target object is modified  // and used as return value  // Source objects remain unchanged  let settings = Object.assign({}, defaults, options);}In case of duplicate properties on source objects, the value from the last object on the chain always prevails.Properties in options3 will override options2, and options2 will override options.function countdownTimer(target, timeLeft, options = {}) {  let defaults = {    // ...  };  let settings = Object.assign({}, defaults, options, options2, options3);}Because the target of Object.assign is mutated, we would not be able to go back and access the original default valuesafter the merge if we used it as the target// bad ideaObject.assign(defaults, options);// Okay alternative approachlet settings = {};Object.assign(settings, defaults, options);We want to preserve the original default values because it gives us the ability to compare them with the optionspassed, and act accordingly when necessary.function countdownTimer(target, timeLeft, options = {}) {  let defaults = {    // ...  };  let settings = Object.assign({}, defaults, options);  // this wouldn't be possible without knowing if the argument  // is different than the default  if (settings.timeUnit !== defaults.timeUnit) {    _conversionFunction(timeLeft, settings.timeUnit);  }}Let’s run countdownTimer() passing the value for container as argument…countdownTimer($('.btn-undo'), 60, {container: '.new-post-options'});function countdownTimer(target, timeLeft, options = {}) {  let defaults = {    container: ".timer-display",    timeUnit: "seconds",    // ...  };  let settings = Object.assign({}, defaults, options);  console.log( settings.container ); // .new-post-options  console.log( settings.timeUnit ); // seconds}Level 4 - Arrays, Maps, and SetsArraysDestructuringWe typically access array elements by their index, but doing so for more than just a couple of elements can quicklyturn into a repetitive task.let users = ["Sam", "Tyler", "Brook"];// this will keep getting longer as we need to extract more elementslet a = users[0];let b = users[1];let c = users[2];console.log(a, b, c); // Sam Tyler BrookWe can use Array Destructuring to assign multiple values from an array to local variables.let users = ["Sam", "Tyler", "Brook"];let [a, b, c] = users; // still easy to understand, AND less codeconsole.log(a, b, c); // Sam Tyler BrookValues can be discarded if desired.let [a, , b] = users; // discarding "Tyler" valueconsole.log(a, b); // Sam BrookWe can combine destructuring with rest parameters to group values into other arrays.let users = ["Sam", "Tyler", "Brook"];let [first, ...rest] = users; // groups remaining argument in an arrayconsole.log(first, rest); // Sam ["Tyler","Brook"]When returning arrays from functions, we can assign to multiple variables at once.function activeUsers() {  let users = ["Sam", "Alex", "Brook"];  return users;}let active = activeUsers();console.log(active); // ["Sam", "Alex", "Brook"]let [a, b, c] = activeUsers();console.log(a, b, c); // Sam Alex BrookUsing for…ofThe for…of statement iterates over property values, and it’s a better way to loop over arrays and otheriterable objects.let names = ["Sam", "Tyler", "Brook"];for (let index in names) {  console.log( names[index] );}for (let name of names) {  console.log( name );}For for..of statement cannot be used to iterate over properties in plain JavaScript objects out-of-the-box.let post = {  title: "New Features in JS",  replies: 19,  lastReplyFrom: "Sam"};// this will not work// TypeError: post[Symbol.iterator] is not a functionfor (let property of post) {  console.log("Value: ", property);}In order to work with for…of, objects need a special function assigned to the Symbol.iterator property. The presenceof this property allows us to know whether an object is iterable.let names = ["Sam", "Tyler", "Brook"];console.log( typeof names[Symbol.iterator] ); // functionfor (let name of names) {  console.log(name);}Since there is a function assigned, then the names array will work just fine with for..of.let post = {  title: "New features in JS",  replies: 19,  lastReplyFrom: "Sam"};console.log( typeof post[Symbol.iterator] ); // undefined// Results in TypeError: post[Symbol.iterator] is not a functionfor (let property of post) {  console.log(property);}Finding an Element in an ArrayArray.find returns the first element in the array that satisfies a provided testing function.let users = [  { login: "Sam", admin: false },  { login: "Brook", admin: true },  { login: "Tyler", admin: true }];How can we find the first admin in the array?let admin = users.find( (user) =&gt; {  return user.admin;  // returns first object for which user.admin is true});console.log(admin);We can alternatively shorten this function by omitting the curly braces and parenthesis in the function definition.let admin = users.find( user =&gt; user.admin );MapsMaps are a data structure composed of a collection of key/value pairs. They are very useful to store simpledata, such as property values. Each key is associated with a single value.Objects are first key/value stores that Javascript developers encounter, however when using Objects as maps, it’skeys are always converted to strings.let user1 = { name: "Sam" };let user2 = { name: "Tyler" };let totalReplies = {};totalReplies[user1] = 5;totalReplies[user2] = 42;console.log(totalReplies[user1]); // 42console.log(totalReplies[user2]); // 42console.log( Object.keys(totalReplies) ); // [ "[object Object]" ]This happens because both objects are converted to the string [object Object] when they are used as keys inside oftotalReplies.We should stop using Javascript objects as maps, and instead use the Map object, which is also a simple key/valuedata structure. Any value may be used as either a key or a value, and objects are not converted to strings.let user1 = { name: "Sam" };let user2 = { name: "Tyler" };let totalReplies = new Map();totalReplies.set(user1, 5);totalReplies.set(user2, 42);console.log( totalReplies.get(user1) ); // 5console.log( totalReplies.get(user2) ); // 42We have to use the get() and set() methods to access values in Maps.Most of the time you will want to use the Map data structure, such as when keys are not known until runtime… such asuser input, or IDs generated by a database. You’ll still want to use Objects when the keys are static.Maps are iterable, so they can be used in a for…of loop. Each run of the loop returns a [key, value] pair foran entry in the Map.let mapSettings = new Map();mapSettings.set("user", "Sam");mapSettings.set("topic", "ES2015");mapSettings.set("replies", ["Can't wait!", "So cool"]);for (let [key, value] of mapSettings) {  console.log(`${key} = ${value}`);}WeakMapA WeakMap is a type of Map where only objects can be passed as keys. Primitive data types — such as strings,numbers, booleans, etc. — are not allowed.let user = {};let comment = {};let mapSettings = new WeakMap();mapSettings.set( user, "user" );mapSettings.set( comment, "comment" );console.log( mapSettings.get(user) ); // userconsole.log( mapSettings.get(comment) ); // commentmapSettings.set("title", "ES2015"); // Invalid value used as weak map keyAll available methods on a WeakMap require access to an object used as a key.let user = {};let mapSettings = new WeakMap();mapSettings.set( user, "ES2015" );console.log( mapSettings.get(user) ); // "ES2015"console.log( mapSettings.has(user) ); // trueconsole.log( mapSettings.delete(user) ); // trueWeakMaps are not iterable, therefore they can’t be used with for…of.// error:// mapSettings[Symbol.iterator] is not a functionfor (let [key, value] of mapSettings) {  console.log(`${key} = ${value}`);}Individual entries in a WeakMap can be garbage collected while the WeakMap itself still exists.let user = {}; // all objects occupy memory spacelet userStatus = new WeakMap();userStatus.set(user, "logged"); // Object reference passed as key to the WeakMap// ...someOtherFunction( user ); // Once this function returns, 'user' can be garbage collected.WeakMaps don’t prevent the garbage collector from collecting objects currently used as keys, but that are no longerreferenced anywhere else in the system. The garbage collector removes the object from the WeakMap as well.SetsLimitations with ArraysArrays don’t enforce uniqueness of items. Duplicate entries are allowed.let tags = [];tags.push("Javascript");tags.push("Programming");tags.push("Web");tags.push("Web");console.log("Total items ", tags.length); // Total items 4The Set object stores unique values of any type, whether primitive values or object references.let tags = new Set();tags.add("Javascript");tags.add("Programming");tags.add({version: "2015"});tags.add("Web");tags.add("Web"); // duplicate entries are ignoredconsole.log("Total items ", tags.size); // Total items 4Set objects are iterable, which means they can be used with for…of and destructuring.let tags = new Set();tags.add("Javascript");tags.add("Programming");tags.add({version: "2015"});tags.add("Web");for(let tag of tags) {  console.log(tag);}let [a,b,c,d] = tags;console.log(a, b, c, d); // Javascript Programming {version: '2015'} WebWeakSetThe WeakSet is a type of Set where only objects are allowed to be stored.let weakTags = new WeakSet();weakTags.add("JavaScript"); // TypeError: Invalid value used in weak setweakTags.add({ name: "JavasScript" });let iOS = { name: "iOS" };weakTags.add(iOS);weakTags.has(iOS); // returns true, because it has that object presentweakTags.delete(iOS); // returns true, it successfully removed from the weaksetCan’t Read From a WeakSetWeakSets cannot be used with for…of and they offer no methods for reading values from it.let weakTags = new WeakSet();weakTags.add({ name: "JavasScript" });let iOS = { name: "iOS" };weakTags.add(iOS);// TypeError weakTags[Symbol.iterator] is not a functionfor (let wt of weakTags) {  console.log(wt);}Using WeakSets to Show Unread PostsIf we can’t read values from a weakset, when should we use them?In a visual interface, we want to add a different background color to posts that have not yet been read.One way to “tag” unread posts is to change a property on each post object once they are read.let post = { // ... };// ... when post is clicked onpostList.addEventListener('click', (event) =&gt; {  // ...  post.isRead = true; // Mutates post object in order to indicate it's been read});// ... rendering list of posts// checks a property on each post objectfor (let post of postArray) {  if(!post.isRead) {    // adds css class on element if new    _addNewPostClass(post.element);  }}The issue with this code is that we are changing/mutating each post object unnecessarily. Using immutable objects inJavascript is a common practice that should be favored whenever possible. Doing so makes your code easier to understand,and leaves less room for errors.We can use WeakSets to create special groups from existing objects without mutating them. Favoring immutableobjects allows for much simpler code with no unexpected side effects.let readPosts = new WeakSet();// ... when post is clicked onpostList.addEventListener('click', (event) =&gt; {  // ...  readPosts.add(post); // Adds object to a group of read posts});// ... rendering postsfor (let post of postArray) {  if(!readPosts.has(post)) {    _addNewPostClass(post.element);  }}While we can’t read values from a WeakSet, we can check to see if an object is present in the group.Level 5 - Classes and ModulesClassesAdding a Sponsor to the SidebarA common approach to encapsulation in JavaScript is using a constructor function.function SponsorWidget(name, description, url) {  this.name = name;  this.description = description;  this.url = url;}SponsorWidget.prototype.render = function() {  // ...};Constructor functions are invoked with the new operator. Invoking the SponsorWidget function looks like this:let sponsorWidget = new SponsorWidget(name, description, url);sponsorWidget.render();Using the New Class SyntaxTo define a class, we use the class keyword followed by the name of the class. The body of a class is the part betweencurly braces.class SponsorWidget {  render() {    // ...  }}Instance method definitions in classes look just like the method initializer shorthand in objects’.Initializing Values in the Constructor Functionclass SponsorWidget {  // Runs every time a new instance is created with the new operator  constructor(name, description, url) {    // Assigning to instance variables make them accessible to other instance methods    this.name = name;    this.description = description;    this.url = url;  }  render() {    // ...  }}let sponsorWidget = new SponsorWidget(name, description, url);sponsorWidget.render();Accessing Class Instance Variablesclass SponsorWidget {  constructor(name, description, url) {    this.description = description;    this.url = url;  }  render() {    // this.url is an instance variable set in constructor    let link = this._buildLink(this.url);    // ...  }  _buildLink(url) {    // ....  }}There are no access modifiers like private or protected like there are in other languages.Prefixing a method with an underscore is a convention for indicating that it should not be invoked from the publicAPI.The class syntax is not introducing a new object model to JavaScript. It’s just syntactical sugar over the existingprototype-based inheritance (syntactical sugar).Class InheritanceWe can use class inheritance to reduce code repetition. Child classes inherit and specialize behavior defined inparent classes.The extends keyword is used to create a class that inherits methods and properties from another class. The supermethod runs the constructor function from the parent class.class Widget {  constructor() {    this.baseCSS = "site-widget";  }  parse(value) {    // ...  }}class SponsorWidget extends Widget {  constructor(name, description, url) {    super();    // ...  }  render() {    let parsedName = this.parse(this.name);    let css = this._buildCSS(this.baseCSS);  }}Overriding Inherited MethodsChild classes can invoke methods from their parent classes via the super object.class Widget {  constructor() {    this.baseCSS = "site-widget";  }  parse(value) {    // ...  }}class SponsorWidget extends Widget {  constructor(name, description, url) {    super();    // ...  }  parse() {    let parsedName = super.parse(this.name);    return `Sponsor: ${parsedName}`;  }  render() {    // ...  }}Super holds a reference to the parent version of the parse() method.Modules - Part 1Polluting the Global NamespaceThe common solution for modularizing code relies on using global variables. This increases the chances ofunexpected side effects and potential naming conflicts.These libraries shown below add to the global namespace.&lt;!DOCTYPE html&gt;&lt;body&gt;  &lt;script src="./jquery.js"&gt;&lt;/script&gt;  &lt;script src="./underscore.js"&gt;&lt;/script&gt;  &lt;script src="./flash-messages.js"&gt;&lt;/script&gt;&lt;/body&gt;&lt;script&gt;// In our Javascript we simply reference these globally defined APIslet element = $("...").find(...);let filtered = _.each(...);flashMessage("Hello");&lt;/script&gt;Global variables can cause naming conflicts.Creating ModulesLet’s create a new JavaScript module for displaying flash messages./* flash-messages.js */export default function(message) {  alert(message);}/* app.js */// points to file with .js extension, which must be in the same folder// pulls in 'default' method from the imported fileimport flashMessage from './flash-message';// call to flashMessage methodflashMessage("Hello");Modules still need to be imported via &lt;script&gt;, but no longer pollute the global namespace.&lt;!DOCTYPE html&gt;&lt;body&gt;  &lt;script src="./flash-messages.js"&gt;&lt;/script&gt;  &lt;script src="./app.js"&gt;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;Can’t Default Export Multiple FunctionsModules give us total control over which methods we expose publicly. The default type export limits the number offunctions we can export from a module./* flash-messages.js */export default function(message) {  alert(message);}// Not available outside this modulefunction logMessage(message) {  console.log(message);}Using Named ExportsIn order to export multiple functions from a single module, we can use the named export./* flash-messages.js */export function alertMessage(message) {  alert(message);}export function logMessage(message) {  console.log(message);}/* app.js */import { alertMessage, logMessage } from './flash-message';alertMessage('Hello from alert');logMessage('Hello from log');Importing a Module as an ObjectWe can also import the entire module as an object and call each funtion as a property from this object./* app.js */import * as flash from './flash-message';flash.alertMessage('Hello from alert');flash.logMessage('Hello from log');Removing Repeated Export StatementsInstead of calling export statements every time we want to export (publicly expose) a function, we can instead exportthem as a list with a single command./* flash-messages.js */function alertMessage(message) {  alert(message);}function logMessage(message) {  console.log(message);}export { alertMessage, logMessage };Modules - Part 2Extracting Hardcoded ConstantsRefining constants across our application is unnecessary repetition and can lead to bugs./* load-profiles.js */function loadProfiles(userNames) {  const MAX_USERS = 3;  if(userNames.length &gt; MAX_USERS) {    // ...  }  const MAX_REPLIES = 3;  if(someElement &gt; MAX_REPLIES) {    // ...  }}export { loadProfiles };/* load-profiles.js */function listReplies(replies=[]) {  const MAX_REPLIES = 3;  if (replies.length &gt; MAX_REPLIES) {    // ...  }}export { listReplies };We cannot redefine constants within the same scope, but here we have 3 different functions with their own scope, so thiscode is correct. It’s still unnecessary duplication. The problem is that if we change one constant, then we have to findall the other ones and update them.Exporting ConstantsPlacing constants in their own module allows them to be reused across other modules and hides implementation details(a.k.a., encapsulation)./* constants.js */export const MAX_USERS = 3;export const MAX_REPLIES = 3;/* alternative constants.js */const MAX_USERS = 3;const MAX_REPLIES = 3;export { MAX_USERS, MAX_REPLIES };How to Import Constants**To import constants, we can use the exact same syntax for importing functions./* load-profiles.js */import { MAX_REPLIES, MAX_USERS } from './constants';function loadProfiles(userNames) {  if(userNames.length &gt; MAX_USERS) {    // ...  }  if(someElement &gt; MAX_REPLIES) {    // ...  }}Exporting Class Modules With Default ExportClasses can also be exported from modules using the same syntax as functions. Instead of 2 individual functions, we nowhave 2 instance methods that are part of a class./* flash-message.js */export default class FlashMessage {  constructor(message) {    this.message = message;  }  renderAlert() {    alert(`${this.message} from alert`);  }  renderLog() {    console.log(`${this.message} from log`);  }}The default keyword allows this class to be set to any variable name once it’s imported.Using Class Modules with Default ExportImported classes are assigned to a variable using import and can then be used to create new instances./* app.js */import FlashMessage from './flash-message';let flash = new FlashMessage("Hello");flash.renderAlert();flash.renderLog();Using Class Modules with Named ExportAnother way to export classes is to first define them, and then use the export statement with the class name insidecurly braces./* flash-message.js */class FlashMessage {  // ...}export { FlashMessage };When using named export, the script that loads the module needs to assign it to a variable withthe same name as the class./* app.js */import { FlashMessage } from './flash-message';let flash = new FlashMessage("Hello");flash.renderAlert();flash.renderLog();Level 6 - Promises, Iterators, and GeneratorsPromisesFetching Poll Results From the ServerIt’s very important to understand how to work with JavaScript’s single-thread model. Otherwise, we mightaccidentally freeze the entire app, to the detriment of user experience.Often users will click on a button, a link, or type within an input box, triggering some sort of Javascript action.While these actions occur, they might trigger other actions, such as fetching data from a back-end API.While we wait for a response, we still must be able to interact with the page. If we mess up and write bad code thatblocks the page, we can make elements non-responsive, affecting the user experience.Avoiding Code That BlocksOnce the browser blocks executing a script, it stops running other scripts, rendering elements and responding to userevents like keyboard and mouse interactions.// Page freezes until a value is returned// from the getPollResultsFromServer function.let results = getPollResultsFromServer("Sass vs. LESS");ui.renderSidebar(results);In order to avoid blocking the main thread of execution, we write non-blocking code like this:getPollResultsFromServer("Sass vs LESS", function(results) {  ui.renderSidebar(results);});We are passing a callback to the function now, so that it can be responsible for calling the callback function when itreceives the response from the API server.Passing Callbacks to Continue ExecutionIn continuation-passing style (CPS) async programming, we tell a function how to continue execution by passingcallbacks.One issue is that this can grow to complicated nested code, resulting in error checking on every single callback.getPollResultsFromServer(pollName, function(error, results) {  if (error) {    //.. handle error  }  // ...  ui.renderSidebar(results, function(error) {    if (error) {      //.. handle error    }    // ...    sendNotificationToServer(pollName, results, function(error, response) {      if (error) {        //.. handle error      }      // ...      doSomethingElseNonBlocking(response, function(error) {        if (error) {          //.. handle error        }        // ...      });    });  });});The Best of Both Worlds With PromisesA Promise is a new abstraction that allows us to write async code in an easier way.getPollResultsFromServer("Sass vs. LESS")  .then(ui.renderSidebar)  .then(sendNotificationsToServer)  .then(doSomethingElseNonBlocking)  .catch(function(error) {    console.log("Error: ", error);  });This is still non-blocking, but not using nested callbacks anymore.Creating a New Promise ObjectThe Promise constructor function takes an anonymous function with 2 callback arguments known as handlers.function getPollResultsFromServer(pollName) {  return new Promise(function(resolve, reject) {    // called when the non-blocking code is done executing    resolve(someValue);    // called when an error occurs    reject(someValue);  });}Handlers are responsible for either resolving, or rejecting the Promise.The Lifecycle of a Promise ObjectCreating a new Promise automatically sets it to the pending state. Then, it can do 1 of 2 things: becomefulfilled or rejected.A Promise represents a future value, such as the eventual result of an asynchronous operation.let fetchingResults = getPollResultsFromServer("Sass vs. less");The fetchingResults variable contains the Promise object in the pending state.Resolving a PromiseLet’s wrap the XMLHttpRequest object API within a Promise. Calling the resolve() handler moves the Promise to afulfilled state.function getPollResultsFromServer(pollName){  return new Promise(function(resolve, reject) {    let url = `/results/${pollName}`;    let request = new XMLHttpRequest();    request.open('GET', url, true);    request.onload = function() {      if (request.status &gt;= 200 &amp;&amp; request.status &lt; 400) {        resolve(JSON.parse(request.response));      }    };    // ...    request.send();  });};Reading Results From a PromiseWe can use the then() method to read results from the Promise once it’s resolved. This method takes a function thatwill only be invoked once the Promise is resolved.function getPollResultsFromServer(pollName) {  // ...     resolve(JSON.parse(request.response));  // ...};let fetchingResults = getPollResultsFromServer("Sass vs Less");fetchingResults.then(function(results) {  // renders HTML to the page  ui.renderSidebar(results);});The callback passed to then() will receive the argument that was passed to resolve().Removing Temporary VariablesWe are currently using a temporary variable to store our Promise object, but it’s not really necessary. Let’sreplace it with chaining function calls.getPollResultsFromServer("Sass vs Less")  .then(function(results){    ui.renderSidebar(results);  });Chaining Multiple ThensgetPollResultsFromServer("Sass vs Less")  .then(function(results){    // only returns poll results from Orlando    return results.filter((result) =&gt; result.city === "Orlando");  })  .then(function(resultsFromOrlando){    ui.renderSidebar(resultsFromOrlando);  });Rejecting a PromiseWe’ll call the reject() handler for unsuccessful status codes and also when the onerror event is triggered on ourrequest object. Both move the Promise to a rejected state.function getPollResultsFromServer(pollName) {  return new Promise(function(resolve, reject) {    // ...    request.onload = function() {      if (request.status &gt;= 200 &amp;&amp; request.status &lt; 400) {        resolve(JSON.parse(request.response));      } else {        reject(new Error(request.status));      }    };    request.onerror = function() {      reject(new Error("Error Fetching Results"));    };    // ...    request.send();  });};Rejecting a Promise moves it to a rejected state.Catching Rejected PromisesOnce an error occurs, execution moves immediately to the catch() function. None of the remaining then() functionsare invoked.getPollResultsFromServer("Sass vs Less")  .then(function(results){    // only returns poll results from Orlando    return results.filter((result) =&gt; result.city === "Orlando");  })  .then(function(resultsFromOrlando){    ui.renderSidebar(resultsFromOrlando);  })  .catch(function(error){    console.log("Error: ", error);  });Passing Functions as ArgumentsWe can make our code more succinct by passing function arguments to then, instead of using anonymous functions.function filterResults(results) { // ... }// new method initializer shorthand syntaxlet ui = {  renderSidebar(filteredResults){ // ... }};getPollResultsFromServer("Sass vs. Less")  .then(filterResults)  .then(ui.renderSidebar)  .catch(function(error){    console.log("Error: ", error);  });IteratorsWhat We Know About Iterables So FarArrays are iterable objects, which means we can use them with for…of.let names = ["Sam", "Tyler", "Brook"];for(let name of names) {  console.log(name);}Plain JavaScript objects are not iterable, so they do not work with for…of out-of-the-box.let post = {  title: "New Features in JS",  replies: 19};// TypeError: post[Symbol.iterator] is not a functionfor (let p of post) {  console.log(p);}Iterables Return IteratorsIterables return an iterator object. This object knows how to access items from a collection 1 at a time,while keeping track of its current position within the sequence.let names = ["Sam", "Tyler", "Brook"];for(let name of names) {  console.log(name);}// what's really happening behind the sceneslet iterator = names[Symbol.iterator]();let firstRun = iterator.next();// firstRun: {done: false, value: "Sam"}let name = firstRun.value;let secondRun = iterator.next();// firstRun: {done: false, value: "Tyler"}let name = secondRun.value;let thirdRun = iterator.next();// firstRun: {done: false, value: "Brook"}let name = thirdRun.value;The next() method is called by the loop. Once ‘done’ is true, the loop is ended.Understanding the next MethodEach time next() is called, it returns an object with 2 specific properties: done and value.done(boolean)  Will be false if the iterator is able to return a value from the collection  Will be true if the iterator is past the end of the collectionvalue(any)  Any value returned by the iterator. When done is true, this returns undefined.  { done: true, value: undefined }The First Step Toward an Iterator ObjectAn iterator is an object with a next property, returned by the result of calling the Symbol.iterator method.let post = {  title: "New Features in JS",  replies: 19};post[Symbol.iterator] = function() {  let next = () =&gt; {    // ...  }  return { next };};// Cannot read property 'done' of undefinedfor (let p of post) {  console.log(p);}Navigating the SequenceWe can use Object.keys to build an array with property names for our object. We’ll also use a counter (count) and aboolean flag (isDone) to help us navigate our collection.let post = { // ... }post[Symbol.iterator] = function() {  let properties = Object.keys(this); // returns array with property names  let count = 0; // used to access properties array by index  let isDone = false; // set to true when done with the loop  let next = () =&gt; {    if (count &gt;= properties.length) {      isDone = true;    }    // 'this' refers to the post object    return { done: isDone, value: this[properties[count++]] };  }  return { next };};Running Our Custom IteratorWe’ve successfully made our plain JavaScript object iterable, and it can now be used with for…of.let post = {  title: "New Features in JS",  replies: 19};post[Symbol.iterator] = function() {  // ...  return {next};}// works properly nowfor let(p of post) {  console.log(p);}// works with spread operator alsolet values = [...post];console.log(values); // ['New Features in JS', 19]Iterables With DestructuringLastly, destructuring assignments will also work with iterables.let [title, replies] = post;console.log(title); // New Features in JSconsole.log(replies); // 19GeneratorsGenerator FunctionsThe function ** declaration defines generator functions. These are special functions from which we can use the*yield keyword to return iterator objects.function *nameList() {  yield "Sam";   // { done: false, value: "Sam" }  yield "Tyler"; // { done: false, value: "Tyler" }}It doesn’t matter where you place the star character in-between.function *nameList() { // ... }function* nameList() { // ... }function * nameList() { // ... }Generator Objects and for…ofGenerator functions return objects that provide the same next method expected by for…of, the spread operator,and the destructuring assignment.function *nameList() {  yield "Sam";   // { done: false, value: "Sam" }  yield "Tyler"; // { done: false, value: "Tyler" }}// nameList() returns a generator objectfor (let name of nameList()) {  console.log(name);}let names = [...nameList()];console.log(names); // ["Sam", "Tyler"]let [first, second] = nameList();console.log(first, second); // Sam TylerReplacing Manual Iterator ObjectsKnowing how to manually craft an iterator object is important, but there is a shorter syntax.let post = { title: "New Features in JS", replies: 19};post[Symbol.iterator] = function() {  let properties = Object.keys(this);  let count = 0;  let isDone = false;  let next = () =&gt; {    if (count &gt;= properties.length) {      isDone = true;    }    return { done: isDone, value: this[properties[count++]] };  }  return { next };}Refactoring to Generator FunctionsEach time yield is called, our function returns a new iterator object and then pauses until it’s called again.let post = { title: "New Features in JS", replies: 19};// generator functions can be anonymouspost[Symbol.iterator] = function *() {  let properties = Object.keys(this);  for(let p of properties) {    yield this[p];  }}// this is the same aspost[Symbol.iterator] = function *() {  yield this.title;  yield this.replies;}for (let p of post) {  console.log(p);}// Output:// New Features in JS// 19"
     
   } ,
  
   {
     
   } ,
  
   {
     
        "title"    : "Git",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/git/",
        "date"     : "",
        "content"  : "Back to Cheat SheetsOther Git TipsTable of Contents  Man Pages  Git Branching  Git Checkout  Git Commit  Git Diff  Git Log  Git Push  Git Rebase  Git Remote  Git Remove  Git Reset  Git Stash  Patching  MiscMan Pages# Manuals# You can view the manual pages on any of the commands below by using# 'man git-' followed by the verbs supported by Git such as 'log' or 'commit'man git-logman git-commitGit Branching# view remote branchesgit branch -r# view local and remote branchesgit branch -a# delete local branchgit branch -d my_branch_name# rename branchgit branch -m old_name new_name# delete a tracking branchgit branch -r -d otherguys/master# rename local and remote branchgit branch -m old_name new_namegit push origin :old_name # delete old remote branchgit push origin new_name # create new branch on remotegit branch --set-upstream-to=origin/new_nameGit Checkout# alternative way to clear all changesgit checkout .# clear all changes to one filegit checkout path/to/file# create and switch to new branchgit checkout -b my_branch_name# create and switch to new branch based on remote branchgit checkout -b local_branch_name origin/remote_branch_name# create a branch from an earlier commit (time travel is possible!)git checkout -b oldstuff commit_hash# create a branch that tracks a remote branchgit checkout -b branch_name remote_name/branch_name# merge selected files from another branchgit checkout frombranch thedir/thefile.txt anotherdir/anotherfile.txt# create local branch from remote branchgit checkout -b local_branch_name johndoe/remote_branch_nameGit Commit# update the last commit messagegit commit --amend -m "New message"# update the last commit with current date/timegit commit --amend --reset-authorGit Diff# show unstaged changes since last commitgit diff# show staged and unstaged changes since last commitgit diff HEAD# show changes since second to last commitgit diff HEAD^# show changes since third to last commitgit diff HEAD^^# show changes since 5 commits agogit diff HEAD~5# show changes between most recent and second most recent commitgit diff HEAD^..HEAD# show changes between two commitsgit diff 4fb063f..f5a6ff9# show changes between tagged release and mastergit diff v1.0..master# show changes between two branchesgit diff master my-feature-branch# show changes using time rangesgit diff --since=1.week.ago --until=1.minute.agoGit Log# search for all commits (any branch) by messagegit log --all --grep="contents of message"# view commits in oneline formatgit log --pretty=oneline# view last 20 logs in reverse with raw comment body only# good for reporting work performedgit log --reverse --pretty=format:"%B" -20# view all changes in specific file, ordered from most recent to oldestgit log -p path/to/file# view last 2 changes in specific filegit log -p -2 path/to/file# show statistics on changes to files in each commitgit log --stat# show visual representation of branch mergesgit log --graph# show log in custom format# %ad - author date# %an - author name# %h - SHA hash# %s subject# %d ref namesgit log --pretty=format:"%h %ad- %s [%an]"# show with date rangesgit log --until=1.minute.agogit log --since=1.day.agogit log --since=1.hour.agogit log --since=1.month.ago --until=2.weeks.agogit log --since=2000-01-01 --until=2012-12-21# setup and use alias for complex git commandsgit config --global alias.mylog "log --pretty=format:'%h %s [%an]' --graph"git mylogGit Push# push to remote with upstream tracking specifiedgit push -u origin qa# push branch to remote repository (origin)git push origin my_branch_name# delete remote branchgit push origin :remote_branch_nameGit Rebase# interactive rebase from remote mastergit rebase -i origin/master# interactive rebase from last 4 commitsgit rebase -i HEAD~4Git Remote# view configured remote repositoriesgit remote -v# add remote repositorygit remote add johndoe https://github.com/johndoe/myproject.git# remove remote repositorygit remote rm johndoeGit Remove# remove file from repository, without actually deleting# good for files you only want locally, and have added to .gitignoregit rm --cached mylogfile.logGit Reset# clear all changesgit reset --hard# undo a successful merge or commitgit reset --hard HEAD^# undo a successful commit, keep changesgit reset --soft HEAD^Git Stash# save current unstaged changes to stashgit stash# save current unstaged changes to stash with descriptiongit stash save &lt;message&gt;# view list of stashesgit stash list# apply first stash to current branchgit stash apply stash@{0}# drop first stashgit stash drop stash@{0}# clear all stored stashesgit stash clearPatching# create patch based on single commitgit format-patch -1 73699d42 --stdout &gt; mycommit.patch# create patch file (auto generated name) for current feature branch,# using remote master as basegit format-patch origin/master# check for errors before apply patchgit apply --check file.patch# inspect / view statistics for patchgit apply --stat file.patch# apply a patchgit am file.patchTagging# delete git tag with specific namegit tag -d tagName# delete remote taggit push origin :refs/tags/tagNameMisc# show log of commits affecting specific filegit whatchanged path/to/file# display revisions and author for each line of a file (lines 450 - 470)git blame -L 450,470 lib/file_name.rb# show commit SHA, author, and date for changes to filegit blame index.html --date short# apply changes from local commit to current branchgit cherry-pick 04567899ae36651daf3dfa117a1088d594632370# create a commit that reverts a previous commitgit revert 04567899ae36651daf3dfa117a1088d594632370# view changes in commit, using SHA hashgit show 6d3b08115028d013d676bc03ece72db3e6e06225"
     
   } ,
  
   {
     
        "title"    : "Setting Up a Rails Development Environment for PC Users",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/setting-up-rails-development-environment-for-pc-users/",
        "date"     : "2011-10-22 23:16:50 -0700",
        "content"  : "Ubuntu LinuxIf you're using a PC instead of a Mac, I recommend that you develop your Ruby on Rails application using Ubuntu Linux instead of Windows. Some Ruby Gems are dependent on software which is available for Linux or Mac OS X, but has not yet been ported to Windows (at least in a compatible manner). The Ruby on Rails community also consists of a majority of Linux or Mac OS X users, so most documentation that you find on various Rails related topics will provide instructions which apply to the commands for those operating systems, and not Windows. Overall using a Unix-based operating system to develop your Rails application will mean less headaches.Ubuntu is the easiest Linux distribution for use as a server or desktop operating system. It supports most hardware without requiring complex steps to make. There is also an abundance of documentation supporting the use of Ubuntu to perform various tasks.You can install Ubuntu without needing to prepare a separate partition on your hard drive via the Windows Installer for Ubuntu known as WUBI. WUBI places a file which contains the entire Ubuntu system in the root of your existing Windows partition, and configures your computer to provide you the choice of using Windows or Ubuntu when you start the computer.Alternatively you can run Ubuntu using Virtualbox inside of Windows, so you don't have to restart your computer each time you want to start working on your Rails application. This may cause your computer to run slow however, as it involves both operating systems being loaded into memory and run at the same time.Development EnvironmentYour development environment will consist of a text editor for modifying the source code of your application, a terminal which provides a command prompt (or command line interface) for running certain commands, and a web browser for viewing and testing the website application that you are developing on your local machine.Each of these programs we are going to use separately. I'm teaching it to you this way so that you can choose to use an alternative terminal or text editor later if you choose. Choice is good.Or if you find one that works for you, you can look into what is known as an Integrated Development Environment (IDE) which provides a text editor, terminal, web browser, and other tools all in one program. One example is RadRails by Aptana.There is also a web-based IDE tailored for Rails projects called Cloud9. It's free if you're using it with a project that you plan on sharing with the public as an open-source project for free on Github, otherwise you'll need to pay $15 a month.Setting up the Launcher Bar for your ProgramsThe latest version of Ubuntu uses a desktop interface known as Unity. This interface features a bar on the left side of the screen known as the Launcher. When you open any programs from the launcher, the launcher will disappear. If you place your mouse against the far left side of the screen, the launcher will reappear.Click on the 'Dash Home' icon at the top of the launcher to open up another feature of the Unity interface known as the 'Dash'. This area provides options to search and open programs which are installed within your Ubuntu system.Search for 'gEdit' and the Dash will display the 'Text Editor' program, which you'll be using as your text editor. Go ahead and drag this icon to your launcher on the left side of the screen. After the 'gEdit' icon appears in the launcher, feel free to click on the icon and hold for a second or two, then drag the icon nearer to the top of the list of icons.If you right-click on icons, such as 'LibreOffice Impress' (a Microsoft Powerpoint-like program) or 'LibreOffice Calc' (a Microsoft Excel-like program), you can choose 'Remove from launcher' to remove those icons from the launcher so that it's less cluttered.Go ahead and search for 'Terminal' from the dash, and drag this to your launcher.By default Ubuntu will come with Firefox installed. You might want to use Chromium, which is like the Linux version of Google Chrome. You can do this by opening the 'Ubuntu Software Center' program from the dash or your launcher, searching for 'Chromium' and then choosing to install it. After it's installed it will be available if you search for it in the dash, and then drag the icon to your launcher.Text EditorWhen you're spending most of your time coding, you want to make sure that your experience working with code is simple, easy on the eyes, and productive. On Mac OS X there is a program called Textmate which is very popular with programmers because it runs fast, includes a built in file browser, supports syntax coloring (which helps you avoid mistakes), is elegant and easy on the eyes, and includes code completion features.Unfortunately Textmate isn't available for Linux, however the text editor that comes with Ubuntu, gEdit, can be setup to work much like Textmate.Add Plugin Support to gEditFirst open the Ubuntu Software Center and search for 'gedit-plugins'. This will find a package with the description 'Set of plugins for gEdit'. Install this package.Download and Install Monaco FontDownload the Monaco font using this link. After the file is downloaded, open it up from your Home directory under the 'Downloads' folder. It should display examples of how the font looks, and provide an 'Install' button in the bottom right corner. Click on this button to install the font.Darkmate Theme for gEditDownload this Darkmate theme file for gEdit which emulates the color scheme of Textmate which is very easy on the eyes. Install the file by opening gEdit, hold down the ALT key to reveal the menu items at the top of the screen, go to Edit &gt; Preferences &gt; Fonts and Colors. Click on the 'Add' button and then navigate and choose the file from your Downloads folder. After it installs and applies the theme, click on the 'Close' button in the bottom right corner of the Preferences window.File Browser for gEditDownload the last version of the Class Browser plugin for gEdit (version 0.2.1) using this link.  The file is a Tar/Gzip file, which is like a ZIP file that is supported by all the Linux-based operating systems. Open the file and click on the 'Extract' button. This will cause a window to popup and allow you to choose where you wish to extract the plugin folder. Choose your home folder, which bares your user name, and then click on CTRL+H to display the hidden files/folders. Open '.local', then 'share'. You'll see some folders in here, but likely won't see one for 'gedit'. Click on the 'Create folder' button in the top right section and create a folder named 'gedit'. This will place you inside of the folder. Next click on 'Create folder' once again and name it 'plugins'. Click on the 'Extract' button to place the plugin folder under 'plugins'.Open the gEdit text editor, hold down the ALT key and go to Edit &gt; Preferences, then select the Plugins tab. You should have a check mark next to 'File Browser Panel'. Close the Preferences window, and while still holding the ALT key select View &gt; Side Panel. This will cause the file browser to display on the left side of the screen.Installing RubyNow that you have a text editor which has feature which closely resemble Textmate, a Terminal which provides a command prompt, and a web browser, we're ready to install the libraries needed for the Ruby on Rails application.The first step is to install Ruby, which is the program which reads and interprets Ruby code from the scripts you create, an runs those scripts in real time.Ruby version 1.8.7 is recommended because it's known to be stable without causing any issues. Ruby 1.9.2 is also compatible with the latest version of Ruby on Rails (version 3.1), however it's fairly new, and a rule of thumb is that it is best to avoid the newest software if you're not a seasoned developer that can find the cause of a problem, find a solution, and report the bugs or issues that you've found.To install Ruby 1.8.7 for Ubuntu open the Terminal program and run 'sudo apt-get install ruby-full'.jason@ubuntu:/usr/bin$ sudo apt-get install ruby-fullReading package lists... DoneBuilding dependency tree       Reading state information... DoneThe following extra packages will be installed:  libtcltk-ruby1.8 ri1.8 ruby1.8-dev ruby1.8-full tcl8.5 tk8.5Suggested packages:  tclreadlineThe following NEW packages will be installed:  libtcltk-ruby1.8 ri1.8 ruby-full ruby1.8-dev ruby1.8-full tcl8.5 tk8.50 upgraded, 7 newly installed, 0 to remove and 0 not upgraded.Need to get 5,009 kB/5,635 kB of archives.After this operation, 66.2 MB of additional disk space will be used.Do you want to continue [Y/n]? YInstalling Ruby GemsMost programming languages provide standard features such as variables, operators, conditional statements, loops, etc. In addition to these standard features a core set of libraries are typically provided which provide functions for working with the file system, networking, etc.All these features and libraries are the building blocks of any computer program, however there are many common actions which you may want to perform with your program that you would need to program from scratch. Luckily there are programming libraries which are made for free to the public which provide methods for performing certain actions via your own Ruby scripts or Rails application.In some cases you simply download a library file, place it inside of the directories for your project, and then add some sort of command that points to the location of that library file so that its functions may be included and used by your own script.With common Ruby libraries, this isn't necessary because Ruby supports a program known as RubyGems which downloads and installs libraries for you, and then makes those libraries available for inclusion in your scripts without having to know the path of the libraries. These libraries are known as 'gems' in the Ruby community, and the Ruby Gem program relies on the centralized repository of gems which are hosted at http://rubygems.org/.Programs such as Ruby Gems are known as package managers, and are available for many other programming languages as well. For the Perl programming language there is a package manager and repository made available by the Comprehensive Perl Archive Network - CPAN.org. For the PHP programming language there is a package manager and repository made available by the PHP Extension and Application Repository - PEAR.PHP.NET.Rails itself is a Gem, as are the many libraries which the Rails framework relies on (ActiveModel, ActiveResource, ActiveSupport, etc). When you install Rails, these other gems are installed as dependencies, which means that the Rails gem needs them so Ruby Gems installs them as well.To install Ruby Gems on your Ubuntu system you could use the Ubuntu Software Center by searching for 'rubygems', but I'm advising against this because you're not able to use commands such as 'gem --update system' to update Ruby Gems itself.The best thing to do is to go to the RubyForge download page for Ruby Gems and download the latest 'tgz' package. Currently this is rubygems-1.8.10.tgz. Download the package, and then open your Terminal program and run 'cd ~/Downloads/' to switch to the 'Downloads' folder under your home directory. As shown below I used the 'ls' command to view the files in my Downloads folder, which showed that the file was present. Next 'tar -zxvf rubygems-1.8.10.tgz' is the command to extract the contents of the file to the same directory.jason@ubuntu:~$ cd ~/Downloads/jason@ubuntu:~/Downloads$ lsrubygems-1.8.10.tgzgedit_classbrowser-0.2.1  MONACO.TTFjason@ubuntu:~/Downloads$ tar -zxvf rubygems-1.8.10.tgzrubygems-1.8.10/rubygems-1.8.10/.autotestrubygems-1.8.10/.documentrubygems-1.8.10/.gemtestrubygems-1.8.10/bin/...After this completes use 'cd rubygems-1.8.10.tgz' to switch to the new directory that was just created. From within this directory run 'sudo ruby setup.rb' to install Ruby Gems.jason@ubuntu:~/Downloads/rubygems-1.8.10$ sudo ruby setup.rb [sudo] password for jason: RubyGems 1.8.10 installed== 1.8.10 / 2011-08-25RubyGems 1.8.10 contains a security fix that prevents malicious gems fromexecuting code when their specification is loaded.  Seehttps://github.com/rubygems/rubygems/pull/165 for details.* 5 bug fixes:  * RubyGems escapes strings in ruby-format specs using #dump instead of #to_s    and %q to prevent code injection.  Issue #165 by Postmodern  * RubyGems attempt to activate the psych gem now to obtain bugfixes from    psych.  * Gem.dir has been restored to the front of Gem.path.  Fixes remaining    problem with Issue #115  * Fixed Syck DefaultKey infecting ruby-format specifications.  * `gem uninstall a b` no longer stops if gem "a" is not installed.------------------------------------------------------------------------------RubyGems installed the following executables:	/usr/bin/gem1.8This installs Ruby Gems, but doesn't make it available by simply using 'gem' as the command. Run the command 'sudo ln -s /usr/bin/gem1.8 /usr/bin/gem' to create a shortcut to gem1.8 using the command 'gem'.jason@ubuntu:~$ sudo ln -s /usr/bin/gem1.8 /usr/bin/gem[sudo] password for jason: jason@ubuntu:~$ gem --version1.8.10To ensure that it's all up-to-date, run the command 'gem update --system'.jason@ubuntu:~$ sudo gem update --systemUpdating rubygems-updateFetching: rubygems-update-1.8.11.gem (100%)Successfully installed rubygems-update-1.8.11Installing RubyGems 1.8.11RubyGems 1.8.11 installed== 1.8.11 / 2011-10-03* Bug fix:  * Deprecate was moved to Gem::Deprecate to stop polluting the top-level    namespace.------------------------------------------------------------------------------RubyGems installed the following executables:	/usr/bin/gem1.8RubyGems system software updatedjason@ubuntu:~$Installing RailsFrom the Terminal window run the command 'sudo gem install rails'. You'll be prompted to enter your password for your Ubuntu user account. Type this in and press enter again. Remember that sometimes you'll be prompted from the command line to enter your password, and you won't see stars or characters to indicate each character of your password that you're typing in. Just type it in and press ENTER. If you've typed it wrong, try again until it works.The output you get should be similar to this:jason@ubuntu:~$ sudo gem install rails[sudo] password for jason:Fetching: multi_json-1.0.3.gem (100%)Fetching: activesupport-3.1.1.gem (100%)Fetching: builder-3.0.0.gem (100%)Fetching: i18n-0.6.0.gem (100%)Fetching: activemodel-3.1.1.gem (100%)Fetching: rack-1.3.5.gem (100%)Fetching: rack-cache-1.1.gem (100%)Fetching: rack-test-0.6.1.gem (100%)Fetching: rack-mount-0.8.3.gem (100%)Fetching: hike-1.2.1.gem (100%)Fetching: tilt-1.3.3.gem (100%)Fetching: sprockets-2.0.3.gem (100%)Fetching: erubis-2.7.0.gem (100%)Fetching: actionpack-3.1.1.gem (100%)Fetching: arel-2.2.1.gem (100%)Fetching: tzinfo-0.3.30.gem (100%)Fetching: activerecord-3.1.1.gem (100%)Fetching: activeresource-3.1.1.gem (100%)Fetching: mime-types-1.16.gem (100%)Fetching: polyglot-0.3.2.gem (100%)Fetching: treetop-1.4.10.gem (100%)Fetching: mail-2.3.0.gem (100%)Fetching: actionmailer-3.1.1.gem (100%)Fetching: rake-0.9.2.2.gem (100%)Fetching: thor-0.14.6.gem (100%)Fetching: rack-ssl-1.3.2.gem (100%)Fetching: json-1.6.1.gem (100%)Building native extensions.  This could take a while...Fetching: rdoc-3.11.gem (100%)Depending on your version of ruby, you may need to install ruby rdoc/ri data:= 1.9.2 : nothing to do! Yay!Fetching: railties-3.1.1.gem (100%)Fetching: bundler-1.0.21.gem (100%)Fetching: rails-3.1.1.gem (100%)Successfully installed multi_json-1.0.3Successfully installed activesupport-3.1.1Successfully installed builder-3.0.0Successfully installed i18n-0.6.0Successfully installed activemodel-3.1.1Successfully installed rack-1.3.5Successfully installed rack-cache-1.1Successfully installed rack-test-0.6.1Successfully installed rack-mount-0.8.3Successfully installed hike-1.2.1Successfully installed tilt-1.3.3Successfully installed sprockets-2.0.3Successfully installed erubis-2.7.0Successfully installed actionpack-3.1.1Successfully installed arel-2.2.1Successfully installed tzinfo-0.3.30Successfully installed activerecord-3.1.1Successfully installed activeresource-3.1.1Successfully installed mime-types-1.16Successfully installed polyglot-0.3.2Successfully installed treetop-1.4.10Successfully installed mail-2.3.0Successfully installed actionmailer-3.1.1Successfully installed rake-0.9.2.2Successfully installed thor-0.14.6Successfully installed rack-ssl-1.3.2Successfully installed json-1.6.1Successfully installed rdoc-3.11Successfully installed railties-3.1.1Successfully installed bundler-1.0.21Successfully installed rails-3.1.131 gems installedInstalling ri documentation for multi_json-1.0.3...Installing ri documentation for activesupport-3.1.1...Installing ri documentation for builder-3.0.0...Installing ri documentation for i18n-0.6.0...Installing ri documentation for activemodel-3.1.1...Installing ri documentation for rack-1.3.5...Installing ri documentation for rack-cache-1.1...Installing ri documentation for rack-test-0.6.1...Installing ri documentation for rack-mount-0.8.3...Installing ri documentation for hike-1.2.1...Installing ri documentation for tilt-1.3.3...Installing ri documentation for sprockets-2.0.3...Installing ri documentation for erubis-2.7.0...Installing ri documentation for actionpack-3.1.1...Installing ri documentation for arel-2.2.1...Installing ri documentation for tzinfo-0.3.30...Installing ri documentation for activerecord-3.1.1...Installing ri documentation for activeresource-3.1.1...Installing ri documentation for mime-types-1.16...Installing ri documentation for polyglot-0.3.2...Installing ri documentation for treetop-1.4.10...Installing ri documentation for mail-2.3.0...Installing ri documentation for actionmailer-3.1.1...Installing ri documentation for rake-0.9.2.2...Installing ri documentation for thor-0.14.6...Installing ri documentation for rack-ssl-1.3.2...Installing ri documentation for json-1.6.1...Installing ri documentation for rdoc-3.11...Installing ri documentation for railties-3.1.1...Installing ri documentation for bundler-1.0.21...Installing ri documentation for rails-3.1.1...Installing RDoc documentation for multi_json-1.0.3...Installing RDoc documentation for activesupport-3.1.1...Installing RDoc documentation for builder-3.0.0...Installing RDoc documentation for i18n-0.6.0...Installing RDoc documentation for activemodel-3.1.1...Installing RDoc documentation for rack-1.3.5...Installing RDoc documentation for rack-cache-1.1...Installing RDoc documentation for rack-test-0.6.1...Installing RDoc documentation for rack-mount-0.8.3...Installing RDoc documentation for hike-1.2.1...Installing RDoc documentation for tilt-1.3.3...Installing RDoc documentation for sprockets-2.0.3...Installing RDoc documentation for erubis-2.7.0...Installing RDoc documentation for actionpack-3.1.1...Installing RDoc documentation for arel-2.2.1...Installing RDoc documentation for tzinfo-0.3.30...Installing RDoc documentation for activerecord-3.1.1...Installing RDoc documentation for activeresource-3.1.1...Installing RDoc documentation for mime-types-1.16...Installing RDoc documentation for polyglot-0.3.2...Installing RDoc documentation for treetop-1.4.10...Installing RDoc documentation for mail-2.3.0...Installing RDoc documentation for actionmailer-3.1.1...Installing RDoc documentation for rake-0.9.2.2...Installing RDoc documentation for thor-0.14.6...Installing RDoc documentation for rack-ssl-1.3.2...Installing RDoc documentation for json-1.6.1...Installing RDoc documentation for rdoc-3.11...Installing RDoc documentation for railties-3.1.1...Installing RDoc documentation for bundler-1.0.21...Installing RDoc documentation for rails-3.1.1...jason@ubuntu:~$[previous][next]"
     
   } ,
  
   {
     
        "title"    : "Static and Dynamic Resources, and Rewrite Engines",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/static-dynamic-resources-rewrite-engines/",
        "date"     : "2011-10-12 22:03:18 -0700",
        "content"  : "When requesting a single webpage there may be several requests and responses for each resource. A resource being requested may be an HTML coded web page, which then leads to several images which must be requested and loaded inside of the page, as well as other files such as Javascript or CSS libraries needed by the page. This sequence of requests-response transactions which take place between an HTTP client (browser) and an HTTP web server is known as an HTTP session.Static ResourcesStatic resources, such as files containing pure HTML coding, are accessed from the server in the same form as they are on the server itself. For example, many web hosting companies provide access to the files on the server via a File Transfer Protocol (FTP) server program that is also running on the web server. The account owner uses an FTP client program such as FileZilla or Dreamweaver to access and upload files to the directory where the website files reside. The FTP account may provide a directory called 'public_html' or 'public', which represents the web root for the public website. Files put directly into this folder will be available directly from the root of the website.The reason why the folder which contains the website files is a subdirectory of the root folder for the account is so that files which you do not want to be accessed via your website publicly can be uploaded to your account outside of the public_html folder.For a website using 'www.example.com', a file named 'index.html' can be placed in this directory and will be accessible just by going to http://www.example.com/ . This occurs because the web server is configured to provide any files named 'index.html', as the root webpage for the site. Such a file must be overwritten via FTP with a newer version before the content of that webpage changes for the public. If a folder is created in the 'public_html' directory named 'news', and then a file is placed in that directory named 'updates.html', the URL to access the file would be http://www.example.com/news/updates.htmlDynamic ResourcesResources provided by a web server may also be dynamic, which means that the contents of the resource/page are generated on-the-fly by coding placed on the server. This type of coding is known as server side scripting because it is executed on the server and influences the response from the web server before it reaches the clients web browser. This is in contrast with Javascript coding which is a client side scripting language that is executed inside of the web browser, commonly used to modify or animate elements of the web page in the browser in real time. HTML and CSS coding are also interpreted by the browser on the client side, but are not technically considered scripting. HTML is a markup language used to describe elements which are rendered on a page, and cascading style sheets (CSS) is a language used to describe the style/presentation of those elements defined by the HTML.One of the most popular server side coding options available is PHP. Most hosting companies configure their servers to scan files for PHP coding when the files have filenames ending in '.php' instead of the typical '.html' file extension. When found, this PHP coding is executed and dynamically generates certain portions of the page which are provided in the response. This scanning by the web server is also referred to as 'parsing'. This allows PHP coding to be placed in the middle of a file that is predominantly coded in HTML. The HTML coding is provided as is, but the PHP portions of the page are executed and replaced with any text output by the PHP coding.Although dynamic coding is typically used to output text content such as HTML, CSS, or Javascript coding in a dynamic function, it's possible for scripts to also return images if an image library is in use for a specific purpose. This is less likely, but still possible, which is why I've referred to them as static or dynamic resources instead of static or dynamic web pages.Rewrite EnginesMore advanced website applications do not operate within this paradigm where the URL of a specific resource corresponds directly with specific directories or files on the web server. For instance the Wordpress blogging system relies on an extension of the Apache web server known as mod_rewrite to direct all requests directly to the main index.php file located in the root of the directory which stores the Wordpress system files. The index.php file is programmed to compare the request, such as '/2010/02/how-to-tie-your-shoe' to a list of routing rules which determine which internal resource within the Wordpress system should be served, such as a page or blog post.This method makes it so that the website URL for each page is within complete control of the web application instead of the web server it is running under. This method allows website developers to specify URL's for each section of the site which enhance the search engine optimization for those pages. For example a system not using a rewrite engine might provide pages dynamically using the following address:http://www.example.com/index.php?p=5In the above URL 'p=5' is telling the index.php file to provide page ID '5' in the response. Search engines do not prefer to follow links with parameters such as this, as they know all the content is being dynamically fed via scripting driven by a database. They prefer to index pages which were created manually and placed into directories with URL's ending like /about/ or /about/index.html. Rewrite engines make it possible to map such URL's directly to pages which are dynamically generated via your database driven blog, or content management system.The example page provided by a system using a rewrite engine might provide the page via this URL:http://www.example.com/seo-friendly-page-title-goes-here/[previous][parent][next]"
     
   } ,
  
   {
     
        "title"    : "Setting up a Rails Development Environment for Mac Users",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/setting-up-rails-development-environment-for-mac-users/",
        "date"     : "2011-10-13 18:28:05 -0700",
        "content"  : "This article provides instructions for setting up a Ruby on Rails development environment using Mac OS X. Please see the next article for instructions on setup for Windows or Linux.Mac OS X because it's the most popular operating system within the Ruby on Rails community, with many tutorials, screencasts, and other resources devoted toward those developing for Ruby on Rails using Mac OS X.Text EditorWhen you're working on a Ruby on Rails application it's best if you have a text editor which provides Ruby code syntax highlighting / coloring. This makes it easy to detect when you're making a mistake, and makes for a pleasant coding experience (don't you like colors?!). Also important is a project folder viewer which displays the various files in each folder of the project.I highly recommend TextMate. At a price of $55, it's well worth it as it makes your code look beautiful and easy to edit. There are alternative programs such as jEdit, or an entire development environment known as Aptana RadRails, however these are complicated and I don't recommend them to someone who is just getting into Ruby on Rails web development.If you're not wanting to pay for Textmate, then I can recommend RedCar, which runs on jRuby/Java and can be kind of slow, but closely resembles Textmate.If you're working on an open source project, or willing to pay $15 a month, then you can use a web-based IDE tailored for Rails projects called Cloud9.Package ManagementTo work on a Ruby on Rails project, you'll need to use the command line to run certain commands. I also recommend that you setup your computer so that you can installation and use any Linux-based software or libraries which you may find you need to have available at some point in the future.You may be aware that Windows software is made to be installed and run for any version of Windows (XP, Vista, 7), and just the same Mac software will install and run on Mac computers running a recent Mac OS X version (such as Leopard or Lion). Software made for Linux is not so easy to install on any computer running a Linux operating system. This is because Linux software is originally developed and provided as source code, and requires a very technical understanding of how to compile and install the software on the system.At the same time, there are not just versions of Linux (older and newer), but many various distributions that are being maintained and updated. Each distribution, which is put together and distributed by an organization or sometimes by an individual, may store programs, libraries, and configuration files in entirely different directories inside the file system. A Linux distribution may also come with certain systems or utilities which are designed to work with that distributions configuration of programs, libraries, and configuration files. Because of this, there is not a one-size fits all installer available for Linux programs that will work with any distribution.This is why the most popular Linux distributions come with a program known as a Package Manager, which downloads and installs software as packages which are intended for that specific distribution. For example there is a very popular Linux distribution known as Ubuntu, which comes with a package manager called Synaptic. When an Ubuntu user chooses to install the Apache2 web server via Synaptic, a package is downloaded and installed which is specifically designed to work with Ubuntu.For the purpose of this website, the instructions below will help you to create a link to the command line/terminal for your system, install a package manager, and then install the software needed via that package manager. This way your version of Ruby, Apache web server, and other libraries, will all be associated with each other, and will make for a smoother experience without as many complications.Command Prompt for Mac OS X - TerminalThe command line on a Mac is known as 'Terminal' and is available under Applications &gt; Utilities, in the Finder window. Drag this program to your Dock on the bottom of the screen so you can open it quickly and easily in the future as needed.Even though Mac OS X comes packaged with Ruby, we recommend that you install a package manager known as MacPorts and then establish all the software installed by MacPorts as the ones used in your command line environment.Installing RubyThe first step in getting started with Ruby on Rails is to install the Ruby interpreter itself. Many programming languages, such as C or Java, require a program known as a compiler which converts the text coding of the language into an executable program for use on the computer. Ruby is a scripting language that is run by an interpreter program in realtime, like PHP or Perl, and thus it doesn't require compiling. You simply run the command for ruby to execute the script and it does what the script is programmed to do.If you're running Mac OS X, you don't need to install Ruby because you already have it. It is packaged with your operating system.Installing Ruby GemsMost programming languages provide standard features such as variables, operators, conditional statements, loops, etc. In addition to these standard features a core set of libraries are typically provided which provide functions for working with the file system, networking, different types of variables, etc. All these features and libraries are the building blocks of any computer program, however there are many common actions which you may want to perform with your program that you would need to program from scratch. Luckily there are programming libraries which are made for free to the public which provide methods for performing certain actions via your own programs. Typically you simply add the library to a program folder in your program, and then use some sort of command to include that library either globally (available to the whole program), or inside of a specific script where you intend to use the functions of that library.Many programming languages have a package manager program available which aids in the retrieval and installation of these libraries. For the Perl programming language there is a package manager and repository of libraries made available called Comprehensive Perl Archive Network (CPAN). For the PHP programming language there is a package manager and repository of libraries made available through a system known as PHP Extension and Application Repository (PEAR).RubyGems is a package manager for the Ruby programming language which provides program or libraries in packages called 'Gems'. Ruby on Rails itself is a Gem, as are the many libraries which the Rails framework relies on (ActiveModel, ActiveResource, ActiveSupport, etc). After installing a gem, the Ruby interpreter has access to the gem by simply including it. For instance a Ruby script that needs to use the functions contained in the FasterCSV gem simply includes "require 'faster_csv'" at the top of the script.If you're using Mac OS X Leopard or above, you already have Ruby and Ruby Gems running on your computer.Installing RailsAll you need to do is open up the Terminal program from your Applications folder under 'Utilities'. We recommend that you drag the Terminal to your toolbar as you'll be using it often enough as you work on your Ruby on Rails application to make it easily accessible.From the command line of the Terminal program run the command 'sudo gem update rails'. The lines displayed after this command, after you've typed your password and pressed enter, should look similar to this:My-MacBook-Pro: jason$ sudo gem update railsPassword:Updating installed gemsUpdating jquery-railsFetching: jquery-rails-1.0.16.gem (100%)Fetching: activesupport-3.1.1.gem (100%)Fetching: activemodel-3.1.1.gem (100%)Fetching: rack-cache-1.1.gem (100%)Fetching: actionpack-3.1.1.gem (100%)Successfully installed jquery-rails-1.0.16Successfully installed activesupport-3.1.1Successfully installed activemodel-3.1.1Successfully installed rack-cache-1.1Successfully installed actionpack-3.1.1Updating railsFetching: activerecord-3.1.1.gem (100%)Fetching: activeresource-3.1.1.gem (100%)Fetching: actionmailer-3.1.1.gem (100%)Fetching: railties-3.1.1.gem (100%)Fetching: rails-3.1.1.gem (100%)Successfully installed activerecord-3.1.1Successfully installed activeresource-3.1.1Successfully installed actionmailer-3.1.1Successfully installed railties-3.1.1Successfully installed rails-3.1.1Updating rails-footnotesFetching: rails-footnotes-3.7.5.gem (100%)Successfully installed rails-footnotes-3.7.5Gems updated: jquery-rails, activesupport, activemodel, rack-cache, actionpack, activerecord, activeresource, actionmailer, railties, rails, rails-footnotesInstalling ri documentation for jquery-rails-1.0.16...Installing ri documentation for activesupport-3.1.1...Installing ri documentation for activemodel-3.1.1...Installing ri documentation for rack-cache-1.1...Installing ri documentation for actionpack-3.1.1...Installing ri documentation for activerecord-3.1.1...Installing ri documentation for activeresource-3.1.1...Installing ri documentation for actionmailer-3.1.1...Installing ri documentation for railties-3.1.1...Installing ri documentation for rails-3.1.1...file 'lib' not foundInstalling ri documentation for rails-footnotes-3.7.5...Installing RDoc documentation for jquery-rails-1.0.16...Installing RDoc documentation for activesupport-3.1.1...Installing RDoc documentation for activemodel-3.1.1...Installing RDoc documentation for rack-cache-1.1...Installing RDoc documentation for actionpack-3.1.1...Installing RDoc documentation for activerecord-3.1.1...Installing RDoc documentation for activeresource-3.1.1...Installing RDoc documentation for actionmailer-3.1.1...Installing RDoc documentation for railties-3.1.1...Installing RDoc documentation for rails-3.1.1...file 'lib' not foundInstalling RDoc documentation for rails-footnotes-3.7.5...Note: You will not see stars or other characters as you enter your password. Simply type it and press the 'Enter' key. If you mistyped the password, try again until it works.[previous][next]"
     
   } ,
  
   {
     
        "title"    : "Web Hosting",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/web-hosting/",
        "date"     : "2011-10-12 19:56:18 -0700",
        "content"  : "Data CentersA website is hosted on a web server, accessible via a network such as the Internet or a private local area network through an Internet address known as a Uniform Resource Locator (URL). All publicly accessible websites collectively constitute the World Wide Web. A majority of web servers are located in facilities known as data centers, which providing the space, power, air cooled environment, and bandwidth needed to optimally run a web server with optimal uptime.Hosting TypesThere are several types of hosting you can choose from when deciding to setup a website. These include shared hosting, dedicated hosting, colocation, virtual private servers (VPS), or cloud hosting.Dedicated HostingDedicated hosting is where you pay a hosting company to provide a web server machine to you for the duration of the time you are paying for the service. They build the machine, install the operating system you want (Linux or Windows) and set it up in the data center for you. Typically they also setup their monitoring system to periodically check and make sure your server is still up and running. Another upside to dedicated hosting is that you have full control over the server, instead of limited access to one account like you do with shared hosting.Dedicated hosting costs at least $80 or more per a month, and is only really necessary for businesses which are hosting multiple websites, or a single website which receives a great amount of traffic and/or requires the ultimate amount of uptime. If your website is a core function of your business (such as an online shopping cart system), then you may definitely want to upgrade to dedicated or VPS hosting to ensure optimal uptime of your website(s).ColocationIf you're wanting dedicated hosting, but at a slightly lower cost, or you have a special web server hardware setup, then you'll want to consider colocation. Like dedicated hosting the data center provides the space, power, and bandwidth needed, but you provide the web server yourself. The slightly lower cost may be beneficial, but it can also be difficult in resolving an issue when the data center staff are unfamiliar with your servers hardware and if they do not have compatible parts in stock to repair the server in the event of an issue.Shared HostingShared hosting is where you pay a hosting company for an account on a web server that is already setup and likely hosting many other websites. This is why it's called shared hosting, because you are sharing the server with other websites. This type of hosting is much cheaper than dedicated hosting, at a cost of $6 - $20 per a month depending on the plan you sign up for.Unfortunately however this type of hosting has its downsides. If another website on the server receives a huge amount of traffic all at once, it could slow down or even stop the server from serving your own websites requests. At the same time a shared server may be under utilized by the other websites, so you might have a well responsive website for a fraction of the cost. It's a gamble though, and typically hosting companies like to keep shared servers well utilized to optimize profitability. Because of this shared hosting is only recommended for personal websites, or small organizations where uptime is not critical to the day-to-day operations of the business.Virtual Private ServerA virtual private server is like a mix between dedicated and shared hosting. Like dedicated hosting, you have full access to the server. You can choose the operating system, management system (such as cPanel), or install all the software you want/need from scratch via an Secure Shell (SSH) login to the command line of the server. Like shared hosting, your hosting environment is just one of many on the actual server hardware, however the software running on the server which provides a virtualized server environment is typically designed to limit other VPS servers running from the same machine from hogging the resources (CPU cycles, memory) of the server. This results in a more stable hosting environment than shared hosting, but at a fraction of the cost of a dedicated server.While a Virtual Private Server may be more stable than shared hosting, it is also more limited in the resources available to it than a dedicated server, and thus is best suited for individuals or small organizations which receive light traffic, and yet still require optimal uptime for their website.A VPS is the hosting type recommended for individuals which want to host their first Ruby on Rails project. You have total control over the server, so you can install any gems needed, or configure the server however you need. I highly recommend Linode as a VPS hosting provider. Their service has the best uptime I've ever seen, the tools they provide to manage your VPS are superior, and their documentation is really great also. For instance here is a guide on setting up a VPS to host a Ruby on Rails application using the Passenger mod with the Apache web server under Ubuntu 10.10 Maverick.Cloud HostingThe 'cloud' in cloud hosting is used as a metaphor to represent the Internet, based on the cloud drawing typically used in network diagrams to represent the Internet. The term is currently a buzz word in the IT world, and the definition of what it is has become somewhat vague.Unlike the previous types of hosting outlined above, cloud hosting is not provided by a single machine, but instead by a suite of various computing resources which are virtualized and accessed as a service.For instance, the Amazon S3 (Simple Storage Service) provides simple file hosting. A special API is used to upload images to an Amazon S3 account in special containers known as 'buckets', and then these files/images may be linked to using the appropriate URL for each file. Some websites are setup to host certain assets such as images or file downloads with S3, while still hosting the web pages from a standard web server.One reason why websites choose to use Amazon S3 instead of hosting these assets from the same web server is because it allows web pages to load faster, as most web browsers will only download three files at a time from a single web server. Additionally the Amazon S3 service provides scalability, meaning that no matter how much traffic or space is needed for your files, Amazon S3 has the infrastructure to handle the hosting. This means that a website administrator won't have to worry about migrating all the files to another high capacity server at some point in the future. The service is also provided with high availability, low latency, at a commodity cost.Cloud services may be used individually, or configured to work together to provide an environment much like a VPS. The upside is scalability and high availability, however the cost may exceed that of a VPS depending on your needs. Using cloud hosting services together can require some amount of setup and configuration, and thus companies such as RightScale or Engine Yard have stepped in to combine Amazon cloud services into a single solution. An open source platform known as Scalr is also available as a low cost solution. Cloud services are of course also provided by companies other than Amazon such as Rackspace.Cloud hosting is recommended for organizations which require optimal uptime, and likely expect to grow beyond the capabilities of even the most powerful dedicated servers in the near future.&nbsp;[previous][parent][next]"
     
   } ,
  
   {
     
        "title"    : "Web Technologies",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/web-technologies/",
        "date"     : "2011-10-13 09:58:29 -0700",
        "content"  : "Web BrowsersThe majority of requests made to a web server are from a client computer running a web browser such as Google Chrome, Mozilla Firefox, or Microsoft Internet Explorer. Web browsers and web servers are both designed to communicate using the Hypertext Transfer Protocol (HTTP).Websites are also accessed from web servers by special software created by search engines called robots, such as Googlebot. This software is used by search engines to traverse all the pages, through the links on each page, and index all the content from the websites so that the content may be searched via the search engine.Web ServersThe most popular web server in use is Apache, which hosted approximately 54% of all domains on the Internet as of June 2010. Apache is provided by an open source software foundation and runs on Linux/Unix, Windows, and has been ported to run under Mac OS X (a Unix based operating system).The second most popular web server is Internet Information Services (IIS) provided by Microsoft, and only runs on Windows, and is used to host approximately 26% of domains on the Internet.Third is a new contender called Nginx which is known for being lightweight (using low memory of server machine) and efficient, counted as hosting 5.44% of websites in June 2010. Nginx is also provided via an open source project and runs on practically all operating systems (Linux, Unix, Windows, OS X).HTMLHypertext Markup Language (HTML) is not a programming language, but is a markup language used to describe webpages. A programming language is able to receive input, perform calculations, and output the results. A markup language is only used to describe how a document should be displayed. In the browser an HTML page looks like a document, but the file itself is only text coding which conforms to the standards of the HTML language.HTML standards evolve as time passes. Currently the most popular versions of HTML in use on the Internet are HTML 4, and XHTML 1.1.eXtensible HyperText Markup Language (XHTML) is like HTML, but conforms to the stricter standards of XML. XHTML was introduced to make HTML more extensible, and increase interoperability with other XML based data formats.HTML5 is currently being finalized as the new standard for websites.Learn HTML through W3Schools.eXtensible Markup Language (XML)XML was introduced as a format that could be used to describe not just documents, but is flexible and extensible enough to encapsulate an unlimited number of structured data formats.Many systems today use XML to request or transmit data to other systems on the internet. For instance the Google Checkout service provides an XML API for use by websites wishing to integrate with the payment processing service.Two of the most well known uses of XML are podcasts and RSS feed.  Podcasts feeds are files in a type of XML format which describe information on audio files which can be downloaded and listened to. Podcast subscription software, such as iTunes, is used to track new audio files which are made available via the podcast feeds. When a new audio file becomes available, the software downloads the audio file and typically adds it to the portable audio player device (such as an iPod). Much like podcasts, RSS feeds provide a similar purpose, but instead of providing information on audio files, they instead provide data on documents, such as blog posts, which are provided by a particular website. People who like to keep themselves updated on various topics will subscribe to several sites using a RSS feed reader program. The reader program allows them to scan the titles and excerpts of all the pages/posts which have been made available recently, and choose which ones they wish to link to to read the page/post in its entirety. Google provides a free RSS reader available online by Google known as Google Reader.Cascading Style Sheets (CSS)CSS is used to define the how HTML elements are displayed on a websites pages. This applies not only to the standard HTML elements defined by the language, but can also be specified for element which contain certain id fields (which represent a single specific element), or elements which are assigned to a certain class (for styles which apply to multiple elements).For instance, all the paragraphs displayed on a page will be wrapped in a paragraph tag like so:&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc et ante urna. Morbi facilisis interdum libero, id interdum ligula vestibulum eget. Fusce ipsum libero, viverra eu rutrum ut, ultricies nec libero. Mauris sit amet dolor nec lorem congue dapibus eget id felis. Morbi sit amet orci tellus. Aenean aliquam laoreet metus, ac feugiat erat eleifend at.&lt;/p&gt;CSS coding such as this would be used to define the font type, size, and weight (normal or bold) of the text:&lt;style type="text/css"&gt;  p {       font-family:Arial,Helvetica,sans-serif;      font-weight: normal;      font-size: 12px;   }&lt;/style&gt;Just the same another paragraph might require some sort of special style that is unlike all the other paragraphs throughout the website. For instance a paragraph that displays in a sidebar with a dark background.&lt;p id="sidebar-thanks"&gt;  Thanks for visiting my website. Feel free to check out these links   to my friends websites displayed below.&lt;/p&gt;As you can see this paragraph has an id set to 'sidebar-thanks'. The following CSS coding could be used to ensure that the text is smaller, and that it is white so that it stands out on the dark background of the sidebar it's being displayed inside of.&lt;style type="text/css"&gt;  p#sidebar-thanks {     font-size:9px;     color:#FFFFFF;   }&lt;/style&gt;This paragraph will still be of normal weight, and also be Arial, Helvetica, or san-serif, but will instead be 9 pixels in size, and white instead of the default black.Learn more about CSS at W3Schools.JavascriptJavascript is a client-side scripting language which is included with web pages and is executed only by the web browser that is displaying the page. Javascript is typically used to make modifications to elements displayed on a web page in realtime, instead of requiring the user to submit data to the web server, and wait for the page to reload with a different state from the web server.A common use of Javascript includes providing a popup alert to the user when they attempt to submit an incomplete web form, thus stopping the form from being submitted to the server until all necessary information is present. A method known as Asynchronous Javascript (AJAX) is a newer method of Javascript programming which allows the browser to connect to a script running on the web server (using a server side language such as PHP or Ruby), request and receive certain information, and then present the information inside of the web page without requiring the webpage to reload. One of the most popular demonstrations of this is the Google Maps interface which loads new map images as you click and drag the map to view a new geographic location.jQueryPerforming certain tasks using Javascript can be very tedious in that the common web browsers in use by the public, mentioned above, do not support certain Javascript commands in the same manner. This is especially the case regarding Internet Explorer in comparison to Firefox and Chrome (yes, I dislike Microsoft too). Many Javascript developers in the past have used complex sets of commands to detect the type of web browser being used, and thus execute the proper command that works for that web browser.To avoid this complication altogether there have been libraries/frameworks introduced which provide cross-browser compatible functions so you don't have to worry about which browser your coding will or will not work in. The first Javascript library introduced that gained widespread use was Prototype, which was released in February 2005 to provide the foundation for AJAX support in Ruby on Rails. A library known as Script.aculo.us was released in June of 2005, built upon Prototype to provide easy implementation of visual effects and user interface elements.More recently another library known as jQuery, released in January 2006, has taken the lead as the most popular Javascript frameworks, with jQueryUI being a library which extends jQuery to provide visual effects, animations, and user interface elements, while also supporting various themes which can be easily produced and applied to the webpage interface.RubyRuby is a programming language which was introduced in the mid-1990's by Japanese programmer Yukihiro Matsumoto, also known as 'Matz'. The Ruby language was designed for programmer productivity and fun, stressing that systems need to emphasize human rather than computer needs.Ruby is an object-oriented programming language, which simply means that the language places an emphasis on software elements which are treated as objects which have certain properties, and perform certain actions. Every variable inside of a Ruby program is an object which is of a certain class type, and has several methods which can be performed on it's value. Ruby objects are also reflective, which means that they can reveal information about themselves, such as their class.Many programming languages, such as C or Java, require a program known as a compiler which converts the source code you've written into a program file or files which can then be executed and run on the computer. Ruby is a scripting language that is run by an interpreter program in realtime, similar to other languages such as PHP or Perl, and thus it doesn't require compiling. You simply run the command for ruby to execute the script and it does what the script is programmed to do.For example, let say you install Ruby, then put the following code into a file called 'hello.rb':  puts "Hello World"If you then opened the Terminal, changed to the directory that contains the file, and then ran the command 'ruby hello.rb', you would see something like this:$ ruby hello.rbHello World!$ YAMLSimilar to XML, YAML is simply just another standard for storing various types of structured data. YAML uses a syntax which results in a very clean and easy to read format, utilizing mostly tab characters and colons to describe the structure of the data.Ruby on Rails often uses YAML as the format for configuration files.RailsRuby on Rails is a web application framework, which means that it provides a structure which includes directories, configuration files, and many software libraries, which support the development of website applications. Obviously the name "Ruby on Rails" is meant to communicate the metaphor of using Ruby on a track, much like a train track, which gets you where you want to go smoothly and quickly.A developer which is familiar with the Ruby on Rails framework will be able to easily aquaint themselves with other Ruby on Rails applications they haven't worked on before, as all the various types of files that make up the coding for the application are stored in the same directories, and use the same programming structure. One of the primary philosophies of Ruby on Rails is "Convention over Configuration", which means that a developer only needs to specify unconventional aspects of the application...everything else which is conventionally provided by a website is provided by the Rails system.Ruby on Rails is designed to allow most coding by a web developer to be implemented using the Ruby programming language. For instance all interactions with the database server are handled by Ruby scripts which utilize a Ruby library known as ActiveRecord which converts Ruby commands into the SQL language commands which are sent to a database server such as MySQL, PostgreSQL, SQLite3, Oracle, etc. One benefit of the use of such a library is that a Ruby on Rails system can switch to a different type of database server should the need arise at some point in the future, without a lengthy migration process handled by developers and database administrator staff.ConclusionIf you're looking to dive into web development I recommend that you start with HTML and CSS first. Check out the links to the W3School tutorials provided above. If these aren't working for you, consider buying a book about HTML or CSS.You won't need Javascript, but it's recommended that you learn the basics as soon as you can so that you can use it once the need arises. Your understanding of HTML and CSS will help you become familiar with the structure of the webpage, and how to select certain HTML elements by ID or class. Javascript will help to acquaint you to what is known as the Document Object Model (DOM), which is needed to know which parts of the webpage and browser your Javascript coding can manipulate. Once you understand what options Javascript provides, you can then start to learn jQuery, which will prove to be much easier with less coding. There are many plugins available which rely on jQuery to provide very amazing solutions. For instance if you need to provide a dynamic photo gallery on a website, Gallerific is a very powerful and flexible library which can be used with jQuery to implement a very elegant image gallery solution.You won't need to understand anything more than the basics of XML or YAML to begin working with Ruby on Rails. If you want, you can also learn Ruby before you learn the Rails framework, so that you know the difference between coding which involves Rails libraries, and which are standard Ruby commands, but this isn't completely necessary.[previous][parent][next]"
     
   } ,
  
   {
     
        "title"    : "Introduction",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/introduction/",
        "date"     : "2011-10-12 22:40:23 -0700",
        "content"  : "The pages which make up this course are intended for people who are completely new to website programming. They are designed to provide an explanation of the concepts which experienced web developers are already aware of, and thus provide the prerequisite material needed for a person to jump into a book on Ruby on Rails without being completely lost. In the case of this site, the articles are intended to serve as the prerequisite for the Rails 3 In Action book by Ryan Bigg and Yehuda Katz, which are available in print or ebook versions.As you go through the articles that make up this course you are going to encounter a large number of acronyms. The number of acronyms can be overwhelming, so we ask that you keep in mind that as you work with various website technologies these terms become common. Not all website developers are 100% fluent in the details of every technology, and all developers certainly reference articles on the internet when details on a technology are needed...especially when it comes to coding syntax.This course attempts to provide some simple explanations for technologies which can be explained with much more immense detail. If more detail is wanted, simply use the links provided which should mostly point to the corresponding Wikipedia.org article, although Wikipedia articles can be extremely dry and just as confusing. Feel free to use the 'Contact' page to provide me with any feedback or confusion you may be experiencing from these articles so that I may further elaborate on areas which are still not clearly explaining the needed concepts.[previous][parent][next]"
     
   } ,
  
   {
     
        "title"    : "Project Planning",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/project-planning/",
        "date"     : "2011-10-15 22:18:34 -0700",
        "content"  : "Before we jump into developing an application, we want to plan out what it will do. Imagine that you're working with a client that wants you to build them a website. Exactly what they ultimately want and need might not be immediately available, but a basic idea of what they definitely need from the system now is a start. You can sit down with a pen and paper with the client and kind of diagram everything, but for the purpose of this article we're going to present our diagrams in a digital format created with Gliffy.Example: Social Networking SiteFor our example, we'll imagine that we have a client that wants to build a social networking site, similar to Myspace or Facebook, with profiles for each user which include a photo and information about the user, and the ability to these profiles to associate with each other as contacts of some sort (kind of like how Facebook has 'friends').We'll imagine that the client is wanting this application to be for some specific purpose, like a special community of people, but they haven't worked out all the details in their own mind. They just know so far that they want profiles for each user, with a photo, they want associations between users, and they also want the ability for users to send private messages to each other. The remaining details will come later.Object Oriented CodingRuby is an object oriented language, which means that the resources that you create will have both properties/attributes, and will have certain actions that they perform. For instance you can think of a 'cat' as a type of object which always has two eyes, one nose, one mouth, and one tail (unless the cat has been abused). These are constants which would be hardcoded into what is known as a 'class'. A class is used to create an instance of each individual object, like the blueprint (or DNA) for each individual object. A class might define that each object also has certain properties which change (i.e. are variable), such as the color of the cats hair, or how much it weighs. Actions it might perform include 'meow' or 'walk' or perhaps even 'poop'.This is a typical explanation of classes and objects in an object oriented language, but this example doesn't seem to suggest how object oriented coding applies to real life. Most of the time the actions which an object performs, formally known as 'methods', deal with the properties of the object itself. A real life example that applies with our example project is the 'user' class which would define that each user has a first and last name, stored separately in two properties of the object. There might be a method called 'full_name' which returns both the first and last name together, with a space between the first and last name.If you've done object oriented programming, it may seem silly to input information into the computer and have it store the information in an object temporarily, and then that information is lost as soon as the program is done executing. The point of object oriented programming doesn't make sense when the state of the objects are lost. This is where databases become important. The state of a specific object, such as a 'user', can be loaded from a database record for that user, the user can be modified using the methods of the object which are defined by the class, and then the new state of the object can be saved to the database. This is how Ruby on Rails works. The classes you create for the resources you're working with are called 'models', and the properties of each object are stored in the database once you're done using the methods of that model to modify the resource in some way.DiagramHere is a simple diagram for the first version of our project. It will have users which have a single photos. Users will have many contacts, and users will also have many messages sent to contacts.&nbsp;[previous][next]"
     
   } ,
  
   {
     
        "title"    : "HTTP Port and Request Methods",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/http-port-request-methods/",
        "date"     : "2011-10-13 10:20:16 -0700",
        "content"  : "HTTP PortsA web browser by default will make a request to an HTTP server on port 80, the standard HTTP server port, however it's possible for web servers to use a different port in special circumstances. To specify an alternative port in the address for the request, simply add a colon and the number after the domain. For instance many hosting companies use a system known as cPanel to manage their hosting accounts on a web server. Since the web server runs on port 80, the cPanel administrative interface runs on port 2082 like so: http://www.redconfetti.com:2082/Standard GET and POST RequestsThe most common HTTP method used to make a request of a web server is the 'GET' method, which simply tells the server to provide the contents of a specific resource based on the URL. Upon receiving the request, the server sends back a status line, such as "HTTP/1.1 200 OK" (indicating a successful request), along with the body of the response which is either the HTML webpage being requested, or an error message.For example, here is the GET request sent to a server after the browser has been told to go to http://www.example.com/index.htmlGET /index.html HTTP/1.1Host: www.example.comThe server might then respond with these headers:HTTP/1.1 200 OKDate: Mon, 23 May 2005 22:38:34 GMTServer: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)Last-Modified: Wed, 08 Jan 2003 23:11:55 GMTEtag: "3f80f-1b6-3e1cb03b"Accept-Ranges: bytesContent-Length: 438Connection: closeContent-Type: text/html; charset=UTF-8...and thereafter include the 438 bytes of HTML coding for the index web page in the body of the response.The contents of an HTTP request are not seen in the web browser when requesting a web page, and just the same the 'header' information of the HTTP response provided by the server are not seen in the web browser either. It is only the body of the response which is either rendered in the browser window (such as an HTML web page), or displayed directly (such as images).Sometimes a GET request includes additional information used by the resource. For instance a webpage address such as http://www.redconfetti.com/index.php?page=about&amp;style=black would result in a request such as:GET /index.php?page=about&amp;style=black HTTP/1.1Host: www.example.comThis type of request allows you to see the information being provided to the server in the URL for the page/resource. This method is recommended for webpages which provide different information based on the additional parameters included in the request, but not for scripts/pages which create, update, or delete resources on the server as the URL can be bookmarked and re-used, leading to accidental and unwanted modifications.The second most common HTTP method used with requests to web servers is the 'POST' method. A POST request is the type typically used when a web form is submitted to the server. A web form can either submit information via GET (like shown above) or via a POST request. A POST request includes information in a certain format in addition to the path of the resource.This type of request cannot be accidentally re-submitted to the server, and in fact your browser will specifically ask you if you wish to re-submit the request when you choose to 'Refresh' a page that was loaded via a POST request.A POST request for an email form on a website may look like this:POST /contact/send-email.php HTTP/1.1Host: www.example.comContent-Type: application/x-www-form-urlencodedContent-Length: 46name=John%20Smith&amp;email=john.smith@mailinator.com&amp;message=Hello,How%20are%20you!Other HTTP MethodsHTTP defines nine methods/request types indicating the desired action to be performed on the resource (webpage, image, or other file) being requested. These methods are: HEAD, GET, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, and PATCH.Most people think of HTTP as a simple read-only medium where a browser makes a request and receives information, and the only method available to publish or remove content from a website is via FTP. Tim Berners-Lee, the inventor of the World Wide Web, originally designed the first browser called "WorldWideWeb" as a read/write browser; meaning you could not only browse and read content, but create and edit content too. The majority of websites today only operate through GET requests for the majority of pages, and sometimes use POST for web form submissions, but do not utilize the other HTTP requests types. These other request methods were intended to allow web servers to act like full services which not only provide options to 'GET' resources, but also to create new resources using the 'PUT' request type, or delete resources using the 'DELETE' request type.The PUT method is similar to POST, as it provides data with the request separate of the path of the resource being requested. The DELETE method is much like GET, but is intended for requests to delete certain resources.More detail on the HTTP methods is available W3.org Definitions page.[previous][next]"
     
   } ,
  
   {
     
        "title"    : "Creating Rails Project",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/creating-rails-project/",
        "date"     : "2011-10-15 23:27:34 -0700",
        "content"  : "The first step in creating your Rails project is to open the command line.The 'rails' command is used to generate a new Ruby on Rails application. It's also used for many other functions when you are inside of the root directory of the application that has been generated.If you run the command 'rails --help', you will be shown the options which you can use with the 'rails' command.$ rails --helpUsage:  rails new APP_PATH [options]Options:      [--old-style-hash]         # Force using old style hash (:foo => 'bar') on Ruby >= 1.9      [--skip-gemfile]           # Don't create a Gemfile  -d, [--database=DATABASE]      # Preconfigure for selected database (options: mysql/oracle/postgresql/sqlite3/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)                                 # Default: sqlite3  -O, [--skip-active-record]     # Skip Active Record files      [--skip-bundle]            # Don't run bundle install  -T, [--skip-test-unit]         # Skip Test::Unit files  -r, [--ruby=PATH]              # Path to the Ruby binary of your choice                                 # Default: /opt/local/bin/ruby  -S, [--skip-sprockets]         # Skip Sprockets files      [--dev]                    # Setup the application with Gemfile pointing to your Rails checkout  -j, [--javascript=JAVASCRIPT]  # Preconfigure for selected JavaScript library                                 # Default: jquery  -J, [--skip-javascript]        # Skip JavaScript files  -m, [--template=TEMPLATE]      # Path to an application template (can be a filesystem path or URL)      [--edge]                   # Setup the application with Gemfile pointing to Rails repository  -G, [--skip-git]               # Skip Git ignores and keeps  -b, [--builder=BUILDER]        # Path to a application builder (can be a filesystem path or URL)Runtime options:  -q, [--quiet]    # Supress status output  -s, [--skip]     # Skip files that already exist  -f, [--force]    # Overwrite files that already exist  -p, [--pretend]  # Run but do not make any changesRails options:  -v, [--version]  # Show Rails version number and quit  -h, [--help]     # Show this help message and quitDescription:    The 'rails new' command creates a new Rails application with a default    directory structure and configuration at the path you specify.Example:    rails new ~/Code/Ruby/weblog    This generates a skeletal Rails installation in ~/Code/Ruby/weblog.    See the README in the newly created application to get going.You'll see that there is a section which outlines the database options you can specify. -d, [--database=DATABASE]      # Preconfigure for selected database (options: mysql/oracle/postgresql/sqlite3/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)When creating a new Rails application you can create it so that it's ready to be configured with various database servers. For the purpose of our tutorial, we will be using the MySQL server. We will create our application with the name 'snetwork', configured for a MySQL database, using the following command:rails new snetwork -d mysql[previous][next]"
     
   } ,
  
   {
     
        "title"    : "Capistrano Deployment for Apache2 with Passenger",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/capistrano-deployment-for-apache2-with-passenger/",
        "date"     : "2011-12-29 12:31:19 -0800",
        "content"  : "This page outlines how to configure a Ruby on Rails 3 application with the Capistrano gem, and deploy your application to a remote server running Apache2 and the Passenger (mod_rails) extension.Preparing the ServerCreating Remote User AccountFirst we need to setup the server to host the Rails application. This is done by creating a user account which will have a home directory to store the files being deployed to the server. The following commands will create the user account with a home directory, and provide the user with Bash shell access.useradd -m testuser -s /bin/bashpasswd testuserAdding Public Key to Remote UserAt some point you should have created an SSH key pair for use with the Git repository you're using. Log into the remote server as the new user you've created, and place the contents of your public key file (~/.ssh/id_rsa.pub) inside of the file located at ~/.ssh/authorized_keys under the remote account.Before the '.ssh' folder exists in the remote account, we should create an SSH key pair for the remote account too.testuser@remoteserver:~$ pwd/home/testusertestuser@remoteserver:~$ ssh-keygen -t dsaGenerating public/private dsa key pair.Enter file in which to save the key (/home/testuser/.ssh/id_dsa): Created directory '/home/testuser/.ssh'.Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/testuser/.ssh/id_dsa.Your public key has been saved in /home/testuser/.ssh/id_dsa.pub.The key fingerprint is:8e:69:75:a8:ba:c0:9a:a2:90:67:69:40:48:14:64:37 testuser@remoteserverThe key's randomart image is:+--[ DSA 1024]----+|o*.E             ||+ b .            ||..               ||.        .       ||.       S .      || + .   3 .       ||o x   = .        ||o* . n           ||*   o.           |+-----------------+Once this is completed, you can switch to the .ssh folder and create the 'authorized_keys' folder, and paste your own public key onto the first line inside of the file.testuser@remoteserver:~$ cd .sshtestuser@remoteserver:~/.ssh$ nano authorized_keysWith your local computers private key added to the 'authorized_keys' file of the remote account, you'll be able to login to the remote account via SSH from your local computer without a password (or at least using the password setup with your SSH key pair).Next copy the public key under ~/.ssh/id_dsa.pub on the remote server, and configure your Git repository to with the remote users public key so that the remote user may download updates from the Git repository.Setting up Deployment ScriptFor our Rails application we will use Capistrano to deploy updates to our application to the live server, with the server configured to use Passenger (mod_rails) with Apache2.Assuming that the Rails application has already been setup on your local machine in a directory, initialized to be a local Git repository that is configured to push to an upstream server, we first need to setup the Rails application to be used with the Capistrano gem.Install Capistrano GemRun the following from the command line to install the Capistrano gem if you haven't already.gem install capistranoConfigure Rails Application to Require CapistranoOpen your Gemfile in your Rails application root folder and add the following on a new line so that Capistrano is available in the Rails application environment.gem 'capistrano'While you have the Gemfile open, also add the 'execjs' and 'therubyracer' gem requirements in the assets group to ensure that the application deploys successfully without errors with the new Sprockets/Asset Pipeline system which precompiles assets (images, stylesheets, Javascript) under the /public folder when pushing your application out to the remote server.group :assets do  gem 'sass-rails',   '~> 3.1.5'  gem 'coffee-rails', '~> 3.1.1'  gem 'uglifier', '>= 1.0.3'  gem 'execjs'  gem 'therubyracer'endAdd Deployment Configuration to ApplicationFrom the root directory of your application, run the following command to setup your application to use Capistrano for deployment. This adds a file named 'deploy.rb' under your 'config' folder.capify .Open the deploy.rb file and paste the following deployment recipe into the file, and then change the repository address, usernames, passwords, and other items as needed.##############################################################	Application#############################################################set :application, "testapplication"##############################################################	Settings############################################################## runs 'bundle install' during deployment# precompiles assets in productionrequire "bundler/capistrano"load "deploy/assets"default_run_options[:pty] = true  # Must be set for the password prompt from git to workset :use_sudo, false##############################################################	Servers#############################################################set :user, "testuser"  # The remote server user for deploysset :scm_passphrase, "remoteuserpassword"  # The remote server user's passwordset :deploy_to, "/home/#{user}"set :ssh_options, { :forward_agent => true }set :domain, "myapplicationdomain.com"server domain, :app, :webrole :db, domain, :primary => true##############################################################	Git#############################################################set :scm, :gitset :repository,  "git@git.myrepository.com:testapp.git"set :branch, "master"set :deploy_via, :remote_cache##############################################################	Passenger#############################################################namespace :passenger do  desc "Restart Application"    task :restart do      run "touch #{current_path}/tmp/restart.txt"    endendafter :deploy, "passenger:restart"You can view a list of Capistrano tasks which are available, much like Rake tasks by using the 'cap -T' command.$ cap -Tcap bundle:install           # Install the current Bundler environment.cap deploy                   # Deploys your project.cap deploy:assets:clean      # Run the asset clean rake task.cap deploy:assets:precompile # Run the asset precompilation rake task.cap deploy:check             # Test deployment dependencies.cap deploy:cleanup           # Clean up old releases.cap deploy:cold              # Deploys and starts a `cold' application.cap deploy:migrate           # Run the migrate rake task.cap deploy:migrations        # Deploy and run pending migrations.cap deploy:pending           # Displays the commits since your last deploy.cap deploy:pending:diff      # Displays the `diff' since your last deploy.cap deploy:restart           # Blank task exists as a hook into which to inst...cap deploy:rollback          # Rolls back to a previous version and restarts.cap deploy:rollback:code     # Rolls back to the previously deployed version.cap deploy:setup             # Prepares one or more servers for deployment.cap deploy:start             # Blank task exists as a hook into which to inst...cap deploy:stop              # Blank task exists as a hook into which to inst...cap deploy:symlink           # Updates the symlink to the most recently deplo...cap deploy:update            # Copies your project and updates the symlink.cap deploy:update_code       # Copies your project to the remote servers.cap deploy:upload            # Copy files to the currently deployed version.cap deploy:web:disable       # Present a maintenance page to visitors.cap deploy:web:enable        # Makes the application web-accessible again.cap invoke                   # Invoke a single command on the remote servers.cap passenger:restart        # Restart Applicationcap shell                    # Begin an interactive Capistrano session.Some tasks were not listed, either because they have no description,or because they are only used internally by other tasks. To see alltasks, type `cap -vT'.Extended help may be available for these tasks.Type `cap -e taskname' to view it.Run 'cap deploy:setup' to configure the remote account to contain the folders needed to host the various folders and files needed for our deployed application.$ cap deploy:setup  * executing `deploy:setup'  * executing "mkdir -p /home/testuser /home/testuser/releases /home/testuser/shared /home/testuser/shared/system /home/testuser/shared/log /home/testuser/shared/pids"    servers: ["myapplicationdomain.com"]    [myapplicationdomain.com] executing command    command finished in 122ms  * executing "chmod g+w /home/testuser /home/testuser/releases /home/testuser/shared /home/testuser/shared/system /home/testuser/shared/log /home/testuser/shared/pids"    servers: ["myapplicationdomain.com"]    [myapplicationdomain.com] executing command    command finished in 100msIf this runs successfully, like the example above, use 'cap deploy' to push out the current version of your application in the Git repository to the remote server, which will begin with something like this:$ cap deploy  * executing `deploy'  * executing `deploy:update' ** transaction: start  * executing `deploy:update_code'    updating the cached checkout on all servers    executing locally: "git ls-remote git@git.myrepository.com:testapp.git master"    command finished in 1975ms...After deploying for the first time, you're then free to configure Apache with a configuration similar to the following. With Passenger you simply need to point to the 'public' folder under the 'current' folder which stores the most current deployed version of your application.&lt;VirtualHost *:80&gt;  ServerAdmin your@emailaddress.com  ServerName myapplicationdomain.com  ServerAlias www.myapplicationdomain.com  DocumentRoot /home/testuser/current/public  &lt;Directory "/home/testuser/current/public"&gt;    Options Indexes FollowSymLinks MultiViews    AllowOverride All    Order allow,deny    allow from all  &lt;/Directory&gt;&lt;/VirtualHost&gt;"
     
   } ,
  
   {
     
        "title"    : "Tracking Changes using Git",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/tracking-changes-using-git/",
        "date"     : "2011-10-29 21:11:53 -0700",
        "content"  : "Git is a free distributed revision control system. A revision control system allows developers to submit additions or modifications they make to a software project to a central database known as a repository. Each change made to the source code for the project is known as a commit. With each commit a developer will include a comment which describes what the change is.Unlike other popular revision control systems, such as Subversion, Git allows the developer to make multiple commits to a local repository hosted from their local computer. Once they are ready to share their changes with other developers, they will push the one or many commits they've made locally to the remotely hosted repository. When a developer begins a session of modifying a project, they'll usually run a command to 'pull' all of the latest changes made by other developers to their own local repository. This ensures that changes made by other developers do not conflict with the changes they are about to make.Setting up an SSH Key on your Local MachineChecking for Existing KeysFirst check to see if you have SSH keys setup on your machine.$ cd ~/.ssh-bash: cd: /Users/johnsmith/.ssh: No such file or directoryIf the directory does exist, run 'ls' to see if there is an id_rsa (or id_dsa) and id_rsa.pub (or id_dsa.pub) file present. If so, you already have an SSH key pair setup to with the Git repository.If it is indicated that the directory doesn't exist, you do not have SSH keys setup for your user account on your computer yet. Proceed with these instructions to generate SSH keys below.Generating SSH KeysRun the following command to generate the SSH keys.ssh-keygen -t rsa -C "your_email@youremail.com"When asked for a passphrase, you can provide one, but it's not required. Using a passphrase with your SSH key only makes authentication more secure, and makes it so you have to provide the passphrase each time you connect to a remote server using the key. Other options include the use of a mechanism which provides the password for you when using the SSH keys, such as the keychain provided by Mac OS X.Setting up a Remote RepositoryFor the purposes of this article I will assume that you are using a server running the Ubuntu operating system, a popular Linux distribution used for both desktop and server machines. I highly recommend using a Linode VPS with Ubuntu installed.We'll be using a program known as Gitosis to setup the Git repository that you'll be hosting from the server to keep track of changes made to your application. The first step in accomplishing this is to install Git on your Ubuntu server. This is done using the apt-get package manager which is available from the Ubuntu command line.sudo apt-get install git-coreNext we'll need to download Gitosis, the program which is going to aid in the setup and management of the repositories hosted from the server.cd ~git clone git://eagain.net/gitosis.gitThis will place a folder named 'gitosis' inside of your home directory. Now move this directory to the /usr/local directory where software not provided by apt-get is typically installed.sudo mv gitosis/ /usr/localNext go into the /usr/local/gitosis folder, install Python using apt-get, and then run the setup.py script as a super user (using sudo) inside of the folder to complete the installation.cd /usr/local/gitosissudo apt-get install python-setuptoolssudo python setup.py installNow that Gitosis is installed, the next step is to create a user account on the Ubuntu server which will host the repository for the project, as well as other repositories you choose to add in the future. Run the following command to add the 'git' user which will exist on the server without a password (so no one can login as the 'git' user), with it's home directory specified as /var/git (a proper place for the repositories to be hosted from the system).sudo adduser -system -shell /bin/sh -gecos 'git version control' -group -disabled-password -home /var/git git"
     
   } ,
  
   {
     
        "title"    : "Web Services",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/web-services/",
        "date"     : "2011-10-12 22:32:43 -0700",
        "content"  : "Web ServicesWeb services are software systems designed to allow for communication between two separate systems on a network, or more specifically in this case - the Internet. Often a website will refer to it's web services as an Application Programming Interface (API), as the web service isn't strictly intended to be used by other websites, but also with desktop applications. For instance Twitter's developers website refers to it's programmer integration options as an API.The dominant protocol adopted earlier for web services was SOAP, however most web applications developed with "Web 2.0" standards in mind are adopting RESTful interfaces which correlate with the HTTP methods discussed above.RESTful Web ServicesThe World Wide Web, and thus HTTP, was originally designed to provide a full suite of methods for the creation, reading, updating, and destroying (also known as CRUD) of resources on the web. As such newer website applications are adopting the use of web services/APIs which use HTTP and principles of a software architecture style known as Representational state transfer (REST), known as a RESTful Web API.A RESTful Web API simply provides an interface for managing resources provided by a web application using the GET, POST, PUT, and DELETE methods, while supporting various data types for communication such as XML, JavaScript Object Notation (JSON), or YAML.When you are creating a new set of resource management options in a Ruby on Rails application, it's possible to define the requests which are possible with a certain resource as a RESTful resource that can be managed via a typical web  browser interface, or as a RESTful Web API, thus killing two birds with one stone. More on this will be covered in detail in the article on Rails Routing.[previous][next]"
     
   } ,
  
   {
     
        "title"    : "Search",
        "category" : "",
        "tags"     : "",
        "url"      : "/search/",
        "date"     : "",
        "content"  : "  "
     
   } ,
  
   {
     
   } ,
  
   {
     
        "title"    : "About",
        "category" : "",
        "tags"     : "",
        "url"      : "/about/",
        "date"     : "",
        "content"  : "I am Jason Miller, a Ruby on Rails developer in the San Francisco Bay area.Programming is a learning experience. You try to do something, hit a wall, trial and error, dig deep, triumph (usually) and learn new things. As I do this, I post about it here."
     
   } ,
  
   {
     
        "title"    : "Course Outline",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/course/",
        "date"     : "2011-10-12 17:05:21 -0700",
        "content"  : "The following is a series of articles I worked on in mid 2011, meant to provide a guide for someone new to web development that wished to start with Ruby on Rails. As a whole the course is incomplete, but some of the articles still could provide value to those who stumble upon them. If you wish to use the articles to help yourself get started, feel free to use my contact page to let me know. I’m willing to clean these up a bit, and finish the course with your help, if I know that you wish to use them.&lt;/p&gt;The course was not intended to provide instruction on HTML, CSS, or Javascript. I expect that you can purchase books on these subjects, or even refer to W3Schools links I’ve just provided to learn more about those languages. HTML and CSS are definitely needed as prerequisites to working with Ruby on Rails. HTML is easy enough to learn. CSS just takes a little bit of experience and time to pick up and work with fluently. I’m still learning Javascript, even though I have a working knowledge of it, so it’s not a total requirement to jump into the world of web development.It might be a bit simpler to start people out with a server side language such as PHP, but I’m interested in helping people dive right into a website development framework (Rails) that is based on an even more flexible and beautiful language known as Ruby.The course provided by this site provides an explanation of the concepts which experienced web developers are already aware of, and thus provide the prerequisite material needed for a person to jump into a book on Ruby on Rails without being completely lost. In the case of this site, the articles are intended to serve as the prerequisite for the Rails 3 In Action book by Ryan Bigg and Yehuda Katz, which are available in print or ebook versions.  Introduction  Web Technologies  Static and Dynamic Resources, and Rewrite Engines  Setting up a Rails Rails Development Environment for Mac Users  Setting Up a Rails Development Environment for PC Users  Project Planning  Creating Rails Project  Web Hosting  Capistrano Deployment for Apache2 with Passenger  HTTP Port and Request Methods  Web Services"
     
   } ,
  
   {
     
        "title"    : "Presentations",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/presentations/",
        "date"     : "",
        "content"  : "Back to ResourcesThe following presentation is a work in progress. I’m using it to take notes as I discovernew approaches that can help my development skills.The presentation uses Reveal.js. During the presentation you can use the ‘S’ key to access the speaker view, where speaker notes are present, along with a timer and a preview of the next slide. You can also press the ‘B’ key to pause the presentation (darken the screen).  Ruby Tips"
     
   } ,
  
   {
     
        "title"    : "Notes",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/notes/",
        "date"     : "",
        "content"  : "  ECMAScript 2015  ReactJS"
     
   } ,
  
   {
     
        "title"    : "Cheat Sheets",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/",
        "date"     : "",
        "content"  : "Back to ResourcesHere are my own personal cheat sheets. I’ve organized some into their own pages, or simply added a few commands below.  Git  RVM  RubyGems  Rails  Rails Tests  MySQL  PostgreSQL  Vagrant  Docker  Node Package Manager (NPM)  Linux  Mac OS  VimActiveRecord# Get name of table associated with modelModel.table_name# Get field/column names from database tableModel.column_namesCapistrano# View available Capistrano tasksbundle exec cap -vTPostgres# ---------------------------# Shell Commands# ---------------------------# Open Console (database name required, use 'postgres' database first time)$ psql database_name$ psql myapp_development# ---------------------------# Console Commands# ---------------------------# List Databases\list# Switch to another database\c database_name# List tables\dt# Quit Postgres Console\qPGP Encryption / DecryptionSee Introduction to GnuPG for more detail.# install using homebrewbrew install gpg# generate your personal keygpg --gen-key# list keysgpg --list-keys# list secret keysgpg --list-secret-keys# encrypt a file (requires specifying recipient)gpg -e -r jsmith@example.com secret.txt# decrypt and view encrypted file contentsgpg -d secret.txt.gpg# decrypt and save file contents to a new filegpg -d -o secret.txt secret.txt.gpg# import a persons public keygpg --import publickey.txt# get ASCII-armored public keygpg --output publickey.txt --armor --export jsmith@example.com"
     
   } ,
  
   {
     
        "title"    : "Resources",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/",
        "date"     : "",
        "content"  : "  Cheat Sheets  Presentations  Links  Rails Course"
     
   } ,
  
   {
     
        "title"    : "Links",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/links/",
        "date"     : "",
        "content"  : "Back to ResourcesCode Courses  CodeSchool - Provides many high quality courses covering several paths(HTMl/CSS, Javascript, Ruby, Python, iOS, Git, and Databases)  EggheadSandboxes  JsFiddle - Free solution with collaboration features  JsBin - Free solution, with upgraded features availablefor $18.90 monthly / $145.50 yearly  Plunker - Provides options for chat and collaborationwith other remote developers  CodePen  [Repl.it] - Create and share code examples, withexecution and output, for many languages (Javascript, Ruby, Python, PHP, Go,etc.)JavaScript Libraries  PrismJS - lightweight, extensible syntax highlighter  Shower - HTML presentation engine. See GithubOrganizational Tools  Pinboard - Social bookmarking for $11 yearly, alternative to Delicious.$25 yearly and they will store copies of the pages you bookmark (just in casethey might go away)  Dragdis - Look a bookmarking platform, but visually oriented. Appearsdesigned for visual inspiration, like Pinterest for the web.  Phabricator - Coding development platform similar to Github, created andused by FacebookCollaboration Tools  Codeassium - Collaborative code editor, video conferencing, code execution  Cloud9 - Cloud / browser based IDE. Includes built in terminal, imageeditor, and language tools.  Nitrous - A development platform with a collaborative web IDE.  Koding - A social development platform with real-time collaborativefeatures. Requires AWS EC2 instance for back-end.  CodeAnywhere - Cross platform Web IDE  Kobra - Realtime collaborative coding, with built invideo &amp; voice chat. Not meant to be an IDE.Transpilers  EMScripten - Compiles C and C++ into highly-optimizable JavaScript in asm.js format. This lets you run C and C++ on the web at near-native speed,without plugins.Javascript  React JS  Fightcode - Program and fight robots usingJavascript  Brief history of JavaScript ModulesAngularJS  ng-newsletter - Build custom directives with AngularJS  Egghead.io - Lessons on Javascript, CSS, AngularJS 1 &amp; 2, React, NodeJS, and more  Thinkster - Lessons on AngularJS, React, Ionic, Firebase, and Swift"
     
   } ,
  
   {
     
        "title"    : "Linux",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/linux/",
        "date"     : "",
        "content"  : "Back to Cheat SheetsUse the man command to read more about any of the following commands.For example, you can read more about the file command by running man file.Misc commands# Discover a files type (text, executable, etc)file /bin/bash# Create Tar Gzip archivetar -cvzf archive.tar.gz /path/to/folder/# scan network for hostssudo nmap -sS -O -v 192.168.0/24# View Manual Page for Executable Utilityman cp# Search for Manuals by Keywordman -k directories# view calendarcalgrep# reveal 10 lines before, and 20 lines after matching line for contextgrep -B10 -A20 'HTTP 404' /path/to/filetop# view running processes, including threadstop -Hsudo# list the sudo privileges for the current usersudo -ltmuxCommands# Create a named sessiontmux new -s session_name# List sessionstmux list-sessionstmux ls# Attach to a sessiontmux attach -t session_name# List infotmux info# List tmux commandstmux list-commands# List configured key bindings and commandstmux list-keysKey Bindings  CTRL + B (the “PREFIX”)  PREFIX % - Split panes vertically  PREFIX " - Split panes horizontally  PREFIX arrow_key - Move to another pane  PREFIX + arrow_key - Hold the prefix while pressing to resize pane  PREFIX z - Toggle between pane and fullscreen  PREFIX c - Open a new window  PREFIX number_key - Switch to a window by number  PREFIX l - Toggle between current and last window  PREFIX d - Detach from session"
     
   } ,
  
   {
     
        "title"    : "Mac OS",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/mac-os/",
        "date"     : "",
        "content"  : "Back to Cheat SheetsMany other modifications can be found in Mathias Bynens DotfilesOpen Current or Other Folder in Finderopen .open ~/ProjectsDisable the Dock’s Bounce to Alert behaviorIf you prefer to not have application icons in your dock bounce to alert you, you can run the following:defaults write com.apple.dock no-bouncing -bool TRUEkillall DockChanging the location of screenshotsBy defaults the screenshots you take using ⌘ + 3, or ⌘ + 4 show up on your desktop. You can reconfigurethese to show up in a different folder you specify.# See the location where screenshots are placeddefaults read com.apple.screencapture location# Create a screenshots folder and set it as the new locationmkdir -p ~/Screenshotsdefaults write com.apple.screencapture location ~/Screenshotskillall DockAutomatically quit printer app once the print jobs completedefaults write com.apple.print.PrintingPrefs "Quit When Finished" -bool trueDisable Writing Behavior in Applications# Disable automatic capitalization as it’s annoying when typing codedefaults write NSGlobalDomain NSAutomaticCapitalizationEnabled -bool false## Disable smart dashes as they’re annoying when typing codedefaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false## Disable automatic period substitution as it’s annoying when typing codedefaults write NSGlobalDomain NSAutomaticPeriodSubstitutionEnabled -bool false# Disable smart quotes as they’re annoying when typing codedefaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false# Disable auto-correctdefaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false"
     
   } ,
  
   {
     
   } ,
  
   {
     
        "title"    : "MySQL",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/mysql/",
        "date"     : "",
        "content"  : "Back to Cheat SheetsCommand Line Commands# Log into MySQL server as root with password$ mysql -u root -pMySQL Client Commands# quit clientquit;# show list of databasesshow databases;# use databaseuse redconfetti;# show tables in current databaseshow tables;# create user account accessible from localhostCREATE USER 'user'@'localhost' IDENTIFIED BY 'secretpass';# create user account accessible from any hostCREATE USER 'user'@'%' IDENTIFIED BY 'secretpass';# grant all privileges on database to userGRANT ALL PRIVILEGES ON my_database.* TO 'user'@'%';"
     
   } ,
  
   {
     
        "title"    : "NPM",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/npm/",
        "date"     : "",
        "content"  : "Back to Cheat SheetsCommon Commands# Update Node Package Managernpm install -g npm# Initialize an NPM managed project, creating packages.jsonnpm init# Install Package, and add to packages.json as dependencynpm install package-name --save# Uninstall Packagenpm uninstall package-name --save# List installed packages# Also points out installed packages that are not dependencies as "extraneous".npm ls# Remove Installed Packages that are not dependenciesnpm prune# List outdated packagesnpm outdated# Install Package as production dependencynpm install --save-prod gulp# Install Package as development dependencynpm install --save-dev gulp# Install Package Globally (used for CLI tools)npm install -g gulp# Detect Global Packages that need updatingnpm outdated -g --depth=0# Publish / Unpublish Module to NPM Registrynpm publishnpm unpublish# Register NPM User Account from Command Line# You can view this user account on the web by inserting your username into this URL:# https://www.npmjs.com/~your-usernamenpm adduser# Display NPM Configurationnpm config ls# Increment the Version of your Packagenpm version patchnpm version majornpm version minornpm version prereleasenpm version preminornpm version premajorCreating a Node ModuleUsing npm init you can completely setup a packages.json file that defines your module.In the “main” Javascript file specified, index.js, you can define properties on the “export” object and these properties will be accessible from your package.# index.jsexports.printMsg = function() {  console.log("This is a message from the demo package");}Javascript using module dependencyvar demo = require('npm-demo-pkg');demo.printMsg()# // outputs "This is a message from the demo package" to consolePublishing Node ModulesThe name and version are the only fields required in your packages.json file.You have to have a registered user account in the NPM registry. You can accomplish this using npm adduser.Once this is completed, you simply use npm publish to push your new package up to the NPM registry. To update your package you will need to first update the version in packages.json, then use npm publish. You can also use the npm version command to increment the version.Semantic VersioningProjects should start out released as version 1.0.0. Anything before 1.0.0, such as version 0.2.1 would be considered a pre-release (i.e. Alpha, Beta, etc). After the first stable release, the following should apply:Bug fixes and other minor changes: Patch release, increment the last number, e.g. 1.0.1New features which don’t break existing features: Minor release, increment the middle number, e.g. 1.1.0Changes which break backwards compatibility: Major release, increment the first number, e.g. 2.0.0When you are specifying the version of a package that you want in your packages.json file, as a dependency, you can use the following formats to specify that you only want patch update, no minor or major updates.Update Latest Patch Versions Only  1.4  ~1.4.2  1.4.xUpdate Latest Minor Versions Only  1  1.x  ^1.4.0Update to Latest Major Version  * (asterisk)  xScoped PackagesA scoped package has a name that begins with your username like so:{  "name": "@username/project-name"}You can initialize your package using the –scoped argument like so:npm init --scope=usernameIf you create scoped packages all the time, you can configure NPM to do this by default in your ~/.npmrc file.npm config set scope usernameScoped packages are private by default. NPMjs.com requires that you be a paid member to host your own private packages with them. Public scoped packages are free however without requiring a membership. You can publish a package, and set it as public for all future publishes, using this command:npm publish --access=publicTo use a scoped package, you simply include the username before the package name like so:npm install @username/project-name --save// in your project require the package like sovar projectName = require("@username/project-name")"
     
   } ,
  
   {
     
        "title"    : "PostgreSQL",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/postgresql/",
        "date"     : "",
        "content"  : "Back to Cheat SheetsThese commands are specific to Postgres installed on a Mac using Homebrew. I recommend using Lunchy to manage the daemons running on Mac OSX machines.See also PostgreSQL SELECT DocsCommand Line Commands# initialize your Postgres database cluster (collection of databases managed by Postgres server)$ initdb /usr/local/var/postgres -E utf8# Start Postgres server manually$ pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start# Stop Postgres server manually$ pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log stop# Create a user without a corresponding database$ createuser myusername --no-createdb --no-superuser --no-createrole --pwprompt# Create a databse with owner specified$ createdb my_database --owner=myusername# Drop a database$ dropdb my_database# Use PostgreSQL command line client to view default 'postgres' table$ psql postgres# Use PostgreSQL command line client to connect as a specific user, connected to specific database$ psql -U myusername -d my_database# Run an PostgreSQL command with user specified$ psql -c 'CREATE DATABASE my_database WITH OWNER myusername ENCODING 'UTF8';' -d canvas_test# Backup single database to file$ pg_dump my_database &gt; backup_file_path# Restore single database from file$ psql my_database &lt; backup_file_path# Backup entire database cluster$ pg_dumpall &gt; full_backup_file_path# Restore entire database clusterpsql -f full_backup_file_path postgresPSQL Client Commands-- get list of non SQL commands\?-- execute query every 5 secondsselect id from tablename limit 5; \watch 5-- list databases\l-- connect to database\c my_database-- list tables in connected database\dt-- list columns on table\d table_name-- quit psql client\q"
     
   } ,
  
   {
     
        "title"    : "Rails Tests",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/rails-tests/",
        "date"     : "",
        "content"  : "Back to Cheat SheetsThese may be helpful to some, but truthfully I highly recommend learning how to use Rspec instead. The tests are much easier to read and write. You can use Rspec Rails for Ruby on Rails projects, and have the ability to test your controllers separate from your views. It even has tests for routes, just in case you might need them.# Run Test Unit Testruby -Itest test/unit/post_test.rb# Run Test Unit Test Methodruby -Itest test/unit/post_test.rb -n test_the_truth# Run a specific RSpec filerspec spec/models/post_spec.rb# Run a specific example group (using line number) in RSpec filerspec spec/models/post_spec.rb:545# Run a specific Cucumber featurecucumber features/manage_posts.feature# Run a specific Cucumber scenario (using line number) in feature filecucumber features/manage_posts.feature:33"
     
   } ,
  
   {
     
        "title"    : "Ruby on Rails",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/rails/",
        "date"     : "",
        "content"  : "Back to Cheat SheetsGenerate New Rails App# Generate for API onlyrails new my_app --api# Using MySQL databaserails new_my_app --database=mysql# Using PostgreSQL databaserails new my_app --database=postgresql# Without Turbolinksrails new my_app --skip-turbolinks# Without JavaScriptrails new my_app --skip-javascriptrails new my_app -J# Without Sprocketsrails new my_app --skip-sprocketsrails new my_app -S# Without Testsrails new my_app --skip-test# Don't run Bundle Installrails new my_app --skip-bundle# Preconfigure for app-like JavaScript with Webpack (options: react/vue/angular)rails new my_app --webpack=WEBPACK# Preconfigure for Vue with Webpackrails new my_app --webpack=vueRake Tasks# Display Rails routing tablerake routes"
     
   } ,
  
   {
     
        "title"    : "ES2015 Notes",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/notes/react-js/",
        "date"     : "",
        "content"  : "Powering Up with ReactCodeSchool CourseLevel 1. First ComponentWhat is React?React is a JavaScript library for building user interfaces (UIs). Some people use it as the V in MVC.Why React?React was build to solve one problem: building large applications with data that changes over time.Conceived at FacebookHeavily used on products made by Facebook and Instagram. Built to simplify the process of building complex UIs.After Facebook open-sourced React, it’s now used by Dropbox, AirBNB, Instagram, Netflix, and Paypal.PrerequisitesJavascript BasicsSee http://javascript-roadtrip.codeschool.com/  Declaring variables  Creating and invoking functionsES2015See http://es2015.codeschool.com/  Class Syntax  Arrow functions  Spread operatorWhat We’ll LearnWe’ll cover some of the features React offers, including how to:  Write React components  Render data to the page  Make components communicate  Handle user events  Capture user input  Talk to remote serversComponent-based ArchitectureIn React, we solve problems by creating components. If a component gets too complex, we break it into smaller, simplercomponents.We’ll first focus on a comment section added to a page, which features a simple form where a person can enter theirname and comment, then click on the ‘Post Comment’ button. Below this is a list of comments. This entire interface isstored inside of a “StoryBox” component.Inside of the StoryBox component is a StoryForm component that contains the form that users can use to add stories tothe feed, as well as a separate Story component for each story displayed in the feed.What is a React Component?A component in React works similar to JavaScript functions: It generates an output every time it is invoked.With a React component a render() method is called, which generates the HTML:&lt;div&gt;  &lt;p&gt;Good Morning&lt;/p&gt;  &lt;p&gt;10:45AM&lt;/p&gt;&lt;/div&gt;10 minutes later we run the render() method again, and instead it generates:&lt;div&gt;  &lt;p&gt;Good Morning&lt;/p&gt;  &lt;p&gt;10:55AM&lt;/p&gt;&lt;/div&gt;The Virtual DOM ExplainedThe virtual DOM is an in-memory representation of real DOM elements generated by React components before anychanges are made to the page.When the component is rendered, the HTML that is being generated is the Virtual DOM. The output is then transformedinto actual HTML within the browsers DOM.The Virtual DOM in ActionWhy go through the extra step? Because using the Virtual DOM makes the updates to the actual DOM faster.Virtual DOM diffing allows React to minimize changes to the DOM as a result of user actions — therefore,increasing browser performance.With the example shown above, the second time the component renders the HTML, the time has changed. The diffing makesthe update faster.Creating Our First React ApplicationWe want to simply print a message to the screen using a React component.Components in React are JavaScript classes that inherit from the React.Component base class./* components.js */// Components are written in upper camel case// Component class inherits from a React base classclass StoryBox extends React.Component {  // every component needs a render() function  render() {    return( &lt;div&gt;Story Box&lt;/div&gt; );  }}You don’t have to put quotes around the markup that is being returned, because of JSX. It allows us to include HTML inour JavaScript.Now we need to tell our application where to put the result into our web page.Rendering Our First React ComponentWe use ReactDOM to render components to our HTML page as it reads output from a supplied React component and adds itto the DOM.class StoryBox extends React.Component {  render() {    return( &lt;div&gt;Story Box&lt;/div&gt; );  }}// first arg: Invokes the StoryBox component (no quotes needed)// second arg: The target container where component will be rendered toReactDOM.render(  &lt;StormBox /&gt;, document.getElementById('story-app'));Referencing the ComponentEvery time we create a new React component, we use it by writing an element named after the class.class StoryBox → &lt;StoryBox /&gt;This is JSX syntax, so the case used with the component name is important.Application Structure/* components.js */ReactDOM.render(&lt;StormBox /&gt;, document.getElementById('story-app'));The page must contain a DIV with the correct ID.&lt;!-- index.html --&gt;&lt;!DOCTYPE html&gt;&lt;html&gt;  &lt;body&gt;    &lt;div id="story-app"&gt;&lt;/div&gt;  &lt;/body&gt;&lt;/html&gt;That’s all there is to creating a component. Now we just need to add libraries.&lt;!-- index.html --&gt;&lt;!DOCTYPE html&gt;&lt;html&gt;  &lt;body&gt;    &lt;div id="story-app"&gt;&lt;/div&gt;    &lt;!-- Supports React Components --&gt;    &lt;script src="vendors/react.js"&gt;&lt;/script&gt;    &lt;script src="vendors/react-dom.js"&gt;&lt;/script&gt;    &lt;!-- Provides support for ES2015 and JSX code --&gt;    &lt;script src="vendors/babel.js"&gt;&lt;/script&gt;    &lt;script type="text/babel" src="components.js"&gt;&lt;/script&gt;  &lt;/body&gt;&lt;/html&gt;Project Folder  index.html  components.js  vendors          react.js      react-dom.js      babel.js      Our React Application FlowTo clarify, here is what takes place when we load a page with a React component:  index.html is opened  dependencies defined in index.html are loaded  StoryBox component is rendered, then applied to the actual DOM elementQuick Recap on React  React was built to solve one problem: building large applications with data that changes over time  In React, we write apps in terms of components  We use JavaScript classes when declaring React components  Components must extend the React.Component class and must contain a render() method  We call the ReactDOM.render() function to render components to a webpageLevel 1 - Section 2No Quotes Around MarkupThe markup we use when writing React apps is not a string. This markup is called JSX (JavaScript XML).class StoryBox extends React.Component {  render() {    // HTML elements are written in lowercase    return( &lt;div&gt;Story Box&lt;/div&gt; );  }}ReactDOM.render(  // React components are written in upper camelcase  &lt;StoryBox /&gt;, document.getElementById('story-app'));JSX is just another way of writing JavaScript with a transpile step.// JSX&lt;div&gt;Story Box&lt;/div&gt;// Transpiled JSX CodeReact.createElement('div', null, 'Story Box')// JSX&lt;StoryBox /&gt;// Transpiled JSX CodeReact.createElement(StoryBox, null)This may take some getting used to, but will feel natural after gaining confidence in using it.Getting Used to the JSX SyntaxJSX looks similar to HTML, and it is ultimately transformed into JavaScript.class StoryBox extends React.Component {  render() {    return(      &lt;div&gt;        &lt;h3&gt;Stories App&lt;/h3&gt;        &lt;p className="lead"&gt;Sample paragraph&lt;/p&gt;      &lt;/div&gt;    );  }}Notice above how the attribute on the paragraph is ‘className’ instead of ‘class’. This is because ‘class’ is areserved JavaScript keyword.// Transpiled JSX codeReact.createElement("div", null,  React.createElement("h3", null, "Stories App"),  React.createElement("p", {className: "lead"}, "Sample paragraph"));Browsers do not understand JSX, but they do understand JavaScript. They are able to run the transpiled JavaScriptthat is created from the JSX, which then is applied as HTML within the DOM.&lt;div data-reactroot&gt;  &lt;div&gt;    &lt;h3&gt;Stories App&lt;/h3&gt;    &lt;p class="lead"&gt;Sample paragraph&lt;/p&gt;  &lt;/div&gt;&lt;/div&gt;Using the Date Object in JSXHere, we’re displaying the current time using JavaScript’s native Date object and JSX.class StoryBox extends React.Component {  render() {    const now = new Date();    return(      &lt;div&gt;        &lt;h3&gt;Stories&lt;/h3&gt;        &lt;p className="lead"&gt;          Current time: {now.toTimeString()}        &lt;/p&gt;      &lt;/div&gt;    );  }}Code written within curly braces gets interpreted as literal JavaScript in JSX.Iterating Arrays in JSXHere, we’re displaying a list of elements using JSX and JavaScript’s native map function.class StoryBox extends React.Component {  render() {    // ...    const topicsList = ['HTML', 'JavaScript', 'React'];    return(      &lt;div&gt;        &lt;ul&gt;          { topicsList.map( topic =&gt; &lt;li&gt;{topic}&lt;/li&gt; ) }        &lt;/ul&gt;      &lt;/div&gt;    );  }}In the above code, the JSX is converted to:&lt;li&gt;HTML&lt;/li&gt;&lt;li&gt;JavaScript&lt;/li&gt;&lt;li&gt;React&lt;/li&gt;Quick Recap on JSX  JSX stands for JavaScript XML.      JSX markup looks similar to HTML, but ultimately gets transpiled to JavaScript function calls, which React willknow hot to render to the page.    Code written within curly braces are interpreted as literal JavaScript  It is a common pattern to map arrays to JSX elements.Level 2 - Talk Through PropsThe App We’re BuildingWe are building a commenting engine that will allow visitors to post comments on a blog post, picture, video, etc.This will allow users to interact with each other, provide social commentary, etc.Adding Components to Our Comments AppWhat the structure of our React app should look like.  CommentBox as the root component  Comment as the re-usable component for each comment displayedPattern for Adding New ComponentsThere are some common things we always do when creating new components.// New class inherits from React.Componentclass NewComponent extends React.Component {  render() {    // render method must return JSX    return ( ... );  }}Coding the Comment ListLet’s start with an HTML mockup and identify potential components by looking at the markup.Here is a mockup of the comment box HTML:&lt;div class="comment-box"&gt;  &lt;h3&gt;Comments&lt;/h3&gt;  &lt;h4&gt; class="comment-count"&gt;2 comments&lt;/h4&gt;  &lt;div class="comment-list"&gt;    &lt;!-- each comment goes here --&gt;  &lt;/div&gt;&lt;/div&gt;Here is an isolated example of what the comment component will render:    &lt;div class="comment"&gt;      &lt;p class="comment-header"&gt;Anne Droid&lt;/p&gt;      &lt;p class="comment-body"&gt;        I wanna know what love is...      &lt;/p&gt;      &lt;div class="comment-footer"&gt;        &lt;a href="#" class="comment-footer-delete"&gt;          Delete Comment        &lt;/a&gt;      &lt;/div&gt;    &lt;/div&gt;Writing the Comment ComponentThe Comment component renders the markup for each comment, including its author and body.class Comment extends React.Component {  render() {    return (      &lt;div className="comment"&gt;        &lt;p className="comment-header"&gt;Anne Droid&lt;/p&gt;        &lt;p className="comment-body"&gt;          I wanna know what love is...        &lt;/p&gt;        &lt;div className="comment-footer"&gt;          &lt;a href="#" className="comment-footer-delete"&gt;            Delete Comment          &lt;/a&gt;        &lt;/div&gt;      &lt;/div&gt;    );  }}We can now reference this component in JSX as &lt;Comment /&gt;.Writing the CommentBox ComponentNow we’ll declare the CommentBox component and use the previously declared Comment component.class CommentBox extends React.Component {  render() {    return (      &lt;div className="comment-box"&gt;        &lt;h3&gt;Comments&lt;/h3&gt;        &lt;h4&gt; className="comment-count"&gt;2 comments&lt;/h4&gt;        &lt;div className="comment-list"&gt;          &lt;Comment /&gt;          &lt;Comment /&gt;        &lt;/div&gt;      &lt;/div&gt;    );  }}As you can see here, we’re using the Comment component twice. The only problem here is that all our comments look thesame.React Components Accept ArgumentsArguments passed to components are called props. They look similar to regular HTML element attributes.class CommentBox extends React.Component {  render() {    return (      &lt;div className="comment-box"&gt;        &lt;h3&gt;Comments&lt;/h3&gt;        &lt;h4&gt; className="comment-count"&gt;2 comments&lt;/h4&gt;        &lt;div className="comment-list"&gt;          &lt;Comment author="Morgan McCircuit" body="Great picture!" /&gt;          &lt;Comment author="Bending Bender" body="Excellent stuff" /&gt;        &lt;/div&gt;      &lt;/div&gt;    );  }}Reading Props in the Comment ComponentArguments passed to components can be accessed using the this.props object.class Comment extends React.Component {  render() {    return (      &lt;div className="comment"&gt;        &lt;p className="comment-header"&gt;{this.props.author}&lt;/p&gt;        &lt;p className="comment-body"&gt;          {this.props.body}        &lt;/p&gt;        &lt;div className="comment-footer"&gt;          &lt;a href="#" className="comment-footer-delete"&gt;            Delete Comment          &lt;/a&gt;        &lt;/div&gt;      &lt;/div&gt;    );  }}Quick Recap on PropsWe just covered a lot of content — here’s a summary of what we learned.  Convert HTML mockup to React components  Created two components: CommentBox and Comment  How to pass arguments to components using props  Props look like HTML element attributesProblem: Props Aren’t Dynamic YetWe are passing literal strings as props, but what if we wanted to traverse an array of objects? In the real world werarely work with hardcoded values.JavaScript Object ArraysTypically, when we consume data from API servers, we are returned object arrays.const commentList = [  { id: 1, author: 'Morgan McCircuit', body: 'Great picture!' },  { id: 2, author: 'Bending Bender', body: 'Excellent stuff' }];Mapping an Array to JSXWe can use JavaScript’s map function to create an array with Comment components.class CommentBox extends React.Component {  // ...  // Underscore helps distinguish custom methods from React methods  _getComments() {    const commentList = [      { id: 1, author: 'Morgan McCircuit', body: 'Great picture!' },      { id: 2, author: 'Bending Bender', body: 'Excellent stuff' }    ];    return commentList.map( () =&gt; {      return (&lt;Comment /&gt;);    });  }}Passing Dynamic PropsThe callback to map takes an argument that represents each element from the calling object.class CommentBox extends React.Component {  // ...  _getComments() {    const commentList = [      { id: 1, author: 'Morgan McCircuit', body: 'Great picture!' },      { id: 2, author: 'Bending Bender', body: 'Excellent stuff' }    ];    return commentList.map( (comment) =&gt; {      return (        &lt;Comment          author={comment.author} body={comment.body} /&gt;      );    });  }}Anything in curly braces is interpreted as literal JavaScript.&lt;img src={this.props.avatarUrl} alt={`${this.props.author}'s picture`} /&gt;Using Unique Keys on List of ComponentsSpecifying a unique key when creating multiple components of the same type can help improve performance. Ithelps React track which element is which within the loop.&lt;Comment  author={comment.author} body={comment.body} key={comment.id} /&gt;Using the _getComments() methodWe’ll store the returned value in a variable named comments and use it for display purposes.class CommentBox extends React.Component {  render() {    const comments = this._getComments();    return(       &lt;div className="comment-box"&gt;         &lt;h3&gt;Comments&lt;/h3&gt;         &lt;h4 className="comment-count"&gt;{comments.length} comments&lt;/h4&gt;         &lt;div className="comment-list"&gt;           // JSX knows how to render arrays of components           {comments}         &lt;/div&gt;       &lt;/div&gt;    );  }  _getComments() { ... }}Incorrect Grammar on the Comments TitleThe title has incorrect grammar in some cases. When title says ’3 comments’ or ’2 comments’, it’s fine, but when itsays ’1 comments’ it’s incorrect grammar.Fixing the Title With Comment CountLet’s write a new method called _getCommentsTitle() that handles the plural case in our title.class CommentBox extends React.Component {  render() {    const comments = this._getComments();    return(      // ...      &lt;h4 className="comment-count"&gt;        {this._getCommentsTitle(comments.length)}      &lt;/h4&gt;      // ...    );  }  _getCommentsTitle(commentCount) {    if (commentCount === 0) {      return 'No comments yet';    } else if (commentCount === 1) {      return '1 comment';    } else {      return `${commentCount} comments`;    }  }}The title now handles different quantities of comments accordingly.Quick Recap on Dynamic Props  How to pass dynamic props using variables  How to map object arrays to JSX arrays for display purposes  Used JavaScript to handle plural case on the titleLevel 3 - Component StateShow and Hide CommentsWe’d like to add a button to the page that will let users toggle the comments.At top of CommentBox it displays the number of comments: “3 Comments”, and also will have a ‘Show Comments’ button.The comments are hidden until this button is clicked on.Once the comments are displayed, the button changes to ‘Hide Comments’. How can we show and hide comments based onbutton clicks?Different Ways to Manipulate the DOM  Direct DOM Manipulation  jQuery, Backbone, etc.  Indirect DOM Manipulation  ReactDirect DOM ManipulationOne way to manipulate the DOM API is by modifying it directly via JavaScript in response to browser events.Events → DOM Updates/* jquery example */$('.show-btn').on('click', function() {  $('.comment-list').show();});$('.hide-btn').on('click', function() {  $('.comment-list').hide();});Indirect DOM ManipulationIn React, we don’t modify the DOM directly. Instead, we modify a component state object in response to user eventsand let React handle updates to the DOM.Events → Update State → DOM UpdatesWe modify the component state, and then let React handle the updates.render() {  if (this.state.showComments) {    // code displaying comments  } else {    // code hiding comments  }}How to Use State in a ComponentThe state is a JavaScript object that lives inside each component. We can access it via this.state.class CommentBox extends React.Component {  render() {    const comments = this._getComments();    if (this.state.showComments) {      // add code for displaying comments    }    return (      &lt;div className="comment-box"&gt;        &lt;h4 className="h4"&gt;{this._getCommentsTitle(comment.length)}&lt;/h4&gt;        &lt;div className="comment-list"&gt;{comments}&lt;/div&gt;      &lt;/div&gt;    );  }}Showing Comments Only if State Is trueclass CommentBox extends React.Component {  render() {    const comments = this._getComments();    let commentNodes;    if (this.state.showComments) {      commentNodes = &lt;div className="comment-list"&gt;{comments}&lt;/div&gt;    }    return (      &lt;div className="comment-box"&gt;        &lt;h4 className="h4"&gt;{this._getCommentsTitle(comment.length)}&lt;/h4&gt;        {commentNodes}      &lt;/div&gt;    );  }}Hiding Comments on the Initial StateWe set the initial state of our component in the class constructor.class CommentBox extends React.Component {  constructor() {    super();    this.state = {      showComments: false    };  }  render() {    // ...  }}When defining a constructor, super() must be called to ensure that the React.Component constructor behavior is keptintact.How to Update a Component’s StateWe don’t assign to the state object directly — instead, we call setState by passing it an object.// wrong, will not workthis.state.showComments = true;// updates showComments propertythis.setState({showComments: true})Calling setState will only update the properties passed as an argument, not replace the entire state object.Causing State ChangeState changes are usually triggered by user interactions with our app.Things that could cause state change:  Button clicks  Link clicks  Form submissions  AJAX requests  And more!Handling Click EventsLet’s add a button that will toggle the showComments state when a click event is fired.class CommentBox extends React.Component {  render() {    // ...    return(      ...        &lt;button onClick={this._handleClick.bind(this)}&gt;Show comments&lt;/button&gt;      ...    );  }  _handleClick() {    this.setState({      showComments: !this.state.showComments    });  }}Button Text Logic Based on StateWe can switch the button text based on the component’s state.class CommentBox extends React.Component {  render() {    // ...    let buttonText = 'Show comments';    if (this.state.showComments) {      buttonText = 'Hide comments';      // ...    }    return(      // ...      &lt;button onClick={this._handleClick.bind(this)}&gt;{buttonText}&lt;/button&gt;      // ...    );  }}Demo: Hide and Show CommentsOur app shows and hides comments when the button is clicked.Quick Recap on State  State represents data that changes over time.  We declare and initial state in the component’s constructor.  We update state by calling this.setState().  Calling this.setState() causes our component to re-render.Level 4 - Synthetic EventsAdding New CommentsWe want to let users add new comments to our app. We will call the new component CommentForm, and it will provideinput fields for the user to provide their name, the comment text, and then click on ‘Post Comment’.New Component: CommentFormCommentForm is a new component that will allow users to add comments to our app. It will be a child of the CommentBox,displayed above the list of Comments.Coding the CommentForm Componentclass CommentForm extends React.Component {  render() {    return (      &lt;form className="comment-form"&gt;        &lt;label&gt;Join the discussion&lt;/label&gt;        &lt;div className="comment-form-fields"&gt;          &lt;input placeholder="Name:" /&gt;          &lt;textarea placeholder="Comment:"&gt;&lt;/textarea&gt;        &lt;/div&gt;        &lt;div className="comment-form-actions"&gt;          &lt;button type="submit"&gt;            Post comment          &lt;/button&gt;        &lt;/div&gt;      &lt;/form&gt;    );  }}Adding an Event Listener to Our FormTo add an event listener to the form, we use the onSubmit prop and pass a handler to it.class CommentForm extends React.Component {  render() {    return (      &lt;form className="comment-form" onSubmit={this._handleSubmit.bind(this)}&gt;        // ...          &lt;input placeholder="Name:" /&gt;          &lt;textarea placeholder="Comment:"&gt;&lt;/textarea&gt;        // ...      &lt;/form&gt;    );  }  _handleSubmit(event) {    // prevents page from reloading when form is submitted    event.preventDefault();  }}Problem: Can’t Access User Input in handleSubmit()We still need a way to access the name and comment field values within the _handleSubmit() function.Accessing Form Data from HandlerWe can use refs for assign form values to properties on the component object.&lt;input placeholder="Name:" ref={(input) =&gt; this._author = input} /&gt;&lt;textarea placeholder="Comment:" ref={(textarea) =&gt; this._body = textarea}&gt;&lt;/textarea&gt;We’ll use these refs to access values from the input elements.class CommentForm extends React.Component {  render() {    return (      &lt;form className="comment-form" onSubmit={this._handleSubmit.bind(this)}&gt;        // ...          &lt;input placeholder="Name:" ref={(input) =&gt; this._author = input} /&gt;          &lt;textarea placeholder="Comment:" ref={(textarea) =&gt; this._body = textarea}&gt;&lt;/textarea&gt;        // ...      &lt;/form&gt;    );  }  _handleSubmit(event) {    // prevents page from reloading when form is submitted    event.preventDefault();  }}What Setting the refs is Actually Doing&lt;input placeholder="Name:" ref={(input) =&gt; this._author = input} /&gt;This is the same as:&lt;input placeholder="Name:" ref={                              function(input) {                                this._author = input;                              }.bind(this)                          } /&gt;The DOM element itself is passed into the callback as ‘input’, with the CommentForm passed as *this* via thebind() call.You may be wondering, who calls this function? React runs ref callbacks on render.Passing the User Input to the CommentBoxclass CommentForm extends React.Component {  render() {    return (        // ...          &lt;input placeholder="Name:" ref={(input) =&gt; this._author = input} /&gt;          &lt;textarea placeholder="Comment:" ref={(textarea) =&gt; this._body = textarea}&gt;&lt;/textarea&gt;        // ...    );  }  _handleSubmit(event) {    event.preventDefault();    // these are populated from refs in JSX    let author = this._author;    let body = this._body;    // this method will be passed as an argument from the parent CommentBox    this.props.addComment(author.value, body.value);  }}Data About Comments Lives in CommentBoxThis is a common pattern with React, where we have to pass references to child components. The array of comments ispart of the CommentBox component, so we need to propagate new comments from CommentForm over to CommentBox.Propagating data about a new comment to CommentBox is simple. You just pass it a callback prop.Using CommentForm to Add CommentsFunctions in JavaScript are first-class citizens, so we can pass them as props to other components.class CommentBox extends React.Component {  render() {    return (      &lt;div className="comment-box"&gt;        &lt;CommentForm addComment={this._addComment.bind(this)} /&gt;        // ...      &lt;/div&gt;    );  }  // this method gets triggered by CommentForm when a new comment is added  _addComment(author, body) {  }}Adding Functionality to Post Commentsclass CommentBox extends React.Component {  render() {    return (      &lt;div className="comment-box"&gt;        &lt;CommentForm addComment={this._addComment.bind(this)} /&gt;        // ...      &lt;/div&gt;    );  }  _addComment(author, body) {    const comment = {      id: this.state.comments.length + 1,      author,      body    };    this.setState({ comments: this.state.comments.concat([comment]) });  }}We are using concat() instead of push(), because concat() returns a new reference to the array, instead of mutating the existing array. This helps React stay fast, by detecting the change that happened in the array earlier on.This comments array doesn’t exist in the state yet though.Comments Are Not Part of the StateCurrently, we’re defining an array every time the _getComments method is called. Let’s move this data to the state.class CommentBox extends React.Component {  // ...  _getComments() {    const commentList = [      { id: 1, author: 'Morgan McCircuit', body: 'Great picture!' },      { id: 2, author: 'Bending Bender', body: 'Excellent stuff' }    ];    // ...  }}To dynamically update the component, we need to move the comments list into the components state.class CommentBox extends React.Component {  constructor() {    super();    this.state = {      showComments: false,      comments: [        { id: 1, author: 'Morgan McCircuit', body: 'Great picture!' },        { id: 2, author: 'Bending Bender', body: 'Excellent stuff' }      ]    };  }}Now they are part of the component state.Rendering Comments From the StateLet’s use the comments from the state object to render our component.class CommentBox extends React.Component {  // ...  _getComments() {    return this.state.comments.map((comment) =&gt; {      return (        &lt;Comment          author={comment.author}          body={comment.body}          key={comment.id} /&gt;      );    });  }}Review: Event Handling in ReactIn order to ensure events have consistent properties across different browsers, React wraps the browser’s nativeevents into synthetic events, consolidating browser behaviors into one API.Form submission handling might work slightly different for each browser, but React provides support for the ‘onSubmit’event.Quick Recap  We use React’s event system to capture user input, including form submissions and button clicks.  Refs allow us to reference DOM elements in our code after the component has been rendered.  Parent components can pass callback functions as props to child components to allow two-way communication.  Synthetic events are a cross-browser wrapper around a browser’s native event system.Level 5 - Section 1 - Talking to Remote Servers5.1 Using Lifecycle Methods to Load CommentsComments Are StaticIn the real world, we’d want to pull comments from an API instead of hard-coding the data.class CommentBox extends React.Component {  constructor() {    super();    this.state = {      showComments: false,      comments: [        { id: 1, author: 'Morgan McCircuit', body: 'Great picture!' },        { id: 2, author: 'Bending Bender', body: 'Excellent stuff' }      ]    };  }}Loading Comments From a Remote ServerLet’s set the initial state of comments as an empty array so we can later populate it with data from an API server.class CommentBox extends React.Component {  constructor() {    super();    this.state = {      showComments: false,      comments: []    };  }}Adding jQuery as a DependencyjQuery will help us make Ajax requests. We can download it from the jQuery website and include it in our HTML page.  index.html  components.js  vendors          react.js      react-dom.js      babel.js      jquery.js      &lt;!DOCTYPE html&gt;&lt;html&gt;  &lt;body&gt;    &lt;div id="story-app"&gt;&lt;/div&gt;    &lt;script src="vendors/react.js"&gt;&lt;/script&gt;    &lt;script src="vendors/react-dom.js"&gt;&lt;/script&gt;    &lt;script src="vendors/jquery.js"&gt;&lt;/script&gt;    &lt;script src="vendors/babel.js"&gt;&lt;/script&gt;    &lt;script type="text/babel" src="vendors/components.js"&gt;&lt;/script&gt;  &lt;/body&gt;&lt;/html&gt;How to Fetch Data in a ComponentLet’s write a class method that will make Ajax requests in the CommentBox component.class CommentBox extends React.Component {  // ...  _fetchComments() {    jQuery.ajax({      method: 'GET',      url: '/api/comments',      success: (comments) =&gt; {        this.setState({comments})      }    });  }}We call the setState method when data is received from the API server. We are using the arrow function because itpreserves the ‘this’ binding to our class.Deciding Where to Call _fetchComments()class CommentBox extends React.Component {  render() {    // ...  }  _fetchComments() {    // ...  }}We cannot call _fetchComments from render(), or else we will get an infinite loop, because the render() method isused by React when new data must be shown inside of the component rendering. fetchComments calls setState, whichcalls render().React’s Lifecycle MethodsLifecycle methods in React are function that get called while the component is rendered for the first time or about tobe removed from the DOM.We will focus on 3 lifecycle methods.  componentWillMount() - called after constructor()  componentDidMount() - called after render()  componentWillUnmount()For a full list of React’s lifecycle methods, visithttps://reactjs.org/docs/react-component.html#the-component-lifecycleIn React, mounting means rendering for the first time. Unmounting means getting removed from the DOM.Fetching Data on the Mounting PhaseThe componentWillMount method is called before the component is rendered to the page.class CommentBox extends React.Component {  componentWillMount() {    _fetchComments();  }  render() {    // ...  }  // ...}Getting Periodic UpdatesIn order to check whether new comments are added, we can periodically check the server for updates. This is known aspolling.Polling Data on the Mounting PhaseThe componentDidMount method is called after the component is rendered to the page. This is a perfect place tostart our polling process.class CommentBox extends React.Component {  // ...  componentDidMount() {    // run comment fetching every 5000 milliseconds (5 seconds)    setInterval(() =&gt; this._fetchComments(), 5000);  }}Updating Component With New CommentsReact optimizes the rendering process by only updating the DOM when changes are detected on the resultingmarkup. When running setState, if the actual state in the Virtual DOM is not modified, no changes occur to the actualpage.  New state value after initial Ajax request → DOM change happens  No new state value after second periodic Ajax request → No DOM change  New state value after third periodic Ajax request → DOM change happensNote: render() is called after each Ajax response because setState is in the response function.Memory Leaks on Page ChangePage changes in a single-page app environment will cause each CommentBox component to keep loading new comments everyfive seconds, even when they’re no longer being displayed.With each new view that is loaded in a single page application, without the browser actually reloading the renderedpage, the setInterval() method sets up yet another interval timer that makes the same request every 5 seconds.Preventing Memory LeaksEach component is responsible for removing any timers it has created. We will remove the timer on the componentWillUnmount method.class CommentBox extends React.Component {  // ...  componentDidMount() {    this._timer = setInterval(      () =&gt; this._fetchComments(),      5000    );  }  componentWillUnmount() {    clearInterval(this._timer);  }}This will ensure that the timer is removed when the component is about to be removed from the DOM.Memory Leak is GoneOur app can be freely navigated through now, without causing multiple unnecessary calls to the API.Reviewing the Steps for Loading Comments  componentWillMount() is called.  render() is called and CommentBox is mounted. “No comments yet” displayed.  Component waits for API response and when it is received, setState() is called, causing render() to be calledagain.  componentDidMount() is called, causing this._fetchComments to be triggered every five seconds.  componentWillUnmount() is called when the component is about to be removed from the DOM and clears thefetchComments timeout.Quick Recap on Lifecycle MethodsLifecycle methods in React are functions that get called during certain phases that components go through.  componentWillMount() is called before the component is rendered.  componentDidMount() is called after the component is rendered.  componentWillUnmount() is called immediately before the component is removed from the DOM.Level 5 - Section 2 - Adding and Deleting Comments on the Server SideDeleting CommentsOur comments have a Delete Comment button now, but no delete actions are associated to it.Deleting from the APIThe CommentBox component needs a new method to delete individual comments.class CommentBox extends React.Component {  // ...  _deleteComment(comment) {    jQuery.ajax({      method: 'DELETE',      url: `/api/comments/${comment.id}`    });  }}Updating the Comment ListWe will not wait for the API request to be finished before updating the component’s state. We will give our userimmediate visual feedback, which is known as an optimistic update.class CommentBox extends React.Component {  // ...  _deleteComment(comment) {    jQuery.ajax({      method: 'DELETE',      url: `/api/comments/${comment.id}`    });    const comments = [...this.state.comments];    const commentIndex = comments.indexOf(comment);    comments.splice(commentIndex, 1);    this.setState({comments});  }}We’re using the spread operator to clone the existing array to comments.Taken from MDN web docs:The const declaration creates a read-only reference to a value. It does not mean the value it holds isimmutable, just that the variable identifier cannot be reassigned. For instance, in the case where the content is anobject, this means the object’s contents (e.g., its parameters) can be altered.splice() is used to add or remove items from an array. SeeArray.prototype.splice().The first argument is the location to begin, the second is the number of items to delete.Passing a Callback Prop to CommentEvents are fired from the Comment component. Since the event handler is defined on the parent componentCommentBox, we’ll pass it as a prop named onDelete.class CommentBox extends React.Component {  // ...  _getComments() {    return this.state.comments.map(comment =&gt; {      return (        &lt;Comment          key={comment.id}          comment={comment}          onDelete={this._deleteComment.bind(this)} /&gt;      );    });  }}Adding an Event Listener to the Delete ButtonLet’s add an event listener to the Delete Comment button and call the onDelete callback prop.class Comment extends React.Component {  render() {    return(      // ...      &lt;a href="#" onClick={this._handleDelete.bind(this)}&gt;        Delete comment      &lt;/a&gt;      // ...    );  }  _handleDelete(event) {    event.preventDefault();    this.props.onDelete(this.props.comment);  }}Inside of _handleDelete() we’re ensuring that the page isn’t reloaded when the link is clicked. Then we’re callingthe function that was passed to the component as ‘onDelete’, and passing it the current comment.Adding a Confirmation to the Delete ButtonLet’s add an if statement and only call the onDelete callback prop if confirm was true.class Comment extends React.Component {  render() {    return(      // ...      &lt;a href="#" onClick={this._handleDelete.bind(this)}&gt;        Delete comment      &lt;/a&gt;      // ...    );  }  _handleDelete(event) {    event.preventDefault();    if (confirm('Are you sure?')) {      this.props.onDelete(this.props.comment);    }  }}confirm() is a native JavaScript function that displays a modal dialog with the message and two buttons(“OK” and “Cancel”).Comments Aren’t Added to a Remote ServerWe would like to post new comments to a remote server so they can persist across sessions.class Comment extends React.Component {  // ...  _addComment(author, body) {    const comment = { id: this.state.comments.length + 1, author, body };    this.setState({ comments: this.state.comments.concat([comment]) });  }}The ID shouldn’t be generated on the client side, but should instead come from the server side. It’s also not makingan Ajax request to sync the comments with the server side.Posting Comments to a Remote ServerWe learned how to add new comments using a form. Now let’s make sure the new comments are sent to a remote server sothey can be persisted.class Comment extends React.Component {  // ...  _addComment(author, body) {    const comment = { author, body };    jQuery.post('/api/comments', {comment})      .success(newComment =&gt; {        this.setState({ comments: this.state.comments.concat([newComment]) });      });  }}Here we’re sending the arguments to the remote API, and then assigning the new comment which contains the server sidegenerated ID into the comment array within the state object.One-way Control FlowControl flows from higher level components down to child components, forcing changes to happen reactively. Thiskeeps apps modular and fast.  The CommentBox component passes the _deleteComment() method to Comment as a callback  The CommentBox component passes the _addComment() method to CommentForm as a callback  The CommentBox component passes the author and body props to each Comment componentWhen a child component needs to send data back to the parent, it does so via a callback.Quick RecapHere’s a review of the two most important things we learned in this section.  Parent components can send data to child components using props.  Child components can accept callback functions as props to communicate back with parent components.    Followup    Screencast: Add a Build System to a React Application  Pluralsight - Building Applications with React and Flux  Pluralsight - React.js on Rails: Building a Full Stack Web App  Pluralsight - Webpack Fundamentals"
     
   } ,
  
   {
     
        "title"    : "RubyGems",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/rubygems/",
        "date"     : "",
        "content"  : "Back to Cheat Sheets# List installed Gemsgem list# Display Gem Filesystem Pathgem which rake# List all Gem Commandsgem help commands# Display all gems that need updatesgem outdated# Install a gemgem install rake# Uninstall a gemgem uninstall rake# Uninstall all gems (does not remove gems in 'global' RVM gemset)gem uninstall -a -d -x -I"
     
   } ,
  
   {
     
        "title"    : "RVM",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/rvm/",
        "date"     : "",
        "content"  : "Back to Cheat Sheets# list all available Ruby versionsrvm list known# list installed ruby versionsrvm list# view requirements for installing certain ruby versionsrvm requirements# install ruby 1.9.2rvm install 1.9.2# use version of rubyrvm use 1.9.2# List Gem Setsrvm gemset list# Create New Gem Setrvm gemset create gemset_name# Use gemsetrvm gemset use gemset_name# Delete gemsetrvm gemset delete gemset_name# Create .rvmrc file for projectcd ~/projects/my_project/rvm --rvmrc --create 1.9.2@my_project"
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
        "title"    : "Tags",
        "category" : "",
        "tags"     : "",
        "url"      : "/tags/",
        "date"     : "",
        "content"  : ""
     
   } ,
  
   {
     
        "title"    : "Vagrant",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/vagrant/",
        "date"     : "",
        "content"  : "Back to Cheat Sheets# creates virtual machine (VM) for first time, or starts the VM if it's not runningvagrant up# view the status of the vagrant VM associated with the current projectvagrant status# shuts down VMvagrant halt# hibernate the VMvagrant suspend# take VM out of hibernationvagrant resume# outputs the status of all VMs for current uservagrant global-status# output the status of the VM for the current projectvagrant status# stop and delete VMvagrant destroy# reapply configuration from Vagrantfile, restart VMvagrant reload# connect to VM via SSHvagrant ssh"
     
   } ,
  
   {
     
        "title"    : "Vim",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/cheat-sheets/vim/",
        "date"     : "",
        "content"  : "Back to Cheat SheetsSearchingTaken from Finding a Word in Vi/VimTo find a word in Vi/Vim, simply type the / or ? key, followed by the word you’re searching for.Once found, you can press the n key to go directly to the next occurrence of the word.Vi/Vim also allows you to launch a search on the word over which your cursor is positioned. To do this, place thecursor over the term, and then press * or # to look it up."
     
   } ,
  
   {
     
   } ,
  
   {
     
        "title"    : "Markdown Demo",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/presentations/reveal.js-3.6.0/plugin/markdown/example/",
        "date"     : "",
        "content"  : "Markdown DemoExternal 1.1Content 1.1Note: This will only appear in the speaker notes window.External 1.2Content 1.2External 2Content 2.1External 3.1Content 3.1External 3.2Content 3.2"
     
   } ,
  
   {
     
        "title"    : "Slide 1.1",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/presentations/reveal.js-3.6.0/test/simple/",
        "date"     : "",
        "content"  : "Slide 1.1var a = 1;Slide 1.2Slide 2"
     
   } ,
  
   {
     
        "title"    : "Simple-Jekyll-Search",
        "category" : "",
        "tags"     : "",
        "url"      : "/bower_components/simple-jekyll-search/",
        "date"     : "",
        "content"  : "Simple-Jekyll-Search====================[![Build Status](https://travis-ci.org/christian-fei/Simple-Jekyll-Search.svg?branch=master)](https://travis-ci.org/christian-fei/Simple-Jekyll-Search)A JavaScript library to add search functionality to any Jekyll blog.Find it on [npmjs.com](https://www.npmjs.com/package/simple-jekyll-search)---idea from this [blog post](https://alexpearce.me/2012/04/simple-jekyll-searching/#disqus_thread)---### Promotion: check out [Pomodoro.cc](https://pomodoro.cc/)# [Demo](http://christian-fei.github.io/Simple-Jekyll-Search/)# Install```bower install --save simple-jekyll-search# ornpm install --save simple-jekyll-search```# Getting startedPlace the following code in a file called `search.json` in the **root** of your Jekyll blog.This file will be used as a small data source to perform the searches on the client side:```------[  {% for post in site.posts %}    {      "title"    : "{{ post.title | escape }}",      "category" : "{{ post.category }}",      "tags"     : "{{ post.tags | join: ', ' }}",      "url"      : "{{ site.baseurl }}{{ post.url }}",      "date"     : "{{ post.date }}"    } {% unless forloop.last %},{% endunless %}  {% endfor %}]```You need to place the following code within the layout where you want the search to appear. (See the configuration section below to customize it)For example in  **_layouts/default.html**:``````# ConfigurationCustomize SimpleJekyllSearch by passing in your configuration options:```SimpleJekyllSearch({  searchInput: document.getElementById('search-input'),  resultsContainer: document.getElementById('results-container'),  json: '/search.json',})```#### searchInput (Element) [required]The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.#### resultsContainer (Element) [required]The container element in which the search results should be rendered in. Typically an ``.#### json (String|JSON) [required]You can either pass in an URL to the `search.json` file, or the results in form of JSON directly, to save one round trip to get the data.#### searchResultTemplate (String) [optional]The template of a single rendered search result.The templating syntax is very simple: You just enclose the properties you want to replace with curly braces.E.g.The template```{title}```will render to the following```Welcome to Jekyll!```If the `search.json` contains this data```[    {      "title"    : "Welcome to Jekyll!",      "category" : "",      "tags"     : "",      "url"      : "/jekyll/update/2014/11/01/welcome-to-jekyll.html",      "date"     : "2014-11-01 21:07:22 +0100"    }]```#### templateMiddleware (Function) [optional]A function that will be called whenever a match in the template is found.It gets passed the current property name, property value, and the template.If the function returns a non-undefined value, it gets replaced in the template.This can be potentially useful for manipulating URLs etc.Example:```SimpleJekyllSearch({  ...  middleware: function(prop, value, template){    if( prop === 'bar' ){      return value.replace(/^\//, '')    }  }  ...})```See the [tests](src/Templater.test.js) for an in-depth code example#### noResultsText (String) [optional]The HTML that will be shown if the query didn't match anything.#### limit (Number) [optional]You can limit the number of posts rendered on the page.#### fuzzy (Boolean) [optional]Enable fuzzy search to allow less restrictive matching.#### exclude (Array) [optional]Pass in a list of terms you want to exclude (terms will be matched against a regex, so urls, words are allowed).## Enabling full-text searchReplace 'search.json' with the following code:```---layout: null---[  {% for post in site.posts %}    {      "title"    : "{{ post.title | escape }}",      "category" : "{{ post.category }}",      "tags"     : "{{ post.tags | join: ', ' }}",      "url"      : "{{ site.baseurl }}{{ post.url }}",      "date"     : "{{ post.date }}",      "content"  : "{{ post.content | strip_html | strip_newlines }}"    } {% unless forloop.last %},{% endunless %}  {% endfor %}  ,  {% for page in site.pages %}   {     {% if page.title != nil %}        "title"    : "{{ page.title | escape }}",        "category" : "{{ page.category }}",        "tags"     : "{{ page.tags | join: ', ' }}",        "url"      : "{{ site.baseurl }}{{ page.url }}",        "date"     : "{{ page.date }}",        "content"  : "{{ page.content | strip_html | strip_newlines }}"     {% endif %}   } {% unless forloop.last %},{% endunless %}  {% endfor %}]```## If search isn't working due to invalid JSON- There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use `remove_chars` as a filter.For example: in search.json, replace```"content"  : "{{ page.content | strip_html | strip_newlines }}"```with```"content"  : "{{ page.content | strip_html | strip_newlines | remove_chars | escape }}"```If this doesn't work when using Github pages you can try ```jsonify``` to make sure the content is json compatible:```"content"   : {{ page.content | jsonify }}```**Note: you don't need to use quotes ' " ' in this since ```jsonify``` automatically inserts them.**##Browser supportBrowser support should be about IE6+ with this `addEventListener` [shim](https://gist.github.com/eirikbacker/2864711#file-addeventlistener-polyfill-js)# Dev setup- `npm install` the dependencies.- `gulp watch` during development- `npm test` or `npm run test-watch` to run the unit tests"
     
   } ,
  
   {
     
        "title"    : "Dependencies",
        "category" : "",
        "tags"     : "",
        "url"      : "/resources/presentations/reveal.js-3.6.0/css/theme/",
        "date"     : "",
        "content"  : "## DependenciesThemes are written using Sass to keep things modular and reduce the need for repeated selectors across files. Make sure that you have the reveal.js development environment including the Grunt dependencies installed before proceeding: https://github.com/hakimel/reveal.js#full-setup## Creating a ThemeTo create your own theme, start by duplicating a ```.scss``` file in [/css/theme/source](https://github.com/hakimel/reveal.js/blob/master/css/theme/source). It will be automatically compiled by Grunt from Sass to CSS (see the [Gruntfile](https://github.com/hakimel/reveal.js/blob/master/Gruntfile.js)) when you run `grunt css-themes`.Each theme file does four things in the following order:1. **Include [/css/theme/template/mixins.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/mixins.scss)**Shared utility functions.2. **Include [/css/theme/template/settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss)**Declares a set of custom variables that the template file (step 4) expects. Can be overridden in step 3.3. **Override**This is where you override the default theme. Either by specifying variables (see [settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss) for reference) or by adding any selectors and styles you please.4. **Include [/css/theme/template/theme.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/theme.scss)**The template theme file which will generate final CSS output based on the currently defined variables."
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } 
  
]

If search isn’t working due to invalid JSON

  • There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use remove_chars as a filter.

For example: in search.json, replace

"content"  : "Simple-Jekyll-Search====================[![Build Status](https://travis-ci.org/christian-fei/Simple-Jekyll-Search.svg?branch=master)](https://travis-ci.org/christian-fei/Simple-Jekyll-Search)A JavaScript library to add search functionality to any Jekyll blog.Find it on [npmjs.com](https://www.npmjs.com/package/simple-jekyll-search)---idea from this [blog post](https://alexpearce.me/2012/04/simple-jekyll-searching/#disqus_thread)---### Promotion: check out [Pomodoro.cc](https://pomodoro.cc/)# [Demo](http://christian-fei.github.io/Simple-Jekyll-Search/)# Install```bower install --save simple-jekyll-search# ornpm install --save simple-jekyll-search```# Getting startedPlace the following code in a file called `search.json` in the **root** of your Jekyll blog.This file will be used as a small data source to perform the searches on the client side:```------[  {% for post in site.posts %}    {      "title"    : "{{ post.title | escape }}",      "category" : "{{ post.category }}",      "tags"     : "{{ post.tags | join: ', ' }}",      "url"      : "{{ site.baseurl }}{{ post.url }}",      "date"     : "{{ post.date }}"    } {% unless forloop.last %},{% endunless %}  {% endfor %}]```You need to place the following code within the layout where you want the search to appear. (See the configuration section below to customize it)For example in  **_layouts/default.html**:``````# ConfigurationCustomize SimpleJekyllSearch by passing in your configuration options:```SimpleJekyllSearch({  searchInput: document.getElementById('search-input'),  resultsContainer: document.getElementById('results-container'),  json: '/search.json',})```#### searchInput (Element) [required]The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.#### resultsContainer (Element) [required]The container element in which the search results should be rendered in. Typically an ``.#### json (String|JSON) [required]You can either pass in an URL to the `search.json` file, or the results in form of JSON directly, to save one round trip to get the data.#### searchResultTemplate (String) [optional]The template of a single rendered search result.The templating syntax is very simple: You just enclose the properties you want to replace with curly braces.E.g.The template```{title}```will render to the following```Welcome to Jekyll!```If the `search.json` contains this data```[    {      "title"    : "Welcome to Jekyll!",      "category" : "",      "tags"     : "",      "url"      : "/jekyll/update/2014/11/01/welcome-to-jekyll.html",      "date"     : "2014-11-01 21:07:22 +0100"    }]```#### templateMiddleware (Function) [optional]A function that will be called whenever a match in the template is found.It gets passed the current property name, property value, and the template.If the function returns a non-undefined value, it gets replaced in the template.This can be potentially useful for manipulating URLs etc.Example:```SimpleJekyllSearch({  ...  middleware: function(prop, value, template){    if( prop === 'bar' ){      return value.replace(/^\//, '')    }  }  ...})```See the [tests](src/Templater.test.js) for an in-depth code example#### noResultsText (String) [optional]The HTML that will be shown if the query didn't match anything.#### limit (Number) [optional]You can limit the number of posts rendered on the page.#### fuzzy (Boolean) [optional]Enable fuzzy search to allow less restrictive matching.#### exclude (Array) [optional]Pass in a list of terms you want to exclude (terms will be matched against a regex, so urls, words are allowed).## Enabling full-text searchReplace 'search.json' with the following code:```---layout: null---[  {% for post in site.posts %}    {      "title"    : "{{ post.title | escape }}",      "category" : "{{ post.category }}",      "tags"     : "{{ post.tags | join: ', ' }}",      "url"      : "{{ site.baseurl }}{{ post.url }}",      "date"     : "{{ post.date }}",      "content"  : "{{ post.content | strip_html | strip_newlines }}"    } {% unless forloop.last %},{% endunless %}  {% endfor %}  ,  {% for page in site.pages %}   {     {% if page.title != nil %}        "title"    : "{{ page.title | escape }}",        "category" : "{{ page.category }}",        "tags"     : "{{ page.tags | join: ', ' }}",        "url"      : "{{ site.baseurl }}{{ page.url }}",        "date"     : "{{ page.date }}",        "content"  : "{{ page.content | strip_html | strip_newlines }}"     {% endif %}   } {% unless forloop.last %},{% endunless %}  {% endfor %}]```## If search isn't working due to invalid JSON- There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use `remove_chars` as a filter.For example: in search.json, replace```"content"  : "{{ page.content | strip_html | strip_newlines }}"```with```"content"  : "{{ page.content | strip_html | strip_newlines | remove_chars | escape }}"```If this doesn't work when using Github pages you can try ```jsonify``` to make sure the content is json compatible:```"content"   : {{ page.content | jsonify }}```**Note: you don't need to use quotes ' " ' in this since ```jsonify``` automatically inserts them.**##Browser supportBrowser support should be about IE6+ with this `addEventListener` [shim](https://gist.github.com/eirikbacker/2864711#file-addeventlistener-polyfill-js)# Dev setup- `npm install` the dependencies.- `gulp watch` during development- `npm test` or `npm run test-watch` to run the unit tests"

with

"content"  : "Simple-Jekyll-Search====================[![Build Status](https://travis-ci.org/christian-fei/Simple-Jekyll-Search.svg?branch=master)](https://travis-ci.org/christian-fei/Simple-Jekyll-Search)A JavaScript library to add search functionality to any Jekyll blog.Find it on [npmjs.com](https://www.npmjs.com/package/simple-jekyll-search)---idea from this [blog post](https://alexpearce.me/2012/04/simple-jekyll-searching/#disqus_thread)---### Promotion: check out [Pomodoro.cc](https://pomodoro.cc/)# [Demo](http://christian-fei.github.io/Simple-Jekyll-Search/)# Install```bower install --save simple-jekyll-search# ornpm install --save simple-jekyll-search```# Getting startedPlace the following code in a file called `search.json` in the **root** of your Jekyll blog.This file will be used as a small data source to perform the searches on the client side:```------[  {% for post in site.posts %}    {      &quot;title&quot;    : &quot;{{ post.title | escape }}&quot;,      &quot;category&quot; : &quot;{{ post.category }}&quot;,      &quot;tags&quot;     : &quot;{{ post.tags | join: &#39;, &#39; }}&quot;,      &quot;url&quot;      : &quot;{{ site.baseurl }}{{ post.url }}&quot;,      &quot;date&quot;     : &quot;{{ post.date }}&quot;    } {% unless forloop.last %},{% endunless %}  {% endfor %}]```You need to place the following code within the layout where you want the search to appear. (See the configuration section below to customize it)For example in  **_layouts/default.html**:``````# ConfigurationCustomize SimpleJekyllSearch by passing in your configuration options:```SimpleJekyllSearch({  searchInput: document.getElementById(&#39;search-input&#39;),  resultsContainer: document.getElementById(&#39;results-container&#39;),  json: &#39;/search.json&#39;,})```#### searchInput (Element) [required]The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.#### resultsContainer (Element) [required]The container element in which the search results should be rendered in. Typically an ``.#### json (String|JSON) [required]You can either pass in an URL to the `search.json` file, or the results in form of JSON directly, to save one round trip to get the data.#### searchResultTemplate (String) [optional]The template of a single rendered search result.The templating syntax is very simple: You just enclose the properties you want to replace with curly braces.E.g.The template```{title}```will render to the following```Welcome to Jekyll!```If the `search.json` contains this data```[    {      &quot;title&quot;    : &quot;Welcome to Jekyll!&quot;,      &quot;category&quot; : &quot;&quot;,      &quot;tags&quot;     : &quot;&quot;,      &quot;url&quot;      : &quot;/jekyll/update/2014/11/01/welcome-to-jekyll.html&quot;,      &quot;date&quot;     : &quot;2014-11-01 21:07:22 +0100&quot;    }]```#### templateMiddleware (Function) [optional]A function that will be called whenever a match in the template is found.It gets passed the current property name, property value, and the template.If the function returns a non-undefined value, it gets replaced in the template.This can be potentially useful for manipulating URLs etc.Example:```SimpleJekyllSearch({  ...  middleware: function(prop, value, template){    if( prop === &#39;bar&#39; ){      return value.replace(/^\//, &#39;&#39;)    }  }  ...})```See the [tests](src/Templater.test.js) for an in-depth code example#### noResultsText (String) [optional]The HTML that will be shown if the query didn&#39;t match anything.#### limit (Number) [optional]You can limit the number of posts rendered on the page.#### fuzzy (Boolean) [optional]Enable fuzzy search to allow less restrictive matching.#### exclude (Array) [optional]Pass in a list of terms you want to exclude (terms will be matched against a regex, so urls, words are allowed).## Enabling full-text searchReplace &#39;search.json&#39; with the following code:```---layout: null---[  {% for post in site.posts %}    {      &quot;title&quot;    : &quot;{{ post.title | escape }}&quot;,      &quot;category&quot; : &quot;{{ post.category }}&quot;,      &quot;tags&quot;     : &quot;{{ post.tags | join: &#39;, &#39; }}&quot;,      &quot;url&quot;      : &quot;{{ site.baseurl }}{{ post.url }}&quot;,      &quot;date&quot;     : &quot;{{ post.date }}&quot;,      &quot;content&quot;  : &quot;{{ post.content | strip_html | strip_newlines }}&quot;    } {% unless forloop.last %},{% endunless %}  {% endfor %}  ,  {% for page in site.pages %}   {     {% if page.title != nil %}        &quot;title&quot;    : &quot;{{ page.title | escape }}&quot;,        &quot;category&quot; : &quot;{{ page.category }}&quot;,        &quot;tags&quot;     : &quot;{{ page.tags | join: &#39;, &#39; }}&quot;,        &quot;url&quot;      : &quot;{{ site.baseurl }}{{ page.url }}&quot;,        &quot;date&quot;     : &quot;{{ page.date }}&quot;,        &quot;content&quot;  : &quot;{{ page.content | strip_html | strip_newlines }}&quot;     {% endif %}   } {% unless forloop.last %},{% endunless %}  {% endfor %}]```## If search isn&#39;t working due to invalid JSON- There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use `remove_chars` as a filter.For example: in search.json, replace```&quot;content&quot;  : &quot;{{ page.content | strip_html | strip_newlines }}&quot;```with```&quot;content&quot;  : &quot;{{ page.content | strip_html | strip_newlines | remove_chars | escape }}&quot;```If this doesn&#39;t work when using Github pages you can try ```jsonify``` to make sure the content is json compatible:```&quot;content&quot;   : {{ page.content | jsonify }}```**Note: you don&#39;t need to use quotes &#39; &quot; &#39; in this since ```jsonify``` automatically inserts them.**##Browser supportBrowser support should be about IE6+ with this `addEventListener` [shim](https://gist.github.com/eirikbacker/2864711#file-addeventlistener-polyfill-js)# Dev setup- `npm install` the dependencies.- `gulp watch` during development- `npm test` or `npm run test-watch` to run the unit tests"

If this doesn’t work when using Github pages you can try jsonify to make sure the content is json compatible:

"content"   : "Simple-Jekyll-Search\n====================\n\n[![Build Status](https://travis-ci.org/christian-fei/Simple-Jekyll-Search.svg?branch=master)](https://travis-ci.org/christian-fei/Simple-Jekyll-Search)\n\nA JavaScript library to add search functionality to any Jekyll blog.\n\nFind it on [npmjs.com](https://www.npmjs.com/package/simple-jekyll-search)\n\n---\n\nidea from this [blog post](https://alexpearce.me/2012/04/simple-jekyll-searching/#disqus_thread)\n\n---\n\n\n\n### Promotion: check out [Pomodoro.cc](https://pomodoro.cc/)\n\n\n# [Demo](http://christian-fei.github.io/Simple-Jekyll-Search/)\n\n\n\n\n# Install\n\n```\nbower install --save simple-jekyll-search\n# or\nnpm install --save simple-jekyll-search\n```\n\n\n\n\n# Getting started\n\nPlace the following code in a file called `search.json` in the **root** of your Jekyll blog.\n\nThis file will be used as a small data source to perform the searches on the client side:\n\n```\n---\n---\n[\n  {% for post in site.posts %}\n    {\n      \"title\"    : \"{{ post.title | escape }}\",\n      \"category\" : \"{{ post.category }}\",\n      \"tags\"     : \"{{ post.tags | join: ', ' }}\",\n      \"url\"      : \"{{ site.baseurl }}{{ post.url }}\",\n      \"date\"     : \"{{ post.date }}\"\n    } {% unless forloop.last %},{% endunless %}\n  {% endfor %}\n]\n```\n\nYou need to place the following code within the layout where you want the search to appear. (See the configuration section below to customize it)\n\nFor example in  **_layouts/default.html**:\n\n```\n<!-- Html Elements for Search -->\n<div id=\"search-container\">\n<input type=\"text\" id=\"search-input\" placeholder=\"search...\">\n<ul id=\"results-container\"></ul>\n</div>\n\n<!-- Script pointing to jekyll-search.js -->\n<script src=\"{{ site.baseurl }}/bower_components/simple-jekyll-search/dest/jekyll-search.js\" type=\"text/javascript\"></script>\n```\n\n\n# Configuration\n\nCustomize SimpleJekyllSearch by passing in your configuration options:\n\n```\nSimpleJekyllSearch({\n  searchInput: document.getElementById('search-input'),\n  resultsContainer: document.getElementById('results-container'),\n  json: '/search.json',\n})\n```\n\n#### searchInput (Element) [required]\n\nThe input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.\n\n\n#### resultsContainer (Element) [required]\n\nThe container element in which the search results should be rendered in. Typically an `<ul>`.\n\n\n#### json (String|JSON) [required]\n\nYou can either pass in an URL to the `search.json` file, or the results in form of JSON directly, to save one round trip to get the data.\n\n\n#### searchResultTemplate (String) [optional]\n\nThe template of a single rendered search result.\n\nThe templating syntax is very simple: You just enclose the properties you want to replace with curly braces.\n\nE.g.\n\nThe template\n\n```\n<li><a href=\"{url}\">{title}</a></li>\n```\n\nwill render to the following\n\n```\n<li><a href=\"/jekyll/update/2014/11/01/welcome-to-jekyll.html\">Welcome to Jekyll!</a></li>\n```\n\nIf the `search.json` contains this data\n\n```\n[\n    {\n      \"title\"    : \"Welcome to Jekyll!\",\n      \"category\" : \"\",\n      \"tags\"     : \"\",\n      \"url\"      : \"/jekyll/update/2014/11/01/welcome-to-jekyll.html\",\n      \"date\"     : \"2014-11-01 21:07:22 +0100\"\n    }\n]\n```\n\n\n#### templateMiddleware (Function) [optional]\n\nA function that will be called whenever a match in the template is found.\n\nIt gets passed the current property name, property value, and the template.\n\nIf the function returns a non-undefined value, it gets replaced in the template.\n\nThis can be potentially useful for manipulating URLs etc.\n\nExample:\n\n```\nSimpleJekyllSearch({\n  ...\n  middleware: function(prop, value, template){\n    if( prop === 'bar' ){\n      return value.replace(/^\\//, '')\n    }\n  }\n  ...\n})\n```\n\nSee the [tests](src/Templater.test.js) for an in-depth code example\n\n\n\n#### noResultsText (String) [optional]\n\nThe HTML that will be shown if the query didn't match anything.\n\n\n#### limit (Number) [optional]\n\nYou can limit the number of posts rendered on the page.\n\n\n#### fuzzy (Boolean) [optional]\n\nEnable fuzzy search to allow less restrictive matching.\n\n#### exclude (Array) [optional]\n\nPass in a list of terms you want to exclude (terms will be matched against a regex, so urls, words are allowed).\n\n\n\n\n\n\n\n## Enabling full-text search\n\nReplace 'search.json' with the following code:\n\n```\n---\nlayout: null\n---\n[\n  {% for post in site.posts %}\n    {\n      \"title\"    : \"{{ post.title | escape }}\",\n      \"category\" : \"{{ post.category }}\",\n      \"tags\"     : \"{{ post.tags | join: ', ' }}\",\n      \"url\"      : \"{{ site.baseurl }}{{ post.url }}\",\n      \"date\"     : \"{{ post.date }}\",\n      \"content\"  : \"{{ post.content | strip_html | strip_newlines }}\"\n    } {% unless forloop.last %},{% endunless %}\n  {% endfor %}\n  ,\n  {% for page in site.pages %}\n   {\n     {% if page.title != nil %}\n        \"title\"    : \"{{ page.title | escape }}\",\n        \"category\" : \"{{ page.category }}\",\n        \"tags\"     : \"{{ page.tags | join: ', ' }}\",\n        \"url\"      : \"{{ site.baseurl }}{{ page.url }}\",\n        \"date\"     : \"{{ page.date }}\",\n        \"content\"  : \"{{ page.content | strip_html | strip_newlines }}\"\n     {% endif %}\n   } {% unless forloop.last %},{% endunless %}\n  {% endfor %}\n]\n```\n\n\n\n## If search isn't working due to invalid JSON\n\n- There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use `remove_chars` as a filter.\n\nFor example: in search.json, replace\n```\n\"content\"  : \"{{ page.content | strip_html | strip_newlines }}\"\n```\nwith\n```\n\"content\"  : \"{{ page.content | strip_html | strip_newlines | remove_chars | escape }}\"\n```\n\nIf this doesn't work when using Github pages you can try ```jsonify``` to make sure the content is json compatible:\n```\n\"content\"   : {{ page.content | jsonify }}\n```\n**Note: you don't need to use quotes ' \" ' in this since ```jsonify``` automatically inserts them.**\n\n\n\n\n\n##Browser support\n\nBrowser support should be about IE6+ with this `addEventListener` [shim](https://gist.github.com/eirikbacker/2864711#file-addeventlistener-polyfill-js)\n\n\n\n\n\n\n\n# Dev setup\n\n- `npm install` the dependencies.\n\n- `gulp watch` during development\n\n- `npm test` or `npm run test-watch` to run the unit tests\n"

Note: you don’t need to use quotes ‘ “ ‘ in this since jsonify automatically inserts them.

##Browser support

Browser support should be about IE6+ with this addEventListener shim

Dev setup

  • npm install the dependencies.

  • gulp watch during development

  • npm test or npm run test-watch to run the unit tests