class WorldDb::Model::CityBase

Public Class Methods

create_or_update_from_attribs( new_attributes, values, opts={} ) click to toggle source
# File lib/worlddb/models/city_base.rb, line 108
def self.create_or_update_from_attribs( new_attributes, values, opts={} )
  #   attribs -> key/value pairs e.g. hash
  #   values  -> ary of string values/strings (key not yet known; might be starting of value e.g. city:wien)

  ## opts e.g. :skip_tags true|false

  ## fix: add/configure logger for ActiveRecord!!!
  logger = LogKernel::Logger.root

  value_numbers     = []
  value_tag_keys    = []
    
  ### check for "default" tags - that is, if present new_attributes[:tags] remove from hash
  value_tag_keys += find_tags_in_attribs!( new_attributes )

  city_class = City  # assume city type by default (use metro,district to change in fixture)
  new_attributes_metro = {}

  ## check for optional values

  values.each_with_index do |value,index|
    if match_state_for_country( value, new_attributes[:country_id] ) do |state|
         new_attributes[ :state_id ] = state.id
       end
    elsif match_country( value ) do |country|
            new_attributes[ :country_id ] = country.id
          end
    elsif match_metro( value ) do |metro|
            new_attributes[ :metro_id ] = metro.id
          end
    elsif match_metro_pop( value ) do |num|  # e.g  m: 1 444 444
            new_attributes_metro[ :pop ] = num    # note: gets added to **metro** attributes; triggers auto-added metro record
          end
    elsif match_metro_flag( value ) do |_|  # metro(politan area)
            city_class = Metro    # turn off default c|city flag; make it m|metro only
          end
    elsif match_city( value ) do |city|  # parent city for district
            new_attributes[ :city_id ] = city.id
            city_class = District # turn off default c|city flag; make it d|district only
          end
    elsif match_km_squared( value ) do |num|   # allow numbers like 453 km²
            value_numbers << num
          end
    elsif match_number( value ) do |num|    # numeric (nb: can use any _ or spaces inside digits e.g. 1_000_000 or 1 000 000)
            value_numbers << num
          end
    elsif value =~ /#{CITY_CODE_PATTERN}/  ## assume three-letter code
      new_attributes[ :code ] = value
    elsif (values.size==(index+1)) && is_taglist?( value )   # tags must be last entry
      logger.debug "   found tags: >>#{value}<<"
      value_tag_keys += find_tags( value )
    else
      # issue warning: unknown type for value
      logger.warn "unknown type for value >#{value}<"
    end
  end # each value

  if value_numbers.size > 0
    new_attributes[ :pop  ] = value_numbers[0]   # assume first number is pop for cities
    new_attributes[ :area ] = value_numbers[1]  
  end


    #######
    ## auto add metro if used M:/m: shortcut
    if new_attributes_metro.empty? == false
      new_attributes_metro[:key]        = new_attributes[:key]
      ## todo/fix: use title or name?
      new_attributes_metro[:name]       = new_attributes[:name] || new_attributes[:title]
      new_attributes_metro[:country_id] = new_attributes[:country_id]

      metro_rec = Metro.find_by_key( new_attributes_metro[ :key ] )

      if metro_rec.present?
        logger.debug "(auto-)update Metro #{metro_rec.id}-#{metro_rec.key}:"
      else
        logger.debug "(auto-)create Metro:"
        metro_rec = Metro.new
      end

      logger.debug new_attributes_metro.to_json

      metro_rec.update_attributes!( new_attributes_metro )
      new_attributes[:metro_id] = metro_rec.id
    end


  rec = city_class.find_by_key( new_attributes[ :key ] )

  if rec.present?
    logger.debug "update #{city_class.name} #{rec.id}-#{rec.key}:"
  else
    logger.debug "create #{city_class.name}:"
    rec = city_class.new
  end

  logger.debug new_attributes.to_json

  rec.update_attributes!( new_attributes )


    ##################
    ## add taggings

    ## todo/fix: reuse - move add taggings into method etc.

    if value_tag_keys.size > 0

      if opts[:skip_tags].present?
        logger.debug "   skipping add taggings (flag skip_tag)"
      else
        value_tag_keys.uniq!  # remove duplicates
        logger.debug "   adding #{value_tag_keys.size} taggings: >>#{value_tag_keys.join('|')}<<..."

        ### fix/todo: check tag_ids and only update diff (add/remove ids)

        value_tag_keys.each do |key|
          tag = Tag.find_by_key( key )
          if tag.nil?  # create tag if it doesn't exit
            logger.debug "   creating tag >#{key}<"
            tag = Tag.create!( key: key )
          end
          rec.tags << tag
        end
      end
    end

  rec
