Midwire

Ruby, Elixir, Macintosh and Other Technical Maunder.

Update ActiveRecord Instance With Validation Context

Validation contexts are really useful, however only the methods valid? and save allow you to pass a custom validation context. What about update?

If you want to pass a validation context when calling update on an Active Record model instance, add this to your base class, which is ApplicationRecord by default in Rails 4.x and 5.x.

1
2
3
4
5
6
7
8
9
10
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  def update_with_context(new_attributes, context)
    with_transaction_returning_status do
      assign_attributes(new_attributes)
      save(context: context)
    end
  end
end

Now you can call mymodel.update_with_context(model_params, :my_special_context, and pass your custom validation context along.

Cheers!

Prevent MacOS Applications From Adding Launch Agents

Many OSX users don’t realize that applications can install their own launch agents1 without you ever knowing it. I found this out because I use some software called Drive Genius to monitor my hard drives and their health, which watches the launch agent folders for new files or changes to existing files. When it detects any changes it pops up a notification like this:

You can find a similar, free, offering here called CIRCL automatic launch object detection: http://www.circl.lu/pub/tr-08/

When I catch an application doing that I use AppleScript to write a launcher which will launch it and then delete any launch agent that it drops.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Launch Amazon Music and remove it's attempt to force itself into your login items

tell application "Amazon Music" to activate

tell application "System Events"
  set startupItems to (name of every login item)
  repeat with i from 1 to count of startupItems
    if startupItems's item i is equal to "Amazon Music" then
      delete login item "Amazon Music"
    end if
  end repeat
end tell

delay 3

tell application "Finder"
  delete (every item of folder "LaunchAgents" of folder "Library" of folder "cblackburn" of folder "Users" of startup disk whose name begins with "com.amazon.music")
end tell

do shell script "/bin/launchctl remove -w com.amazon.com"

Just modify it to your needs and it should help keep unwanted launch agents at bay.


  1. A launch agent is similar to a cron job, but OSX specific.

HOWTO: Use a Personal AWS EC2 Instance as an SSH Tunnel

I recently ditched my T1 line because I found a cellular ISP with no data cap. This new provider gives me about 12 times the downstream bandwidth at 30% of the cost of the T1.

The only problem is that it changes my public IP address everytime I restart the router. This would not normally be a problem but I’m a software engineer and frequently need to access remote resources through SSH or otherwise. We use AWS resources at my company and the security groups require a static IP address to allow access.

I could pay for a static IP address at the ISP, but instead I opted to configure a personal SSH tunnel with a static IP address. This gives me greater flexibility because I can use it for other things and it costs less (about $7-10/month, depending on if you leave it running when you’re not using it)

This is my HOWTO guide for getting things setup and minimizing costs.

Overview

  1. Create a personal AWS account
  2. Create a low-cost EC2 instance
  3. Configure AWS CLI for command line start, stop, status automation
  4. Tunnel all the things for fun and profit

Create a personal AWS Account

I won’t go into a lot of detail for this step because Amazon has really good documentation here. Make sure to create the EC2 key pair for your account as well.

Create a low-cost EC2 instance

Again, AWS has great documentation. Follow the docs and configure your instance to your personal taste. If, like me, you will only use it for an SSH tunnel, you won’t need a lot of resources.

There are several types of AMIs to choose from. I chose a basic Ubuntu t2.micro instance with 1GB of RAM. Follow the documentation and be sure to:

  • Create an IAM user account (i.e., ubuntu)
  • Download your keypair file and store it in ~/.ssh/,
  • chmod 400 ~/.ssh/your-keypair-name.pem - make the file readonly
  • copy/store the access key, and secret keys (strings) somewhere for later use.
  • take note of the region-name, you’ll need it later.

Configure AWS CLI

You’ll want to install AWS CLI (Command Line Interface) in order to be able to start and stop your tunnel from the command line, without logging into the AWS console in your web browser.

For MacOS

1
brew install awscli

For Debian-Based Linux (i.e. Ubuntu)

1
sudo apt-get install awscli

If you only use one account from AWS CLI, you can run aws configure with no arguments to setup the defaults. However, if you use multiple accounts add the --profile account_name switch:

1
aws configure --profile personal

Here is a good post on Stack Overflow about multiple AWS CLI accounts.

Note: Pay attention to the region name. It must match the region name of your EC2 instance.

Configure SSH:

Edit/create ~/.ssh/config as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Host my-aws-tunnel
  User ubuntu
  # replace the hostname below with your EC2 instance hostname
  HostName ec2-35-161-7-236.us-west-2.compute.amazonaws.com
  # replace the keyfile path below with your EC2 instance keypair file
  IdentityFile ~/.ssh/my-ec2-key-pair.pem

# Follow the other confluence docs for host access to different boxes, or ask a Nutrio admin (Ted)
Host stagnat
  HostName ec2-52-21-83-13.compute-1.amazonaws.com
  User ec2-user
  IdentityFile ~/.ssh/staging-vpc-keypair.pem
  ForwardAgent yes
  ProxyCommand ssh my-aws-tunnel -W %h:%p

Elixir - Time Ago in Words

After reading the excellent book “Programming Elixir”, by Dave Thomas, and “Programming Phoenix”, by Chris McCord, Bruce Tate and José Valim, I decided to dive in.

As of this post, I am currently writing an Elixir app using the Phoenix framework. It is called Tunedrop and I am working on it for two reasons:

  1. To learn Elixir and Phoenix
  2. To share some of the music that I grew up on with my kids

You can see the code here.

It is definitely a work in progress and may look pretty raw at times. However, I wanted to share how easy it is to port code from Ruby to Elixir for your benefit, happiness and profit.

As I play music in iTunes, Tunedrop dynamically posts the song’s artist, name and year released, along with the time it was played. Originally, the time played was absolute and looked like this: 4/12 15:32. I wanted to look something like the Rails ActionView::Helpers.distance_of_time_in_words:

listings

Here’s how I did it:

Preparation

I’m using the timex Elixir library for DateTime manipulations. I followed the directions there to install it into my Phoenix project.

TimeHelpers

The Tests

In tunedrop/test/views/time_helpers_test.exs <- click the link to view the entire test module.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
defmodule Tunedrop.TimeHelpersTest do
  use Tunedrop.ViewHelperCase
  use Timex

  test "returns time in words for now" do
    time = DateTime.now
    words = Tunedrop.TimeHelpers.distance_of_time_in_words(time)
    assert words =~ ~r/Less than 1 minute/
  end

  test "returns time in words for 30 minutes" do
    time = DateTime.shift(DateTime.now, minutes: 30)
    words = Tunedrop.TimeHelpers.distance_of_time_in_words(time)
    assert words =~ ~r/30 minutes/
  end

  ...
end

The Module

In tunedrop/web/views/time_helpers.ex <- click the link to view the entire module.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
defmodule Tunedrop.TimeHelpers do
  use Timex
  alias Timex.DateTime

  @moduledoc """
  Helpers for DateTime display
  """

  @doc """
  Generates approximate distance of time between two times in words.
  """
  def distance_of_time_in_words(from_time, to_time \\ DateTime.now) do
    case from_time > to_time do
      true ->
        from = to_time
        to = from_time
      false ->
        from = from_time
        to = to_time
    end
    distance_in_seconds = abs(DateTime.to_seconds(to_time) - DateTime.to_seconds(from_time))
    distance_in_minutes = abs(round(distance_in_seconds / 60.0))

    words = case distance_in_minutes do
      n when n in 0..1 ->
        "Less than 1 minute"
      n when n in 2..45 ->
        "#{n} minutes"
      n when n in 45..90 ->
        "about 1 hour"
      n when n in 90..1440 ->
        "about #{round(n / 60.0)} hours"
      n when n in 1440..2520 ->
        "about 1 day"
      n when n in 2520..43200 ->
        "about #{round(n / 1440.0)} days"
      n when n in 43200..86400 ->
        "about #{round(n / 43200.0)} months"
      n when n in 86400..525600 ->
        "#{round(n / 43200.0)} months"
      _ -> "a long time"
    end
    words
  end
end

I’m sure this code could be better, but what I’m impressed with is how easy it is to port code from Ruby into the pattern-matching paradigm of Elixir, and how similar it looks to the original Ruby code.

Why Not Google Chrome?

Why you should not use the Google Chrome browser

As an internet software engineer, I often get asked why I don’t use Google’s ever popular Chrome browser. My answer is often met with disbelief. So I decided to answer the question once and for all with proof behind my reasoning in this six and a half minute video.

I posted the video on youtube back in August of 2015. An interesting fact is that it is virtually impossible to find the video using a Google search or a Youtube specific search. That’s right; Google refuses to index the video. If this doesn’t confirm the nefariousness behind the Chrome browser what will? Will Google simply remove the video? Probably. I propose they will remove it if it begins to gain any traction.

Try this: Do a search for “why not google chrome” or “why you shouldn’t use the chrome browser”. I’m betting that you will not find a single article or video that exposes their tracking as I do in the linked video. You will most certainly not find my video.

The clear fact is that Google tracks your every move when you use their browser. They don’t want you to know that.

If you want a browser experience without sharing every site you visit and single click you make with Google, use Firefox.

In addition, I use startpage.com instead of google.com for all of my searching. Startpage gets their results from Google but they don’t record your searches and correlate your IP address, etc.

Good luck

A Useful ~/.irbrc File

Here is my ~/.irbrc file.

~/.irbrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
require 'irb/completion'

def what_methods(obj)
  (obj.public_methods - Object.public_methods - Object.instance_methods).sort
end

def wm(obj)
  what_methods(obj)
end

def predicates(obj)
  what_methods(obj).grep(/\?$/)
end

def locate(obj, method)
  obj.method(method.to_sym).source_location
end

It contains 4 useful methods as follows:

what_methods

Allows you to determine what methods are available on an object without displaying all of Object instance methods. The following irb session calls what_methods on an Array instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ary = [1,2,3]
what_methods ary
=> [:&,
 :*,
 :+,
 :-,
 :<<,
 :[],
 :[]=,
 :all?,
   # ...
 :uniq,
 :uniq!,
 :unshift,
 :values_at,
 :zip,
 :|]

Note: wm is just a shortcut for what_methods, cuz I’m lazy.

As you can see, it lists out all public instance methods for the Array instance, ary.

predicates

Predicates is similar to what_methods. It actually calls what_methods and filters out all but methods that end with a question mark (predicates).

1
2
3
ary = [1,2,3]
predicates ary
=> [:all?, :any?, :empty?, :member?, :none?, :one?]

Pretty cool, huh?

locate(obj, method)

Have you ever been at some breakpoint and wanted to look at the code for a specific method? This tiny method lets you do just that.

1
2
3
get :index
locate response, :ok?
["/Users/midwire/Code/ruby/Rallyhood/rh_svc_analytics/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/response.rb", 126]

How about that? It even gives you the line number along with the file where the method is defined.

To use these in an irb session, just copy them into your ~/.irbrc file. However, that won’t help if you plan to use them during a pry session. For that just copy them into your ~/.pryrc file.

Enjoy!

Securing Your Workstation

With all of the revelations from Edward Snowden about the unconscionable and patently unlawful (unconstitutional) NSA spying on Americans and the world, here are some tips on how to secure your computer to make it more difficult for this traitorous organization to spy on you.

1. Use an anonymizing VPN service

You’ll want a service that provides a VPN (Virtual Private Network). Many services, like BTGuard, do not provide a VPN. It only masks your torrent traffic. Whereas a VPN sends all of your network traffic through the anonymized connection.

TOR (The Onion Router) by itself is not good enough either. TOR is only for browsing the web anonymously. It does help but is not foolproof. It doesn’t take much for the venal NSA, CIA, FBI, et al. (a.k.a. Axis of Evil) to trace back to you, even through TOR. In addition TOR is not a VPN. It only masks your web browsing traffic.

There are many to choose from. I have my favorite (which I will not divulge) but here is a list of a few anonymizing VPN based proxy services that I know of. I would stay away from free services, which could easily be a front for the previously mentioned Axis of Evil. In reality any of these services could be funnelling data to said Axis of Evil. Trust is all but gone and the ‘law’ will not help you.

We must ask ourselves the important question, do any of these proxy services have backdoors for the Axis of Evil? The answer is, there is no way to know for sure. Life Hacker has an article about the trust issue.

Even though you are connected to your anonymizing VPN service be careful of logging into any personal accounts. Doing so can provide a means of tracing traffic back to you. It is not possible to forever avoid logging into your accounts (email, et al.). Just be aware that doing so can help reveal you to the Axis of Evil. Think of it this way, if you want to surf the web anonymously then surf the web, but don’t login to your email account using the same session. If you want to check email, then login and check email, then disconnect then reconnect to your VPN using a different server and session to browse the web again.

Note: If you decide to use a VPN service, don’t just choose a server in single country and always use it. Switch things up, daily. For example, use Sweden for a day, then switch to Canada the next day. Of course this is assuming the VPN provider you choose has servers in multiple countries. Hint: Choose a provider with servers in multiple different countries. Do your own research!

2. Frequently modify your MAC address

A MAC address (or Media Access Control address) is the unique ID for your network interface controller (NIC). It is a hardware serial number but it can be changed using software.

Here is a script that I use for changing a MAC address. I use it on OSX but it may work on Linux as well.

It is prudent to change your MAC address at least every bootup. It may be better to change it on a regular schedule as well (i.e., every 24 hours).

Be aware that this can have the side effect of changing your IP address or confusing certain software or hardware peripherials (i.e., DHCP reservations).

3. NEVER use Microsoft Windows!

Microsoft has been revealed to be working with the Axis of Evil. However, it would be naive to think that Apple or other hardware and software manufacturers are not doing the same thing.

The main problem with Windows is that it is very unstable, insecure, buggy and often full of viruses and trojans. I’ve been a professional in the computer industry since 1989, and I can tell you (to the dismay of Windows fanboys) that Windows is the abolute worst, most insecure and unstable operating system under widespread use today.

The most secure and trustworthy OS is Linux/GNU. Why? Because it is open source and you and I, and other smarter people, can go read the source code and see what kind of shenanigans may be going on. Does that provide any guarantees? Absolutely not. Case in point, the Heartbleed bug in SSH.

Personally, I use OSX and have found Apple hardware to be far better than any other. In the past I’ve built my own high-end machines and owned Dells, Gateways, etc. It took a long time for me to jump in and purchase a more expensive Apple computer. Once I did the fog was lifted from my eyes. I’ve still got the first MacBook I purchased after the turn of the century. It still works wonderfully, albeit slowly. Macs just work, and when you drop one on the sidewalk Apple customer service has proven to be the best in the world.

4. Use Firefox

As a software engineer, most of my colleagues choose to use Google Chrome as their browser of choice. My own personal view is that since Google itself frequently hands over data to the Axis of Evil, why on God’s green earth would I use a browser that was developed at the same company?

In my opinion, Firefox can be secured better than Chrome and Mozilla (the company behind Firefox) is not beholden to Google.

5. Don’t Use Google

As stated in a previous article, Google is evil, period. Don’t use it for your search engine, email, their DNS servers (8.8.8.8 and 8.8.4.4). Avoid Google like the plague. See the linked article for alternatives.

There are also alternative DNS providers.

You can tell I hate Google. And, as is with most websites that are critical of them, you will never find high-ranking links back to this site in their index.

6. Watch Your Traffic

As with anything important, pay attention! Watch your IP traffic over the network. On Linux or OSX you can use iptraf or iftop to watch where your traffic is coming and going. You may spot some interesting hostnames like ‘gv-in-f103.1e100.net’, which is Google. Using ‘iftop’ I found an app that was connecting to Google from my machine. Those insidious bastards!

Note: Little Snitch also provides a traffic monitor.

7. Use a Firewall

Whether you use the built-in firewall and tools that come with your operating system or purchase a full-blown professional firewall appliance, don’t neglect the firewall.

Personally, I use the built-in OSX firewall and Little Snitch on my own machines. In addition my LAN is sealed off by a ZyXEL, ZyWALL USG 50.

I highly recommend Little Snitch for OSX users. Iptables works wonderfully for Linux/GNU users.

8. Use Encryption

Just like a padlock on a locker, if someone wants to break-in they will cut the lock. We just want to add as many locks to our data as possible. Our locks are encryption.

  • Encrypt your email using GPG. Encourage your friends and family to do the same.
  • Use HTTPS (SSL) instead of HTTP wherever possible. Even though SSL is clearly hackable or circumventable, it is another ‘lock’ that takes time to successfully break.
  • Use SSH for point-to-point remote connections and tunnelling.

Summary

Understand that the corporate government of America owns, or sits on, all the major switches on the Internet. They have access to all traffic and funnel it into their Utah Data Center. If they want to track you, it cannot be stopped. All you can do is make it more difficult for them. But if you are on one of their many lists, the only way to have computer privacy is to detach it from the internet, and even that guarantees nothing.

Welcome to the world we live in.

– Midwire

RSpec Shared Contexts

I love RSpec! Though I know Cucumber fairly well too, as a backend developer I use RSpec almost exclusively. Cucumber is better for having tests that muggles (non-programmers, executives, suits, etc.) like to execute and look at, IMHO.

I really appreciate Philippe Creux’s post on the way he uses RSpec. I do all of those things as well but I have also found shared contexts to be extremely useful in helping to keep my specs DRY.

They are really easy to use. We typically have a spec/support directory in which we put shared stuff, used across more than one set of specs. I like to create a file called shared_contexts.rb and inside we put code like this:

./spec/support/shared_contexts.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
shared_context 'authentication' do
  let(:user) { login_user(FactoryGirl.create(:user)) }
  let(:auth_params) do
    {
      public_key: Settings["api_keys"]["public"],
      app_token:  ControllerMacros.generate_app_token,
      user:       {remember_token: user.authentication_token},
      format:     :json
    }
  end

  def login_different_user(user)
    login_user(user)
    auth_params[:user] = {remember_token: user.authentication_token}
  end
end

Then, in your actual specs, you can do things like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
require 'spec_helper'

describe Api::V3::PhotoCommentsController, 'Actions' do
  include_context 'authentication'
  ...
  context 'on POST to #create' do
    let(:new_comment) do
      {comment: 'created from rspec'}
    end

    it "does not allow non-related user to post a comment" do
      login_different_user(FactoryGirl.create(:user))
      expect {
        post :create, auth_params.merge(new_comment)
      }.to change(GalleryComment, :count).by(0)
      response.response_code.should == 401 # not authorized
    end
  end
end

If we didn’t use shared contexts, we would have to repeat the login_different_user method declaration and the necessary let variables in every spec that uses them.

DRY is a fundamental principle that keeps code maintainable and with fewer bugs. Just do it!

– Midwire

Rack, Paperclip, File Uploads & RSpec

So I’ve been writing a couple Ruby services, for Rallyhood, using Padrino. We’ve got Rallyhood Authentication Service (RAS) and I’m currently working on Rallyhood File Service (RFS).

Writing my specs for the assets controller, I ran into:

1
2
3
4
5
6
7
8
9
  1) AssetsController POST on /assets uploads the file
     Failure/Error: post '/assets', params
     Paperclip::AdapterRegistry::NoHandlerError:
       No handler found for {:filename=>"rails.png", :type=>"image/png", :name=>"asset[attachment]", :tempfile=>#<Tempfile:/var/folders/34/4z_fjgbs7ys9c3rzj1cgdn6r0000gn/T/RackMultipart20140131-97373-1iy6kt6>, :head=>"Content-Disposition: form-data; name=\"asset[attachment]\"; filename=\"rails.png\"\r\nContent-Type: image/png\r\nContent-Length: 6646\r\n"}
     # ./app/controllers/assets.rb:19:in `block (2 levels) in <top (required)>'
     # (eval):108:in `block in call'
     # (eval):98:in `catch'
     # (eval):98:in `call'
     # ./spec/app/controllers/assets_controller_spec.rb:30:in `block (3 levels) in <top (required)>'

Subsequent web searches revealed various unrelated issues. So after spelunking in the Paperclipe code I found the exception being thrown was due to the uploaded file being represented by a Hash (Rack converts it into a Hash), and that Paperclip does not provide an adapter for this Rack specific Hash out of the box.

The Hash looked like this
1
2
3
4
5
6
7
8
9
10
11
12
13
{"remember_token"=>"75806eba-a178-43ad-a49b-6632c49e8970",
 "oauth_token"=>"nmou6vz3kk6gx1yq8hqw3pygq97srrq",
 "asset"=>
  {"user_id"=>"730",
   "folder_id"=>"1",
   "attachment"=>
    {:filename=>"rails.png",
     :type=>"image/png",
     :name=>"asset[attachment]",
     :tempfile=>
      #<File:/var/folders/34/4z_fjgbs7ys9c3rzj1cgdn6r0000gn/T/RackMultipart20140131-97556-i2p4b>,
     :head=>
      "Content-Disposition: form-data; name=\"asset[attachment]\"; filename=\"rails.png\"\r\nContent-Type: image/png\r\nContent-Length: 6646\r\n"}}}

I figured someone had to have run into this issue before. I then looked for a gem and found paperclip-rack.

Added this to my Gemfile

gem 'paperclip-rack', require: 'paperclip/rack'

… which fixed the issue.

Software Development - Onsite or Remote?

I’ve been in the Software Development business since 1990 and seen a lot of changes in the industry. From GUI-less operating systems and using the “C” language to the world-wide-web and high-level expressive languages like Ruby, things have changed. Some things have come full circle like client-server architectures to ‘the cloud’. One thing that has changed for the better and to its logical conclusion is the ability to telecommute.

Back in the day there was no choice. The internet did not exist and in order to make a living you had to take the time to travel to work everyday, spending your own money for gasoline, wear and tear on your car and sit in a tiny cubicle with no window to write code on a monochrome text-only green or amber colored CRT (Cathode Ray Tube). They weren’t called monitors back then.

Now we live in the age of the “Internet Superhighway” (another throwback term), and we have the option to work remotely from a home office. Taking advantage of this option provides many benefits:

  • Environmental: Far fewer people are required to travel for work, using combustion powered vehicles which are bad for the environment.
  • Financial: This benefit is two-fold in that telecommuting saves money not only for the employer who doesn’t need to provide office space, computers, electricity, water, restrooms, etc., but it also saves money for the employee who no longer has to spend money on gasoline and car maintenance. Employers typically save between 30 to 70 percent on employees who telecommute even part time.
  • Time: The employee can now often save hours each day on commuting and spend that time working or with family.
  • Productivity: Workers that work from home tend to be happier and more productive. Telecommuters are less likely to be absent from work and can more easily manage their time. It is also proven that telecommuters produce higher quality work. In addition employers who are willing to hire remote workers have a much larger pool of high quality talent from which to choose.

Some employers like to throw up the “what about security” issue. With modern day VPNs security is not a concern unless you don’t trust your employee to begin with. Who wants to work for an employer that doesn’t trust you?

All of these jobs nowadays that require software developers to work “onsite” astound me. In this day and age to require software developers to drive to a brick-and-mortar building everyday is simply ridiculous. That kind of policy is a sign of one of two things:

  1. The employer is ignorant of the benefits of telecommuting.
  2. The employer has management issues. Management doesn’t trust their employees to work independently and report their time honestly.

So, to all of the recruiters/head-hunters that keep trying to ‘relocate’ me in order to make a few bucks… give it up! I don’t work onsite!