Friday, August 29, 2014

Buying and Using a Used Verizon Phone

To buy a used Verizon phone, you first want to find a vendor. You could use a directory and intermediary service like Swappa. Swappa basically provides a directory listing and they ask the seller to try to ensure the phone is clean before sale. However, it does not absolve you from needing to ask that the phone has a non-zero and clean (not reported stolen) IMEI and is able to be activated on the Verizon network without additional work. If the phone is rooted be very careful, as it might have an IMEI of 0, which will be a problem. If you decide to go forward with the purchase, Swappa charges the buyer a certain amount (e.g. $10) as part of the sale as well as charging you from the seller the remaining amount of the sale, such that on your Paypal bill you would see the bill for Swappa and the charge from the seller. You can track the device during shipping and when you receive it, you must first check the IMEI to ensure it is not 0, and then try activating it. If you have any problem with your device don't mark the device as received; you would then need to comment on the sale page and then manually send a note in the resolution area of Paypal against the Seller (not Swappa) stating that the seller needs to reimburse you because you are sending the phone back, and then Swapper and seller must then credit you that amount they charged back. So, what Swappa really is doing here is just acting as a directory service and arbitrator for the sale. If you'd rather, you could try buying the phone on eBay or Craiglist, etc. If you do that, take the same precautions asking the seller if the device has a clean, non-zero IMEI that can be used on the Verizon network (e.g. CDMA, 3G (old/slow) or 4G LTE). You may need to go get a new SIM card from Verizon in order to activate your device. Unfortunately for the hearing impaired or those using chat, the Verizon chat support cannot help to the same extent that the phone support staff can, and they are much slower. Newer 4G LTE Verizon devices can automatically register on the network as part of the process, though you may have to reset your network settings on some devices if you are doing something like changing the phone number associated with the SIM. SIMs can vary in size! Older devices will need to call *228 to register on the Verizon network. This involves having to enter "1" on the phone to register after it is answered. The old device must either be off or the battery or even the SIM removed if the phone cannot be turned off (if the screen is badly damaged). To ensure your new device is both registered and able to use the Verizon network, you can call #832. I do not work for Verizon, so don't ask me questions in the comments- just call Verizon for assistance. Good luck!

Tuesday, August 26, 2014

The set -e bash RVM script fix now breaks RVM again

Just found out that with the newer RVM (rvm 1.25.28 (stable), ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]), the old fix that we used in our bash script:


  if test -f ~/.rvm/scripts/rvm; then
    [ "$(type -t rvm)" = "function" ] || source ~/.rvm/scripts/rvm
  fi

That allowed use of so that RVM wouldn't break when using both set -e and cd'ing into a project directory that has a .ruby-version/.ruby-gemset:


  set -e
  cd /some/path/to/project

Will now break the script. Tracking this in issue #3017 of RVM v1.

Tuesday, August 19, 2014

Apple Won't Merge Your Multiple Apple IDs

Just had a few hour long conversation with Apple through 3 levels of their tech support discussing something very simple: moving the purchase history from one Apple ID to another.

Both Apple IDs belong to me, and both IDs are similar, except that one was created prior to Apple using email addresses as IDs and the other was created as an email address, because the device at the time would not allow me to login with the non-email address Apple ID. Each account has purchase history that I'd rather not lose.

The only two solutions the Apple representatives stated that you can use if you find yourself in this situation are:

  1. Login as each account and download your purchases, and/or
  2. In order to avoid what seems sometimes to be a mandate to convert your old non-email address to an email address Apple ID, just get another email address and rename the non-email address account to that other email address.

The primary reason that Apple provided for why this is the case is that merging Apple ID accounts would be a "security issue". They did not describe what that issue was.

I specifically stated that I only require them to move the purchase history from the original account to the new account. I also successfully authenticated both online and over the phone with the representative to both accounts. For me, it is not a security issue. It is a customer service issue.

A greater concern is that two of the representatives said that this was a frequent cause of customer complaints. It was like I was hearing Bill Clinton say, "I feel your pain-", but over and over (and over) again. If it is such a pain, why haven't they done anything about it?

What reason is there to disallow the move of purchase history from one Apple ID to another? How simple would it have been and how much money would Apple be saving in customer service calls if they were to only develop a tool that customers could use to transfer ownership of an app from one account to another? It could even restrict the move to require that both accounts share the same primary email address.

In the meantime, maybe one of the workarounds Apple provided above might help you. They didn't really help me.

Note: this was written August 19, 2014. Hopefully at some point Apple will come to their senses and resolve this, so please contact them if you need support.

Friday, May 30, 2014

"Try not. Do... or do not. There is no try."

At first glance, the try method in Rails is great. It's a quick way to do nil checks in a chain to get at associations and attributes. I've avoided it when I can, partly out of habit and partly because its syntax can be slightly less readable. However, there is another reason to not use try: it can also hide seriously time-wasting bugs caused by misnamed methods, e.g.:


$ rails c
...
2.1.1 :001 > if ''.try(:incorrectly_named_method)
2.1.1 :002?>   # assume method returned nil
2.1.1 :003 > end
 => nil 
