Use a polymorphic association to model relation members and add
authorTom Hughes <tom@compton.nu>
Sat, 21 Jun 2008 17:38:17 +0000 (17:38 +0000)
committerTom Hughes <tom@compton.nu>
Sat, 21 Jun 2008 17:38:17 +0000 (17:38 +0000)
associations for upward links from objects to relations that they
are a part of.

app/models/node.rb
app/models/relation.rb
app/models/relation_member.rb
app/models/way.rb

index cc646b768c1aeb82fd6ce62c0f26724ed5f6a55b..4393f252679e12cf7a6c606ecd1331ad938228a2 100644 (file)
@@ -10,11 +10,16 @@ class Node < GeoRecord
   validates_numericality_of :latitude, :longitude
   validate :validate_position
 
-  has_many :ways, :through => :way_nodes
+  belongs_to :user
+
   has_many :old_nodes, :foreign_key => :id
+
   has_many :way_nodes
-  belongs_to :user
+  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?
index cedfaf656250e25b01f148b8c8175f13153e035b..cd2d67cdde0b969020d88530fdc82748f6f19451 100644 (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
index 79102853e9c218a362a52eedd5acf30b52233e19..9ff4f46f3b8b0b6ae4fb1b02ba49ccab25a71b66 100644 (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
+
+  def after_find
+    self[:member_class] = self.member_type.capitalize
+  end
 
-  # 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_initialize
+    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 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
index f1dc76eb4c6b65053214e1e80f6665f70ad10052..8ae6b40846944a41dca2ac03c542824fbb68fea1 100644 (file)
@@ -1,15 +1,19 @@
 class Way < ActiveRecord::Base
   require 'xml/libxml'
 
+  set_table_name 'current_ways'
+
   belongs_to :user
 
-  has_many :nodes, :through => :way_nodes, :order => 'sequence_id'
+  has_many :old_ways, :foreign_key => 'id', :order => 'version'
+
   has_many :way_nodes, :foreign_key => 'id', :order => 'sequence_id'
-  has_many :way_tags, :foreign_key => 'id'
+  has_many :nodes, :through => :way_nodes, :order => 'sequence_id'
 
-  has_many :old_ways, :foreign_key => 'id', :order => 'version'
+  has_many :way_tags, :foreign_key => 'id'
 
-  set_table_name 'current_ways'
+  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