Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Handle one_to_one associations in the association_dependencies plugin

  • Loading branch information...
commit 8bab13e2ed0066c04dd3e4d992d244e7ca5c0eda 1 parent c32456d
Jeremy Evans authored
21 lib/sequel/plugins/association_dependencies.rb
View
@@ -6,7 +6,7 @@ module Plugins
#
# * :many_to_many - :nullify (removes all related entries in join table)
# * :many_to_one - :delete, :destroy
- # * :one_to_many - :delete, :destroy, :nullify (sets foreign key to NULL for all associated objects)
+ # * :one_to_many, one_to_one - :delete, :destroy, :nullify (sets foreign key to NULL for all associated objects)
#
# This plugin works directly with the association datasets and does not use any cached association values.
# The :delete action will delete all associated objects from the database in a single SQL call.
@@ -23,7 +23,7 @@ module Plugins
module AssociationDependencies
# Mapping of association types to when the dependency calls should be made (either
# :before for in before_destroy or :after for in after_destroy)
- ASSOCIATION_MAPPING = {:one_to_many=>:before, :many_to_one=>:after, :many_to_many=>:before}
+ ASSOCIATION_MAPPING = {:one_to_many=>:before, :many_to_one=>:after, :many_to_many=>:before, :one_to_one=>:before}
# The valid dependence actions
DEPENDENCE_ACTIONS = [:delete, :destroy, :nullify]
@@ -52,13 +52,20 @@ module ClassMethods
def add_association_dependencies(hash)
hash.each do |association, action|
raise(Error, "Nonexistent association: #{association}") unless r = association_reflection(association)
+ type = r[:type]
raise(Error, "Invalid dependence action type: association: #{association}, dependence action: #{action}") unless DEPENDENCE_ACTIONS.include?(action)
- raise(Error, "Invalid association type: association: #{association}, type: #{r[:type]}") unless time = ASSOCIATION_MAPPING[r[:type]]
+ raise(Error, "Invalid association type: association: #{association}, type: #{type}") unless time = ASSOCIATION_MAPPING[type]
association_dependencies[:"#{time}_#{action}"] << if action == :nullify
- raise(Error, "Can't nullify many_to_one associated objects: association: #{association}") if r[:type] == :many_to_one
- r.remove_all_method
+ case type
+ when :one_to_many , :many_to_many
+ proc{send(r.remove_all_method)}
+ when :one_to_one
+ proc{send(r.setter_method, nil)}
+ else
+ raise(Error, "Can't nullify many_to_one associated objects: association: #{association}")
+ end
else
- raise(Error, "Can only nullify many_to_many associations: association: #{association}") if r[:type] == :many_to_many
+ raise(Error, "Can only nullify many_to_many associations: association: #{association}") if type == :many_to_many
r.dataset_method
end
end
@@ -87,7 +94,7 @@ def after_destroy
def before_destroy
model.association_dependencies[:before_delete].each{|m| send(m).delete}
model.association_dependencies[:before_destroy].each{|m| send(m).destroy}
- model.association_dependencies[:before_nullify].each{|m| send(m)}
+ model.association_dependencies[:before_nullify].each{|p| instance_eval(&p)}
super
end
end
21 spec/extensions/association_dependencies_spec.rb
View
@@ -20,7 +20,8 @@ def ds1.fetch_rows(s)
@Artist.columns :id, :name
@Album.columns :id, :name, :artist_id
@Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id
- @Artist.many_to_many :other_artists, :class=>@artist, :join_table=>:aoa, :left_key=>:l, :right_key=>:r
+ @Artist.one_to_one :first_album, :class=>@Album, :key=>:artist_id, :conditions=>{:position=>1}
+ @Artist.many_to_many :other_artists, :class=>@Artist, :join_table=>:aoa, :left_key=>:l, :right_key=>:r
@Album.many_to_one :artist, :class=>@Artist
MODEL_DB.reset
end
@@ -36,6 +37,18 @@ def ds1.fetch_rows(s)
@Album.load(:id=>1, :name=>'Al', :artist_id=>2).destroy
MODEL_DB.sqls.should == ['DELETE FROM albums WHERE (id = 1)', 'DELETE FROM artists WHERE (artists.id = 2)']
end
+
+ specify "should allow destroying associated one_to_one associated object" do
+ @Artist.add_association_dependencies :first_album=>:destroy
+ @Artist.load(:id=>2, :name=>'Ar').destroy
+ MODEL_DB.sqls.should == ['SELECT * FROM albums WHERE ((albums.artist_id = 2) AND (position = 1)) LIMIT 1', 'DELETE FROM albums WHERE (id = 1)', 'DELETE FROM artists WHERE (id = 2)']
+ end
+
+ specify "should allow deleting associated one_to_one associated object" do
+ @Artist.add_association_dependencies :first_album=>:delete
+ @Artist.load(:id=>2, :name=>'Ar').destroy
+ MODEL_DB.sqls.should == ['DELETE FROM albums WHERE ((albums.artist_id = 2) AND (position = 1))', 'DELETE FROM artists WHERE (id = 2)']
+ end
specify "should allow destroying associated one_to_many objects" do
@Artist.add_association_dependencies :albums=>:destroy
@@ -48,6 +61,12 @@ def ds1.fetch_rows(s)
@Artist.load(:id=>2, :name=>'Ar').destroy
MODEL_DB.sqls.should == ['DELETE FROM albums WHERE (albums.artist_id = 2)', 'DELETE FROM artists WHERE (id = 2)']
end
+
+ specify "should allow nullifying associated one_to_one objects" do
+ @Artist.add_association_dependencies :first_album=>:nullify
+ @Artist.load(:id=>2, :name=>'Ar').destroy
+ MODEL_DB.sqls.should == ['UPDATE albums SET artist_id = NULL WHERE ((artist_id = 2) AND (position = 1))', 'DELETE FROM artists WHERE (id = 2)']
+ end
specify "should allow nullifying associated one_to_many objects" do
@Artist.add_association_dependencies :albums=>:nullify
Please sign in to comment.
Something went wrong with that request. Please try again.