SearchKick – Remapping an Index

Recently someone updated a Rails Model ID datatype from int to uuid. This has caused issues with ElasticSearch in my local instance:

:exception:
- Searchkick::ImportError
- '{"type"=>"mapper_parsing_exception", "reason"=>"failed to parse [id]", "caused_by"=>{"type"=>"number_format_exception",
"reason"=>"For input string: \"03b42e85-1f09-402c-8f51-89d61c128ffc\""}} on item
with id ''03b42e85-1f09-402c-8f51-89d61c128ffc'''
:exception_object: '{"type"=>"mapper_parsing_exception", "reason"=>"failed to parse
[id]", "caused_by"=>{"type"=>"number_format_exception", "reason"=>"For input string:
\"03b42e85-1f09-402c-8f51-89d61c128ffc\""}} on item with id ''03b42e85-1f09-402c-8f51-89d61c128ffc'''

After some digging I around I was able to resolve this by deleting the Indexes. Rails/SearchKick rebuilt them afterwords.

You can view the available entries with a GET to elasticsearch with “*” as the path.

curl 'localhost:9200/*'

It’s easier to read if you pipe it into jq.

brew install jq
curl 'localhost:9200/*' | jq keys

From the list, identify the object that is failing, mine was organizations_development. Delete the mapping with

curl -XDELETE 'localhost:9200/organizations_development'

From there, elasticsearch will rebuild it and index your data.

Easily store hard coded values with Active Hash

Hard coded data is usually stored in the class that uses it.

#app/models/camper.rb
class Camper
  MEALS = {1: 'breakfast', 2:'lunch', 3: 'supper'}
 
end
 
Camper::MEALS

Active Hash is a library that helps Rails projects abstract this data out into an ActiveRecord like model:

#app/models/meals.rb
class Meals < ActiveHash::Base
  belongs_to :camper
 
  self.data = [
    { id: 1, name: 'breakfast'},
    { id: 2, name: 'lunch'},
    { id: 3, name: 'supper'}
  ]
end
 
#app/models/camper.rb
class Camper
  # required for ActiveRecord 3.1 or later
  extend ActiveHash::Associations::ActiveRecordExtensions
  has_many :meals
 
end
 
Camper.meals

This benefits our classes by removing data it’s not meant to represent. It helps the code architecture by not littering the application with constants. If someday we want that data to be an ActiveRecord model the code is already organized for it.

ActiveHash also works with FactoryGirl

FactoryGirl.define do
  factory :camper do
    name { 'Sally' }
    meals
  end
end

No Tests? No Excuses!

There is a strong testing vibe in our community. It’s a frequent topic in local groups, conferences, and interviews. Even with that drive in our community it’s common to land projects that have no working tests.

If you are only used to unit testing then it may seem overbearing to trash the existing test suite and start fresh. That’s because it is! It is impractical to delay your project to comb through every class and define it’s behavior in a test.

Getting a test suite quickly is possible when approaching it from the angle of acceptance testing. Ensuring the details are working together instead of testing them independently.

For example, when you hit a piñata, do you get candy? We’re not ensuring the piñata is mounted, that it can take a couple of whacks, or that the candy is delicious. We have a working example and can assume those attributes are true. If one of them is off the entire process fails.

In a Ruby on Rails project I can spend an afternoon and get a decent coverage of an applications expected behavior. Here is a sample of testing a home page using Rspec.

I’m not testing for every working component . This asks if the someone requests the homepage, do they get the elements that make the homepage. It is much easier to do a quick analysis and implementation with this method. I don’t even have to look at the source code to define expected behavior and ensure it doesn’t change.

This has an advantage in a refactoring scenario. It doesn’t matter how much we change the underlying code, the results of the homepage are expected to the same. Having integration tests gives us the confidence to strip out any code and give us quick feedback on the consequences.