Use a polymorphic association to model relation members and add

associations for upward links from objects to relations that they
are a part of.
This commit is contained in:
Tom Hughes 2008-06-21 17:38:17 +00:00
parent a21824f754
commit b527d27674
4 changed files with 40 additions and 35 deletions

View file

@ -10,11 +10,16 @@ class Node < GeoRecord
validates_numericality_of :latitude, :longitude
validate :validate_position
has_many :ways, :through => :way_nodes
has_many :old_nodes, :foreign_key => :id
has_many :way_nodes
belongs_to :user
has_many :old_nodes, :foreign_key => :id
has_many :way_nodes
has_many :ways, :through => :way_nodes
has_many :containing_relation_members, :as => :member
has_many :containing_relations, :through => :containing_relation_members
# Sanity check the latitude and longitude and add an error if it's broken
def validate_position
errors.add_to_base("Node is not in the world") unless in_world?

View file

@ -1,14 +1,17 @@
class Relation < ActiveRecord::Base
require 'xml/libxml'
set_table_name 'current_relations'
belongs_to :user
has_many :old_relations, :foreign_key => 'id', :order => 'version'
has_many :relation_members, :foreign_key => 'id'
has_many :relation_tags, :foreign_key => 'id'
has_many :old_relations, :foreign_key => 'id', :order => 'version'
set_table_name 'current_relations'
has_many :containing_relation_members, :as => :member
has_many :containing_relations, :through => :containing_relation_members
def self.from_xml(xml, create=false)
begin

View file

@ -1,30 +1,23 @@
class RelationMember < ActiveRecord::Base
set_table_name 'current_relation_members'
# problem with RelationMember is that it may link to any one
# object (a node, a way, another relation), and belongs_to is
# not flexible enough for that. So we do this, which is ugly,
# but fortunately rails won't actually run the SQL behind that
# unless someone really accesses .node, .way, or
# .relation - which is what we do below based on member_type.
# (and no: the :condition on belongs_to doesn't work here as
# it is a condition on the *referenced* object not the
# *referencing* object!)
belongs_to :node, :foreign_key => "member_id"
belongs_to :way, :foreign_key => "member_id"
belongs_to :relation, :foreign_key => "member_id"
belongs_to :member, :polymorphic => true, :foreign_type => :member_class
belongs_to :relation, :foreign_key => :id
# so we define this "member" function that returns whatever it
# is.
def member()
return (member_type == "node") ? node : (member_type == "way") ? way : relation
def after_find
self[:member_class] = self.member_type.capitalize
end
# NOTE - relations are SUBJECTS of memberships. The fact that nodes,
# ways, and relations can be the OBJECT of a membership,
# i.e. a node/way/relation can be referenced throgh a
# RelationMember object, is NOT modelled in rails, i.e. these links
# have to be resolved manually, on demand.
def after_initialize
self[:member_class] = self.member_type.capitalize
end
def before_save
self.member_type = self[:member_class].downcase
end
def member_type=(type)
self[:member_type] = type
self[:member_class] = type.capitalize
end
end

View file

@ -1,15 +1,19 @@
class Way < ActiveRecord::Base
require 'xml/libxml'
belongs_to :user
set_table_name 'current_ways'
has_many :nodes, :through => :way_nodes, :order => 'sequence_id'
has_many :way_nodes, :foreign_key => 'id', :order => 'sequence_id'
has_many :way_tags, :foreign_key => 'id'
belongs_to :user
has_many :old_ways, :foreign_key => 'id', :order => 'version'
set_table_name 'current_ways'
has_many :way_nodes, :foreign_key => 'id', :order => 'sequence_id'
has_many :nodes, :through => :way_nodes, :order => 'sequence_id'
has_many :way_tags, :foreign_key => 'id'
has_many :containing_relation_members, :class_name => "RelationMember", :as => :member
has_many :containing_relations, :class_name => "Relation", :through => :containing_relation_members, :source => :relation
def self.from_xml(xml, create=false)
begin