Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions motion/adapters/array_model_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,15 @@ def assign_id(options) #nodoc
end

def belongs_to_relation(col) # nodoc
col.classify.find_by_id(_get_attr(col.foreign_key))
if col.polymorphic
klass, id = get_polymorphic_attr(col)
if klass
klass = Kernel.deep_const_get(klass) if klass.is_a?(String)
klass.find_by_id(id)
end
else
col.classify.find_by_id(_get_attr(col.foreign_key))
end
end

def has_many_relation(col) # nodoc
Expand All @@ -157,7 +165,11 @@ def has_one_relation(col) # nodoc

def _has_many_has_one_relation(col) # nodoc
related_klass = col.classify
related_klass.find(col.inverse_column.foreign_key).belongs_to(self, related_klass).eq(_get_attr(:id))
if col.polymorphic
related_klass.find(col.inverse_column.foreign_key).eq(_get_attr(:id)).and(col.inverse_column.foreign_polymorphic_type).eq(self.className)
else
related_klass.find(col.inverse_column.foreign_key).belongs_to(self, related_klass).eq(_get_attr(:id))
end
end

def do_insert(options = {})
Expand Down
5 changes: 3 additions & 2 deletions motion/model/column.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ def foreign_key
end

def classify
fail "Column#classify indeterminate for polymorphic associations" if type == :belongs_to && polymorphic
if @klass
if type == :belongs_to && polymorphic
nil
elsif @klass
@klass
else
case @type
Expand Down
4 changes: 2 additions & 2 deletions motion/model/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ def set_belongs_to_attr(col, owner, options = {})
# Determine if the :belongs_to relationship is synchronized. Checks the instance and the DB column attributes.
def belongs_to_synced?(col, owner)
# The :belongs_to that points to the instance has changed
return false if get_belongs_to_attr(col) != owner
return false if !col.polymorphic && get_belongs_to_attr(col) != owner

# The polymorphic reference (_type, _id) columns do not match, maybe it was just saved
return false if col.polymorphic && !polymorphic_attr_matches?(col, owner)
Expand Down Expand Up @@ -765,7 +765,7 @@ def get_polymorphic_attr(col)
unless id.nil?
owner_class_name = _get_attr(_col.foreign_polymorphic_type)
owner_class_name = String(owner_class_name) # RubyMotion issue, String#classify might fail otherwise
owner_class = Kernel::deep_const_get(owner_class_name.classify)
owner_class = Kernel::deep_const_get(owner_class_name)
end
[owner_class, id]
end
Expand Down
2 changes: 1 addition & 1 deletion spec/date_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class ProtectedUpdateable
class Model
include MotionModel::Model
include MotionModel::ArrayModelAdapter
columns :test_date => :date,
columns :test_date => :date
end

it 'parses ISO8601 format variant #1 (RoR default)' do
Expand Down
98 changes: 98 additions & 0 deletions spec/polymorphic_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
class Tag
include MotionModel::Model
include MotionModel::ArrayModelAdapter

columns(
name: :string
)

belongs_to :tagged, polymorphic: true
end

class Gadget
include MotionModel::Model
include MotionModel::ArrayModelAdapter

columns(
name: :string
)

has_many :tags, dependent: :destroy, class: Tag, inverse_of: :tagged, polymorphic: true
end

class Widget
include MotionModel::Model
include MotionModel::ArrayModelAdapter

columns(
name: :string
)

has_many :tags, dependent: :destroy, class: Tag, inverse_of: :tagged, polymorphic: true
end

describe 'polymorphic relationships' do
describe 'polymorphic belongs to' do
before do
Tag.delete_all
Gadget.delete_all
Widdget.delete_all
end

it 'can relate to different classes' do
gadget1 = Gadget.create(name: 'Gadget 1')
gadget2 = Gadget.create(name: 'Gadget 2')
gadget3 = Gadget.create(name: 'Gadget 3')
widget1 = Widget.create(name: 'Widget 1')
widget2 = Widget.create(name: 'Widget 2')

tag1 = Tag.create(name: 'Tag 1', tagged: gadget1)
tag2 = Tag.create(name: 'Tag 2', tagged: gadget2)
tag3 = Tag.create(name: 'Tag 3', tagged: gadget2)
tag4 = Tag.create(name: 'Tag 4', tagged: gadget3)
tag5 = Tag.create(name: 'Tag 5', tagged: widget1)
tag6 = Tag.create(name: 'Tag 6', tagged: widget1)
tag7 = Tag.create(name: 'Tag 7', tagged: widget2)

gadget1.tags.to_a.should == [tag1]
gadget2.tags.to_a.should == [tag2, tag3]
gadget3.tags.to_a.should == [tag4]
widget1.tags.to_a.should == [tag5, tag6]
widget2.tags.to_a.should == [tag7]
end
end

describe 'polymorphic has many' do
before do
Tag.delete_all
Gadget.delete_all
Widdget.delete_all
end

it 'can relate polymorphuc records' do
gadget1 = Gadget.create(name: 'Gadget 1')
gadget2 = Gadget.create(name: 'Gadget 2')
gadget3 = Gadget.create(name: 'Gadget 3')
widget1 = Widget.create(name: 'Widget 1')
widget2 = Widget.create(name: 'Widget 2')

gadget1.tags << Tag.create(name: 'Tag 1')
gadget2.tags << Tag.create(name: 'Tag 2')
gadget2.tags << Tag.create(name: 'Tag 3')
gadget3.tags << Tag.create(name: 'Tag 4')
widget1.tags << Tag.create(name: 'Tag 5')
widget1.tags << Tag.create(name: 'Tag 6')
widget2.tags << Tag.create(name: 'Tag 7')

Tag.all.to_a.map(:tagged).should == [
gadget1,
gadget2,
gadget2,
gadget3,
widget1,
widget1,
widget2,
]
end
end
end