Partners and Neighbourhoods

(and how this can trip up testing)

Neighbourhoods

Neighbourhoods are records that come from UK government source. They are built once when the application is being provisioned. They are hierarchical and higher neighbourhoods contain lower neighbourhoods. They do no store postcodes as higher up neighbourhoods will contain many postcodes. But in the record there is a field called 'unit' that can have the value of 'ward' and it is these wards that map to postcodes. A user can be assigned a neighbourhood that will give them permissions to modify certain partners that are also within those neighbourhoods. Users that have a higher level of neighbourhood than 'ward' will have many 'sub-neighbourhoods' that they can admin. So a user with a neighbourhood of 'London' will have the ability to work with partners in any of the London wards.

How Geocoding works

Geocoding is done by a gem and uses a remote server (postcodes.io) to map postcode to UK government neighbourhood data. We pass in a postcode and get back a chunk of data.

Then we look up in our neighbourhoods table the government ID and that is how we map postcode -> neighbourhood.

Creating or updating a partner

When a partner is created (or edited) they are given address fields 'Street address, Street address 2, Street address 3, City and Postcode'. With these filled in the user clicks save.

At a high level this is how it proceeds: if the address has changed, use the postcode to ask geocoder to find the ward ID. Then use the ward ID to find the neighbourhood and assign the neighbourhood to the address.

In more detail the algorithm looks like

user = rails session user

p = Partner.new(partner_attributes)

address = Address.where(street_address: new_address).where(postcode: new_postcode).find

if address.exists?
  p.address = address
  
else
  p.address.create(...new_params) do |address|
    geo_data = Geocoder.search(address.postcode)
    if geo_data.exists?
      neighbourhood = Neighbourhood.find_by_geo_data(geo_data)
      address.neighbourhood = neighbourhood
    end
  end
end

if not user.root?
  if not user.assigned_to_postcode?(p.address.postcode)
    raise 'you cannot edit partners outside your ward'
  end
end

p.save

Some gotchas

Neighbourhoods are not unique. This means duplicates can crop up and the data integrity is still considered sound. During testing many neighbourhoods can be built (by factories or fixtures) and they will be valid, but when tests are run one partner may have a neighbourhood ID of X and another partner could have a neighbourhood of Y even though both X and Y are the same.