Tuesday, April 05, 2016

Re-enable disabled disable_with fields

I have some forms that do JavaScript based validation before submitting to the server.  The submit button is using the disable_with construct, so when the submit button is pressed, it is correctly disabled, but when the client-side validation fails, it's stuck disabled.

To remedy this situation, I added these lines to the JavaScript code that hides the error messages after they've been displayed for 5 seconds.

// re-enable 'disable_with' fields after validation errors
jQuery.rails.enableElement(jQuery('[data-disable-with]'));
jQuery('[data-disable-with]').val(function(){ return jQuery(this).text()}).prop('disabled', false);

The first line is the commonly proposed solution that I found elsewhere online, but when I tried it (in Chrome), I found that it didn't work, leaving the button disabled with the disabled text displayed. However, one important thing it did was to insert the original button text as HTML content of the input element.  I added the second line to use that text as the button value and then actually enable the button.


Saturday, January 16, 2016

Setup of Ruby Development Environment VM

I recently needed to provide some development environment setup instructions to a friend, so I figured it would be a good idea to document them here in case I need them again or if it helps anyone else.

Let me start off with a few premises:

  • I like doing Ruby on Rails development.
  • Ruby development on Windows is not pretty.
  • The computer I'm using most often is Windows-based (provided for my "real" job which is not Ruby development).
  • My personal computers are Macs.
  • I want to be able to work from any computer but don't want to hassle with keeping the environments in sync.
  • I've used multiple flavors of Linux over the years back to the SLS days (Linux version 0.9x), and am very comfortable with it.
With those premises in mind, I've adopted the use of a virtual machine (VM) to be my development environment.  It allows me to separate my personal development environment from other clutter (or even probing by workplace compliance scans), and allows me to readily move it from machine to machine as necessary.  I also usually host my applications on Linux-based servers, so it provides me more confidence in an environment that matches the deployment environment.

I personally don't like living in a VM window to work.  I also feel that I'm already running a windows manager (Windows or OSX) on my host operating system, so why incur the overhead of running another one in the VM.  Therefore, I run a "headless" Linux in the VM, and open X windows on the host by running a simple X server on the host OS.

Step 1 - Setup an X server on the host OS