end
create_or_update_from_values( values, more_attribs={} ) click to toggle source
# File lib/worlddb/models/city_base.rb, line 98
def self.create_or_update_from_values( values, more_attribs={} )
  ## key & title & country required

  attribs, more_values = find_key_n_title( values )
  attribs = attribs.merge( more_attribs )

  ## check for optional values
  self.create_or_update_from_attribs( attribs, more_values )
end
parse( *args ) click to toggle source
# File lib/worlddb/models/city_base.rb, line 74
def self.parse( *args )
  ## remove (extract) attribs hash (if last arg is a hash n present)
  more_attribs = args.last.is_a?(Hash) ? args.pop : {}  ## extract_options!

  ## check if array passed in for batch (multi record) parse
  ##  - fix/todo: add to all other parse model methods too!!!! it's a standard (feature)
  if args.size == 1 && args[0].is_a?(Array)
    ## e.g. City.parse( [ 'Vienna', 'Salzburg' ] )
    ##  note: works for now only w/ *single* name/title records
    ##  add support for array in array too - why? why not?
    ##  e.g. City.parse( [['Vienna', 'VIE'],
    ##                    ['Salzbrug', 'SZB']] )
    ary = args[0]
    ## note: return array of new objs
    ary.map { |value| self.create_or_update_from_values( [value], more_attribs ) }
  else
    ## standard (sinlge) record case
    ##  e.g.  City.parse( 'Vienna', 'VIE', '1 800 000' )
    values  = args
    self.create_or_update_from_values( values, more_attribs )
  end
end

Public Instance Methods

all_names( opts={} ) click to toggle source
# File lib/worlddb/models/city_base.rb, line 60
def all_names( opts={} )
  ### fix:
  ## allow to passing in sep or separator e.g. | or other

  return name if alt_names.blank?
  
  buf = ''
  buf << name
  buf << ' | '
  buf << alt_names.split('|').join(' | ')
  buf
end
on_create() click to toggle source
# File lib/worlddb/models/city_base.rb, line 32
def on_create
  place_rec = Place.create!( name: name, kind: place_kind )
  self.place_id = place_rec.id 

  ## create name recs -- todo: add default lang etc. - move to: after_create callback!!
  Name.parse( name, alt_names,
                place_id:   place_rec.id,
                place_kind: place_rec.kind )
end
on_update() click to toggle source
# File lib/worlddb/models/city_base.rb, line 42
def on_update
  ## fix/todo: check - if name or kind changed - only update if changed ?? why? why not??
  place.update_attributes!( name: name, kind: place_kind )

  ## todo/fix:
  ## update names too ??
end
synonyms() click to toggle source
# File lib/worlddb/models/city_base.rb, line 25
def synonyms()       alt_names;              end
synonyms=(value) click to toggle source
# File lib/worlddb/models/city_base.rb, line 26
def synonyms=(value) self.alt_names = value; end
title() click to toggle source

begin compat

# File lib/worlddb/models/city_base.rb, line 22
def title()        name;              end
title=(value) click to toggle source
# File lib/worlddb/models/city_base.rb, line 23
def title=(value)  self.name = value; end