Implementing social media "like" buttons: Everything you never wanted to know

So you client has asked you to implement a row of buttons to like the URL on Facebook, Twitter and Google+. Here are some things you should know about this.

0. Security considerations

Each "like" button is implemented by including a Javascript on your site. This means you are running fucking remote code on your page. You are giving Facebook, Twitter and Google+ full permission to e. g. copy user cookies. Check with your client if she is cool with that. Also note that if you're site is suggesting security by operating under HTTPS ...

Enable CSRF protection in Javascript tests

You might not know that Rails disables CSRF protection in tests. This means that if you accidentally forget to send the CSRF token for non-GET requests, your tests will be green even though your application is completely broken (a failed CSRF check usually logs out the user). Rails probably does this because CSRF protection sort of requires Javascript.

You want to enable CSRF protection in Cucumber scenarios that can speak Javascript. To do so, copy the a...

Cucumber: Detect if the current Capybara driver supports Javascript

Copy the attached file to features/support. This gets you a convenience method:

Capybara.javascript_test?

Is true for Selenium, capybara-webkit, Poltergeist and a custom driver called :chrome (which we sometimes like to use for Selenium+Chrome).

Similar sounding but completely different card: Detect if a Javascript is running under Selenium WebDriver (with Rails)

You don't need each, collect or select in Coffeescript

Working with lists in Javascript is painful because the native Array class is so poorly designed.

One way to reduce the pain is to to use Underscore.js's functions like _.each, _.map or _.select, which unfortunately clutters your code with awkward calls to the _ helper.

Fortunately when you use CoffeeScript you don't need any of that. CoffeeScript has a very versatile for keyword that can do anything that each, collect or select can do. Enjoy!

each

f...

Understanding AngularJS service types

Angular comes with different types of services. Each one with its own use cases.

All of these services are singletons. You probably want to use Factory all the time.

Provider

  • is the parent of all other services (except constant)
  • can be configured using `app.config(function(Provider) { ...})
  • a little complex

Factory

  • simpler than Provider, but without configuration
  • definition: `app.factory('name', someFunction)
  • someFunction is called when the name service is instantiated and should return an object

Se...

Compiling Javascript template functions with the asset pipeline

The asset pipeline (which is actually backed by sprockets) has a nice feature where templates ending in .jst are compiled into Javascript template functions. These templates can be rendered by calling JST['path/to/template'](template: 'variables'):

<!-- templates/hello.jst.ejs -->
<div>Hello, <span><%= name %></span>!</div>

// application.js
//= require templates/hello
$("#hello").html(JST["templates/hello"]({ name: "Sam" }));

Whatever is in the <% ... %> is evaluated in Javascript...

Speed up your websites: Put JavaScripts at bottom

For websites that don't do JavaScript rendering on the client, it's best practice to put script tags at the bottom of the HTML. This way, the page can start to render before scripts have been loaded and run.

The caveat is that you also have to move all other script tags from your views to the bottom of the page. This can be done with helpers.

How to implement

  1. Add the attached javascript_helper to your app.
  2. Move your `javascript_i...

Trigger a link's click action with Javascript

Use the click method on the DOM element:

let link = document.querySelector('a')
link.click()

Howto remove the location hash without causing the page to scroll

Set the hash to a dummy hash which doesn't hit any id at your page, for example:

window.location.hash = "_";

Note

  • If you'd set the hash to "" it causes the page to scroll to the top because the hash "#" by itself is equivalent to "_top".
  • If you'd set window.location.href = "..." to get rid of the "#", you cause the browser to reload the page what is most likely not intended.

Upgrading Rails 2 from 2.3.8 through 2.3.18 to Rails LTS

This card shows how to upgrade a Rails 2 application from Rails 2.3.8 through every single patch level up to 2.3.18, and then, hopefully, Rails LTS.

2.3.8 to 2.3.9

This release has many minor changes and fixes to prepare your application for Rails 3.

Step-by-step upgrade instructions:

  1. Upgrade rails gem
  2. Change your environment.rb so it says RAILS_GEM_VERSION = '2.3.9'
  3. Change your ...

Coffeescript: Caveat when cloning objects with fat-arrow methods

Coffeescript allows you to create classes whose methods are automatically bound to the correct this. You can do this by using a fat arrow:

class Person

  constructor: (name) ->
    @name = name

  sayHello: =>
    alert("Hello, I am #{@name}")

An important caveat is that when you clone such an object, all of its methods are still bound to the original instance:

eve = new Person("Eve")
eve.sayHello() # => "Hello, I am Eve"
bob = _.clone(eve)
bob.name = "Bob"
bob.sayHello() # => "Hello, I am Eve"

I don't thin...

Clean up application servers when deploying

Our development process makes us deploy very often. As the number of releases grows, junk clogs up the hard drive of our application servers:

  • Old release code
  • Old tmp folders with compiled view templates etc.
  • Precompiled assets (Javascripts, images...) that no longer exist. When using the asset pipeline, Capistrano will symlink the public/assets directory to shared/assets. This is cool since we can still serve previous assets after a new release, in the window where browser caches might still have references to old assets. But i...

JavaScript: How to generate a regular expression from a string

Getting a regular expression from a string in JavaScript is quite simple:

new RegExp('Hello Universe');
# => /Hello Universe/

You can also use special characters:

new RegExp('^(\\d+) users')
# => /^(\d+) users/

Our expression above now works only at the beginning of the matched string, looks for a number (\d+ [1]) and also captures that. Sweet.

However, mind that your input will not be magically escaped because of that:

new RegExp('makandra.com')
# => /makandra.com/

The above expression would match "`...