For Windows, I recommend VcXsrv (see http://sourceforge.net/projects/vcxsrv/), but if you're already using Cygwin for other UNIX applications, the Cygwin Xserver (see http://x.cygwin.com/docs/ug/setup-cygwin-x-installing.html) works well, or alternatively you could try Xming (http://sourceforge.net/projects/xming/files/latest/download).

For OSX, I use XQuartz (see http://www.xquartz.org/)

Step 2 - Install VMWare (or VirtualBox, Parallels, etc.)

I'm not going to provide instructions for every virtualization software out there.  I use VMWare so that's what I'm describing.  Other solutions work just as well.

For Windows, VMWare Player does everything you need, and it's free!

For OSX, there's no free player, so you have to purchase VMWare Fusion.  (but, hey, it's the only thing you need to buy!).

Step 3 - Download a Linux distribution ISO

Again, there are plenty of options (Ubuntu, Red Hat, SuSE, etc), but I'm using Ubuntu here as it is frequently used for hosting.  You want the Server version (not Desktop) as it will be more light-weight without all the X11 + window manager overhead.  Also, I recommend the LTS (longer term service) version so you don't have to deal with upgrading your OS all the time (besides security fixes of course).

Step 4 - Create a New Virtual Machine

Select the VMWare option to create a new virtual machine, point it to the ISO and it should be pretty straight forward.

You don't have to be excessive with the resources you allocate for the VM.  The default recommendations by VMWare will probably suffice, but if you have a little more to give, then bump it up a little.  For example, the VMWare recommendation for the memory is 1GB, my system has 16GB so I gave the VM 2GB.  I allowed it 4 out of the 8 processor cores, and give it up to 40GB of disk space.

Step 5 - Forward local ports to VM

While this is not strictly necessary, it is useful.

For Windows, in earlier versions of VMWare Player, the Virtual Network Editor was included, but you needed to know the right command to access it.  In case the current omission is unintentional and they add the network editor back in future releases, the method to access the network editor for VMPlayer was:

  1. Open command prompt as administrator
  2. cd "C:\Program Files (x86)\VMware\VMware Player"
  3. rundll32.exe vmnetui.dll VMNetUI_ShowStandalone

As it stands currently, that will give you an error that the vmnetui.dll is not found.  So instead, you need to extract the Virtual Network Editor from the VMWare Workstation package.  This is done by:

  1. Download the latest VMWare Workstation package.
  2. unpack it locally with this command :
    "
    VMWare-worksation-full-10.0.1-xxxxxx.exe /e .\ext"
    note the xxxxxx is the release id you got at download
  3. Go to the newly created "ext" directory and open the "core.cab" (use your favorite zip util)
  4. Get the "vmnetcfg.exe" from there, and copy it to the vmwareplayer install directoryGet the "_vmnetcfglib.dll" file and rename it "vmnetcfglib.dll", and then copy it to the same directory than for vmnetcfg.exe
OR  

Download vmnetcfg.exe and vmnetcfglib.dll and put them in your VMWare Player install directory.

Once you have the Virtual Network Editor, select the NAT adapter (should be VMnet8), click on the "NAT Settings..." button, and add whatever ports you'll be using as shown below.  In this example, my VM IP is 192.168.216.131 and I'm forwarding ports 22 for SSH and 3000 as the default Rails server port.  Add port 80 if you'll be running your apps through a normal HTTP server like Apache or nginx (ex. via Passenger).




For Macs using VMWare Fusion, edit the vmnet8 NAT config file using the terminal and your favorite editor

sudo emacs /Library/Preferences/VMware\ Fusion/vmnet8/nat.conf

or
 
sudo vim /Library/Preferences/VMware\ Fusion/vmnet8/nat.conf
 
 
Near the bottom you’ll see something like this
 
[incomingtcp]
 
# Use these with care - anyone can enter into your VM through these...
# The format and example are as follows:
# = :
#8080 = 172.16.3.128:80
 
This is where we’ll be putting the port forwarding.  We'll assuming the same VM IP and that we still want to forward to the Rails server port 3000 and SSH port 22.   Since OSX is likely already running an SSH server on port 22, we'll forward from port 2222 instead.  So, add the lines:

3000 = 192.168.216.131:3000
2222 = 192.168.216.131:22 


Restart VMWare Fusion and it should be forwarding to these ports for you.  Alternatively, you could restart the VMWare networking using the command line:


sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --stop
sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --start


Optionally, if you want to ensure your VM always gets the same IP address, you can edit /Library/Preferences/VMware\ Fusion/vmnet8/dhcpd.conf and add a clause to the bottom with the format of:


host <some-name> {
    hardware ethernet <MAC-ADDRESS>;
    fixed-address <IP-address>;
}

You can determine the VMWare assigned MAC address for your VM by looking in your VM's *.vmx file and look for a line like:

ethernet0.generatedAddress = "00:0c:29:42:f0:54"

Then to assign a static IP address of 192.168.216.131 to this VM, you could add the clause:

host ubuntu {
    hardware ethernet 00:0c:29:42:f0:54;
    fixed-address
192.168.216.131;
}


Remember to restart the Fusion Networking services either by restarting Fusion or using the command line option.
Most of the OSX instructions came from http://encyclopediaofdaniel.com/blog/fusion-dhcp-port-forwarding/ where you can also find information on a Ruby gem to make the changes for you.

Step 6 - Connect using SSH with X forwarding

X11 forwarding needs to be enabled on both the client side and the server side.

On the client side, the -X (capital X) option to ssh enables X11 forwarding, and you can make this the default (for all connections or for a specific conection) with ForwardX11 yes in ~/.ssh/config.

On the server side, X11Forwarding yes must specified in /etc/ssh/sshd_config. Note that the default is no forwarding (some distributions turn it on in their default /etc/ssh/sshd_config), and that the user cannot override this setting.

The xauth program must be installed on the server side. If there are any X11 programs there, it's very likely that xauth will be there. In the unlikely case xauth was installed in a nonstandard location, it can be called through ~/.ssh/rc (on the server!).

Note that you do not need to set any environment variables on the server. DISPLAY and XAUTHORITY will automatically be set to their proper values. If you run ssh and DISPLAY is not set, it means ssh is not forwarding the X11 connection.

To confirm that ssh is forwarding X11, check for a line containing Requesting X11 forwarding in the ssh -v -X output. Note that the server won't reply either way.

(credit to http://unix.stackexchange.com/questions/12755/how-to-forward-x-over-ssh-from-ubuntu-machine)

Friday, November 20, 2015

Updated Clip All function for Publix Digital Coupons

Over a year ago, I provided the Clip All function for Publix Digital Coupons.  It's been working well and I've received plenty of positive feedback for it.

This month, Publix revised their digital coupon site and the function stopped working.  I have fixed my code and it should work again!  There are a few things to point out though.

First, the method I used in the past for attaching my JavaScript code to their site no longer works.  When I do that, it causes the page to re-load itself, which then negates the addition of my code.  I now load the code and invoke the function from within the bookmarklet.  That works out fine, but that method no longer allows me to re-direct you to the coupon site if you're not currently there.  So you need to invoke the code from the coupon site.

Second, the no longer have links to more pages of coupons, but load more dynamically as you scroll down the page.  I try to make the code emulate the scrolling activity to automatically load more coupons, but it doesn't always trigger the event to load more coupons.  So, if you're sitting on the bottom of the page with all the coupons 'clipped', try to scroll up and down a little to see if more coupons start loading.  If more load, the auto-clipping function should kick back into action.

Please go to https://pothoven.net/PublixClipper.html for installation instructions, and please drop me a comment here if you try it out to let me know how it works for you.

Tuesday, January 07, 2014

Bishop Swap Puzzle Fixed!

I implemented a Bishop Swap Puzzle back in 2007 (see my prior post), but it has had a bug in it where bishops of the same color could pass through each other.  I had noted it as a 'TODO' in my code comments while I was writing it, but I had neglected to go back and fix it and forgot all about it until I was trying it out again recently.

I'm happy to say that I've now fixed the bug and it works correctly, so happy gaming!


Once you've completed the Bishop Swap puzzle, be sure to check out the others!

Thursday, January 02, 2014

Clip All function for Publix Digital Coupons

Happy New Year!

Sadly, it's been over a year since my last post.  To make up for not contributing for so long, I'll provide a little gift for those of you who have resolved to save more in the new year.  In particular, you need to live in the southeastern United States and do your grocery shopping at Publix.

Last year, Publix introduced a digital coupon site. This site provides a collection of coupons that you can "clip" and then when you're at the checkout lane, you enter your phone number on the credit card reader keypad and it will automatically apply any coupons you have clipped that apply to the groceries you have purchased.  The problem with the site is that they have not provided a "Clip All" function, so you need to look through several pages of coupons and clip any coupon you're interested in one at a time.  This can be a very time consuming process as many pages of coupons can be added each week.

To rectify this problem, I created a bookmarklet that provides a "Clip All" function.  It will clip all on the current page of coupons and continue to navigate through all available pages of coupons and clip them all.  The bookmarklet also works from mobile devices (at least iPads) so you can even quickly clip all the digital coupons while you're in Publix using their WiFi.

Please go to https://pothoven.net/PublixClipper.html for installation instructions, and please drop me a comment here if you try it out to let me know how it works for you.