Skip to content

Commit

Permalink
improved sti support
Browse files Browse the repository at this point in the history
  • Loading branch information
rsl committed Jul 3, 2008
1 parent e15f547 commit e171109
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 15 deletions.
23 changes: 14 additions & 9 deletions lib/lucky_sneaks/proxy_attributes.rb
Expand Up @@ -11,11 +11,12 @@ module ClassMethods
# Please read the README.rdoc[link:files/README_rdoc.html]
# for a full explanation and example of this method
def proxy_attributes(&block)
cattr_accessor :attributes_for_string, :forceable_associations, :dont_swallow_errors,
:before_creating_procs, :attributes_as_string_separator
self.attributes_for_string = {}.with_indifferent_access
self.forceable_associations = []
self.before_creating_procs = {}.with_indifferent_access
class_inheritable_accessor :attributes_as_string_separator, :dont_swallow_errors
class_inheritable_array :forceable_associations
class_inheritable_hash :attributes_for_string, :before_creating_procs
self.attributes_for_string ||= {}.with_indifferent_access
self.forceable_associations ||= []
self.before_creating_procs ||= {}.with_indifferent_access

integrator = LuckySneaks::ProxyIntegrator.new(self)
integrator.instance_eval(&block)
Expand Down Expand Up @@ -101,8 +102,10 @@ def assign_proxy_members_by_string(association_id, string)
self.send(proxy.name) << string.split(separator).map { |substring|
next if substring.blank?
member = proxy.klass.send("find_or_initialize_by_#{attribute}", substring)
if before_creation_proc = self.class.before_creating_procs[association_id.singularize]
instance_exec member, &before_creation_proc
if before_creation_procs = self.class.before_creating_procs[association_id.singularize]
before_creation_procs.each do |before_creation_proc|
instance_exec member, &before_creation_proc
end
end
if member.save
member
Expand All @@ -122,8 +125,10 @@ def create_proxy_member(association_id, hash_of_attributes)
end

member = proxy.klass.new(hash_of_attributes)
if before_creation_proc = self.class.before_creating_procs[association_root]
instance_exec member, &before_creation_proc
if before_creation_procs = self.class.before_creating_procs[association_root]
before_creation_procs.each do |before_creation_proc|
instance_exec member, &before_creation_proc
end
end
if member.save
if !manually_settable?(proxy) && !new_record?
Expand Down
4 changes: 3 additions & 1 deletion lib/lucky_sneaks/proxy_integrator.rb
Expand Up @@ -118,7 +118,9 @@ def just_defaults(*association_ids)
# end
def before_creating(*association_ids, &block)
association_ids.each do |association_id|
parent.before_creating_procs[association_id.to_s.singularize] = block
key = association_id.to_s.singularize
parent.before_creating_procs[key] ||= []
parent.before_creating_procs[key] << block
end
end

Expand Down
56 changes: 51 additions & 5 deletions test/proxy_attributes_test.rb
Expand Up @@ -22,7 +22,7 @@

create_table :documents, :force => true do |t|
t.integer :project_id
t.string :title
t.string :title, :type
end

create_table :categories, :force => true do |t|
Expand Down Expand Up @@ -53,13 +53,14 @@

create_table :mystery_meats, :force => true do |t|
t.integer :document_id, :project_id
t.string :meat
t.string :meat, :garnish
end
end
ActiveRecord::Migration.verbose = true

class Project < ActiveRecord::Base
has_many :documents
has_many :pages
has_many :mystery_meats
end

Expand Down Expand Up @@ -89,6 +90,14 @@ class Document < ActiveRecord::Base
validates_presence_of :title
end

class Page < Document
proxy_attributes do
before_creating(:mystery_meats) do |meat|
meat.garnish = self.title
end
end
end

class Category < ActiveRecord::Base
has_many :categorizations
has_many :documents, :through => :categorizations
Expand Down Expand Up @@ -135,6 +144,14 @@ def unsaveable_doc(optional = {})
Document.new(optional)
end

def saveable_page(optional = {})
unsaveable_page(optional.merge(:title => "Saveable Page"))
end

def unsaveable_page(optional = {})
Page.new(optional)
end

def setup
# Just to be safe
[Document, Category, Tag, Attachment, MysteryMeat].each do |foo|
Expand Down Expand Up @@ -169,22 +186,30 @@ def test_assigns_children_by_ids_plain_has_many_support
assert_equal [@badge.id], @doc.badge_ids
end

def test_creates_child_by_ids_if_parent_saves
def test_assigns_children_by_ids_sti_support
@cat = Category.create(:title => "Saved Page")
@page = saveable_page(:category_ids => [@cat.id])
@page.save
assert @page.categories.include?(@cat)
assert @cat.documents.include?(@page)
end

def test_add_child_if_parent_saves
@doc = saveable_doc(:add_category => {:title => "Created"})
@doc.save
@cat = Category.find_by_title("Created")
assert @doc.categories.include?(@cat)
assert @cat.documents.include?(@doc)
end

def test_does_not_create_child_if_parent_save_fails
def test_does_not_add_child_if_parent_save_fails
@doc = unsaveable_doc(:add_category => {:title => "Not Created"})
@doc.save
assert @doc.categories.empty?
assert_nil Category.find_by_title("Not Created")
end

def test_caches_attributes_for_reassignment_if_parent_save_fails
def test_add_child_caches_attributes_for_reassignment_if_parent_save_fails
@doc = unsaveable_doc(:add_category => {:title => "Not Created"})
@doc.save
# Man I wish Foo.new == Foo.new, but it doesn't
Expand Down Expand Up @@ -227,6 +252,14 @@ def test_add_child_support_for_plain_has_many
assert_equal @doc, @badge.document
end

def test_add_child_sti_support
@page = saveable_page(:add_category => {:title => "Created"})
@page.save
@cat = Category.find_by_title("Created")
assert @page.categories.include?(@cat)
assert @cat.documents.include?(@page)
end

def test_assigns_children_by_string_if_parent_saves
@tag = Tag.create(:title => "prexisting")
@doc = saveable_doc(:tags_as_string => "prexisting")
Expand Down Expand Up @@ -398,4 +431,17 @@ def test_children_as_string_allows_procs
assert @project.mystery_meats.include?(@meat)
assert_equal @project, @meat.project
end

def test_child_creation_procs_with_sti
@project = Project.create!(:title => "some project")
@page = @project.pages.create(:title => "page in a project")
assert @project.pages.include?(@page)
assert_equal @project, @page.project
@page.add_mystery_meat = {:meat => "mystery meat for page in a project"}
@page.save
@meat = MysteryMeat.find_by_meat("mystery meat for page in a project")
assert @project.mystery_meats.include?(@meat)
assert_equal @project, @meat.project
assert_equal @page.title, @meat.garnish
end
end

0 comments on commit e171109

Please sign in to comment.