AngularJS: Access the scope for a rendered DOM element

This trick might be useful to implement more complicated directives in AngularJS. I needed it to do drag'n'drop in a hierarchical tree.

Let's say you have this $scope in your Angular controller:

$scope.tasks = [
  { 'text': 'Task 1' },
  { 'text': 'Task 2' }
]

And you have this template:

<ul ng-repeat="task in tasks">
  <li>
    {{task.text}}
  </li>
</ul>

Which renders this HTML:

<ul>
  <li>Task 1</li>
  <li>Task 2</li>
</ul>

If you'd like to access the scope bound to the second <li> you can say this in jQ...

How to not die with ActionView::MissingTemplate when clients request weird formats

When HTTP clients make an request they can define which response formats they can process. They do it by adding a header to the HTTP request like this:

Accept: application/json

This means the client will only understand JSON responses.

When a Rails action is done, it will try to render a template for a format that the client understand. This means when all you are HTML templates, a request that only accepts application/json will raise an error:

An ActionView::MissingTemplate occurred in pages#foo:
  Missing templa...

Fixing authentication in legacy applications

Authentication is hard: there are many edge cases, and most users (including yourself) usually only go the "happy path" once and never see the edge cases. If you have rolled your own authentication, or been using older authentication solutions, or resorted to HTTP Basic Authentication, this card will tell you what to do to make your application safe.

Any application that stores sensitive data in the browser

That is: cookies, e.g. by offering a login.

  • Ask the admins to [turn on SSL](https://makandracards.com/makandra/1416-integrate-s...

kamens/jQuery-menu-aim

jQuery plugin to fire events when user's cursor aims at particular dropdown menu items. For making responsive mega dropdowns like Amazon's.

parallel_tests: Disable parallel run for tagged scenarios

Note: This technique is confusing and slows down your test suite.


Copy the attached code to features/support. This gets you a new Cucumber tag @no_parallel which ensures that the tagged scenario does not run in parallel with other scenarios that are tagged with @no_parallel. Other scenarios not tagged will @no_parallel can still run in parallel with the tagged test. Please read the previous sentence again.

This can help when multiple test processes that access a single resource that is hard to shar...

What `var` actually does in Javascript

TL;DR: Variables not declared using var are stored outside the current scope, most likely in the global scope (which is window in web-browsers).


Declaring a variable in Javascript is done like var x = 5. This creates a new variable in the current scope (e.g. the function you're in). What happens when don't use var?

Javascript needs to be clever when you do an assignment without declaring a variable, e.g. x = 7. To find that variable,

  • it first looks up x in the current scope
  • next, it goes up the scope chain, lookin...

Test redirects to an external URL with Cucumber/Capybara

When a controller action redirects to an external URL (like http://somehost.com/some/path) you will find that this is hard to test with Cucumber and Capybara:

  • A non-Javascript Rack::Test scenario will just ignore the host and try to open /some/path in your local application
  • A Selenium test will actually follow the redirect, which you probably don't want either

There are two workarounds for this. You can use either, or a combination of both.

  1. Write a controller spec

Controller specs can test if a resp...

The Plight of Pinocchio: JavaScript's quest to become a real language - opensoul.org

Great presentation about writing Javascript like you write everything else: Well-structured and tested.

JavaScript is no longer a toy language. Many of our applications can’t function without it. If we are going to use JavaScript to do real things, we need to treat it like a real language, adopting the same practices we use with real languages.

This framework agnostic talk takes a serious look at how we develop JavaScript applications. Despite its prototypical nature, good object-oriented programming principles are still relevant. The...

What's in a View? A look at the alternatives

Great look at the tradeoffs between progressive enhancement with jQuery or similiar, vs. client-side views.

Chart.js - a promising JavaScript charting library with MIT-license

Chart.js seems to be a good alternative to Google's Chart API and other commercial chart drawing libraries.

  • good looking charts
  • canvas based (means less memory consumptive, but no interactivity out of the box)
  • highly configurable
  • good API and documentation
  • just 4.5 kilobytes
  • MIT license
  • Browser support: all browsers supporting the canvas element (for IE8 and below, use the polyfill as describes in the [chart.js documentation...

JavaScript: Comparing objects or arrays for equality (not reference)

JavaScript has no built-in functions to compare two objects or arrays for equality of their contained values.

If your project uses Lodash or Underscore.js, you can use _.isEqual():

_.isEqual([1, 2], [2, 3]) // => false
_.isEqual([1, 2], [1, 2]) // => true

If your project already uses Unpoly you may also use up.util.isEqual() in the same way:

up.util.isEqual([1, 2], [2, 3]) // => false
up.util.isEqual([1, 2], [1, 2]) // => true

If you are wri...