2.1.1 :004 > unless ''.incorrectly_named_method
2.1.1 :005?>   # assume method returned nil
2.1.1 :006 > end
NoMethodError: undefined method `incorrectly_named_method' for "":String
 from (irb):4
 ...
 from bin/rails:4:in `require'
 from bin/rails:4:in `
'

That undefined method error on execution can really help. If you avoid it, then if the method name changes, or if you had typed the method name incorrectly, you may not find out about it quickly.

Why would you use try? A few good reasons for using try might be: (1) you are absolutely sure the method name is correct and will not change, and/or (2) you might have used defined? to check that the method existed before attempting to call the method.

Remember that Yoda said, "Try not. Do... or do not. There is no try."

Tuesday, April 15, 2014

Temporarily Force a No-arg Initializer in Ruby

How to temporarily bypass a Ruby class initializer, which you shouldn't do unless you really just need access to the instance and don't require any setup that happens in the initializer:

def force_class_instance(klass)
  result = nil
  if klass.instance_method(:initialize).parameters.any? {|ar|ar[0] == :req}
    klass.class_eval 'alias_method :orig_initialize, :initialize; def initialize; end'
    result = klass.new
    warn_level = $VERBOSE
    $VERBOSE = nil
    klass.class_eval 'remove_method :initialize; alias_method :initialize, :orig_initialize; remove_method :orig_initialize'
    $VERBOSE = warn_level
  else
    result = klass.new
  end
  result
end

Now just use force_class_instance(YourClass) to get an instance.

The $VERBOSE setting is to avoid "(eval):1: warning: removing `initialize' may cause serious problems" showing up in the log.

Tuesday, March 18, 2014

Extract the Version of Bundler, Chef, Ruby, etc. for CI

RVM and rbenv can use the .ruby-version file to define the Ruby version to use for your application. What about extracting the versions for Bundler and Chef?

If your application doesn't need to know anything about Chef, but you want your CI build/tests for that application to use your Chef bootstrapping process to set up your VM, maybe in your Chef repo where you keep your recipes, etc., your Chef Gemfile might look like:

chef_version = File.read(
  File.join(
    File.dirname(__FILE__),
      '.chef-version')).strip

gem 'chef', chef_version

And, let's say that you have a Chef bootstrap script that needs to install Bundler prior to doing bundle install:

gem install bundler --version=`cat .bundler-version`
bundle install

Now put the Chef version in .chef-version and the Bundler version in .bundler-version, e.g. if a version is 1.2.3, then the file would only contain:

1.2.3

Your application's repo just has .ruby-version and the rest of the application, but after you clone it and change to that directory in CI, you could do the following to grab and use those new version files from the Chef git repo. More about git archive here:

rbenv install `cat .ruby-version` || true
rbenv local
git archive --format=tar \
  --remote=your_chef_git_repo_uri \
  HEAD: .chef-version .bundler-version \
  | tar -x
gem install bundler --version=`cat .bundler-version`
gem install chef --version=`cat .chef-version`

That installs ruby if it isn't there (need || true so won't fail if already installed), uses it, just gets .chef-version and .bundler-version from another git repo, and then installs bundler, then chef, and you are ready to start bootstrapping. If you are using RVM like I do in development (this is the long version- you might not need all of this):

if test -f ~/.rvm/scripts/rvm; then
    [ "$(type -t rvm)" = "function" ] \
       || source ~/.rvm/scripts/rvm
fi
rvm get stable
rvm install `cat .ruby-version` || true
# if using gemset, specify that too, and --create
rvm use `cat .ruby-version`
git archive --format=tar \
  --remote=your_chef_git_repo_uri \
  HEAD: .chef-version .bundler-version \
  | tar -x
gem install bundler --version=`cat .bundler-version`
gem install chef --version=`cat .chef-version`

It is a bit dirty. Docker may be a better choice now for getting setup quickly, but if you use chef and other shell scripts, etc., then extracting version numbers might help.

Monday, March 17, 2014

Using Bullet with MiniTest to Identify N+1 Queries

The Bullet gem can be helpful when used on an on-demand basis to identify some n+1 query problems in code called by your integration tests. Although Tommy noticed that Bullet gives a false notification (see #148 for status) when using empty? on a relation that would trigger a query unless there is an includes, it identified some n+1 queries effectively.

In your test group in Gemfile:

# this example is just for testing,
# but it might be helpful in development as well
group :test do
  # ...
  gem 'bullet', '~> 4.8.0'
end

Then at command-line:

bundle install

In test_helper, we require a file that contains something similar to the following:

if ENV['BULLET']
  Bullet.enable = true
  # it is set this way by default, but being explicit
  Bullet.raise = false

  require 'minitest/unit'
  module MiniTestUsesBullet
    def before_setup
      Bullet.start_request
      super if defined?(super)
    end

    def after_teardown
      super if defined?(super)
      Bullet.end_request
      if passed?
        # format however you want
        raise "Bullet failed: #{Bullet.warnings.inspect}" if Bullet.warnings.present?
      end
    end
  end

  class MiniTest::Unit::TestCase
    include MiniTestUsesBullet
  end
end

Then prefix BULLET=1 in command line when running a test or all tests. Bullet docs note similar, but they use rspec and they leave it kind of up-in-the-air of what to use. We originally tried Bullet.raise=true, but Tommy noticed that hides valid ActiveRecord errors because the Bullet (4.8.0 at least) raises at the end of the Rack request handling. So, instead you need to only fail if the test passed and if there are warnings. As Tommy noted, since it is Rack based, you might only add this to your integration tests (not controller tests, etc.) vs. MiniTest::Unit::TestCase, and he said this works for better format:

raise warnings.values.flatten.map(&:full_notice).join('\n') unless warnings.values.empty?