property 0.9.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/History.txt +19 -3
- data/README.rdoc +51 -6
- data/lib/property.rb +4 -2
- data/lib/property/attribute.rb +14 -7
- data/lib/property/base.rb +16 -0
- data/lib/property/column.rb +13 -1
- data/lib/property/declaration.rb +48 -26
- data/lib/property/error.rb +4 -0
- data/lib/property/index.rb +104 -29
- data/lib/property/properties.rb +7 -1
- data/lib/property/redefined_method_error.rb +8 -0
- data/lib/property/redefined_property_error.rb +8 -0
- data/lib/property/role.rb +30 -0
- data/lib/property/{behavior.rb → role_module.rb} +67 -35
- data/lib/property/schema.rb +76 -32
- data/lib/property/stored_column.rb +30 -0
- data/lib/property/stored_role.rb +101 -0
- data/property.gemspec +20 -5
- data/test/fixtures.rb +39 -1
- data/test/shoulda_macros/index.rb +95 -0
- data/test/shoulda_macros/role.rb +237 -0
- data/test/shoulda_macros/serialization.rb +1 -1
- data/test/test_helper.rb +2 -0
- data/test/unit/property/base_test.rb +80 -0
- data/test/unit/property/declaration_test.rb +89 -30
- data/test/unit/property/index_foreign_test.rb +2 -2
- data/test/unit/property/index_simple_test.rb +17 -4
- data/test/unit/property/role_test.rb +78 -0
- data/test/unit/property/stored_role_test.rb +84 -0
- data/test/unit/property/validation_test.rb +26 -4
- metadata +22 -7
- data/test/unit/property/behavior_test.rb +0 -146
data/.gitignore
CHANGED
data/History.txt
CHANGED
@@ -1,6 +1,22 @@
|
|
1
|
+
== 1.0.0 2010-05-27
|
2
|
+
|
3
|
+
* Major enhancements
|
4
|
+
* Added StoredRole class to store role definitions in the database.
|
5
|
+
* Validates with legacy but invalid properties if value is unchanged.
|
6
|
+
* Added the notion of used roles.
|
7
|
+
* Renamed Behavior to Role.
|
8
|
+
* Added support for index definition in stored column.
|
9
|
+
* Added support for :with option in index_reader.
|
10
|
+
|
11
|
+
* 2 minor enhancements
|
12
|
+
* Created Property::Base module for inclusion without callbacks.
|
13
|
+
* Raises an exception if we try to define a property that would hide a superclass method.
|
14
|
+
* Fixed multiple column declarations in one go.
|
15
|
+
* Fixed bug when adding role as class to sub-class.
|
16
|
+
|
1
17
|
== 0.9.1 2010-03-20
|
2
18
|
|
3
|
-
*
|
19
|
+
* 2 major enhancements
|
4
20
|
* Added support for custom indexer classes.
|
5
21
|
* Removed after_commit dependency (no need for an after_commit).
|
6
22
|
|
@@ -24,13 +40,13 @@
|
|
24
40
|
== 0.8.1 2010-02-14
|
25
41
|
|
26
42
|
* 2 major enhancement
|
27
|
-
* Enabled
|
43
|
+
* Enabled role method definitions.
|
28
44
|
* Enabled external storage with 'store_properties_in' method.
|
29
45
|
|
30
46
|
== 0.8.0 2010-02-11
|
31
47
|
|
32
48
|
* 3 major enhancements
|
33
|
-
* Enabled
|
49
|
+
* Enabled Roles that can be added on an instance.
|
34
50
|
* Enabled non-DB types.
|
35
51
|
* 100% test coverage.
|
36
52
|
|
data/README.rdoc
CHANGED
@@ -47,12 +47,12 @@ And set them with:
|
|
47
47
|
@contact.prop['name'] = 'Gandhi'
|
48
48
|
@contact.name = 'Gandhi'
|
49
49
|
|
50
|
-
==
|
50
|
+
== Roles
|
51
51
|
|
52
52
|
Properties would not be really fun if you could not add new properties to your instances depending
|
53
|
-
on
|
53
|
+
on what the object does. First define the roles:
|
54
54
|
|
55
|
-
@picture = Property::
|
55
|
+
@picture = Property::Role.new do |p|
|
56
56
|
p.integer :width, :default => :get_width
|
57
57
|
p.integer :height, :default => :get_height
|
58
58
|
p.string 'camera'
|
@@ -76,16 +76,21 @@ on some flags. First define the behaviors:
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
And then, either when creating new pictures or updating them, you need to include the
|
79
|
+
And then, either when creating new pictures or updating them, you need to include the role:
|
80
80
|
|
81
|
-
@model.
|
81
|
+
@model.has_role @picture
|
82
82
|
|
83
83
|
The model now has the picture's properties defined, with accessors like @model.camera, methods like
|
84
84
|
@model.image, get_with, etc and default values will be fetched on save.
|
85
85
|
|
86
|
-
Note that you do not need to include a
|
86
|
+
Note that you do not need to include a role just to read the data as long as you use the 'prop'
|
87
87
|
accessor.
|
88
88
|
|
89
|
+
== StoredRole
|
90
|
+
|
91
|
+
The dynamic nature of the Property gem goes to the point where you can store your property definitions
|
92
|
+
in the database by using the StoredRole and StoredColumn modules.
|
93
|
+
|
89
94
|
== External storage
|
90
95
|
|
91
96
|
You might need to define properties in a model but store them in another model (versioning). In this
|
@@ -102,3 +107,43 @@ case you can simply use 'store_properties_in' class method:
|
|
102
107
|
|
103
108
|
Doing so will not touch the storage class. All property definitions, validations and method
|
104
109
|
definitions are executed on the 'Contact' class.
|
110
|
+
|
111
|
+
== Indexing support
|
112
|
+
|
113
|
+
The property gem lets you very easily export content from the packed data to any kind of external table. Using
|
114
|
+
a key/value tables:
|
115
|
+
|
116
|
+
class Contact < ActiveRecord::Base
|
117
|
+
include Property
|
118
|
+
property do |p|
|
119
|
+
p.string 'name', :indexed => true
|
120
|
+
p.string 'first_name', :index => Proc.new {|rec| { 'fullname' => rec.fullname }}
|
121
|
+
|
122
|
+
p.index(:string) do |record|
|
123
|
+
{
|
124
|
+
'fulltext' => "name:#{record.name} first_name:#{record.first_name}",
|
125
|
+
"name_#{record.lang}" => record.name
|
126
|
+
}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
Using a custom indexer, you can group indexed values together in a single record. This can be interesting if you have
|
132
|
+
some legacy code or queries that need direct access to some values:
|
133
|
+
|
134
|
+
class Contact < ActiveRecord::Base
|
135
|
+
include Property
|
136
|
+
property do |p|
|
137
|
+
p.string 'name'
|
138
|
+
p.string 'first_name'
|
139
|
+
|
140
|
+
p.index(ContactIndexer) do |record|
|
141
|
+
{
|
142
|
+
'name' => record.name,
|
143
|
+
'first_name' => record.first_name,
|
144
|
+
}
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
Please read the docs for details: http://zenadmin.org/635
|
data/lib/property.rb
CHANGED
@@ -2,16 +2,18 @@ require 'property/attribute'
|
|
2
2
|
require 'property/dirty'
|
3
3
|
require 'property/properties'
|
4
4
|
require 'property/column'
|
5
|
-
require 'property/
|
5
|
+
require 'property/role'
|
6
|
+
require 'property/stored_role'
|
6
7
|
require 'property/schema'
|
7
8
|
require 'property/declaration'
|
8
9
|
require 'property/db'
|
9
10
|
require 'property/index'
|
10
11
|
require 'property/serialization/json'
|
11
12
|
require 'property/core_ext/time'
|
13
|
+
require 'property/base'
|
12
14
|
|
13
15
|
module Property
|
14
|
-
VERSION = '0.
|
16
|
+
VERSION = '1.0.0'
|
15
17
|
|
16
18
|
def self.included(base)
|
17
19
|
base.class_eval do
|
data/lib/property/attribute.rb
CHANGED
@@ -11,18 +11,25 @@ module Property
|
|
11
11
|
# them apart.
|
12
12
|
#
|
13
13
|
module Attribute
|
14
|
-
|
15
14
|
def self.included(base)
|
16
|
-
base.extend ClassMethods
|
17
|
-
|
18
15
|
base.class_eval do
|
19
|
-
include
|
16
|
+
include Base
|
17
|
+
after_validation :dump_properties
|
18
|
+
alias_method_chain :attributes=, :properties
|
19
|
+
end
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
+
# This is just a helper module that includes necessary code for property access, but without
|
23
|
+
# the validation/save hooks.
|
24
|
+
module Base
|
25
|
+
def self.included(base)
|
26
|
+
base.extend ClassMethods
|
22
27
|
|
23
|
-
|
28
|
+
base.class_eval do
|
29
|
+
include InstanceMethods
|
24
30
|
|
25
|
-
|
31
|
+
store_properties_in self
|
32
|
+
end
|
26
33
|
end
|
27
34
|
end
|
28
35
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Property
|
2
|
+
|
3
|
+
# This module is used when we need to access the properties in the properties storage model (to
|
4
|
+
# compare versions for example). Including this module has the same effect as including 'Property'
|
5
|
+
# but without the hooks (validation, save, etc).
|
6
|
+
module Base
|
7
|
+
def self.included(base)
|
8
|
+
base.class_eval do
|
9
|
+
include Attribute::Base
|
10
|
+
include Serialization::JSON
|
11
|
+
include Declaration::Base
|
12
|
+
include Dirty
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/property/column.rb
CHANGED
@@ -12,11 +12,11 @@ module Property
|
|
12
12
|
|
13
13
|
def initialize(name, default, type, options={})
|
14
14
|
name = name.to_s
|
15
|
-
extract_property_options(options)
|
16
15
|
if type.kind_of?(Class)
|
17
16
|
@klass = type
|
18
17
|
end
|
19
18
|
super(name, default, type, options)
|
19
|
+
extract_property_options(options)
|
20
20
|
end
|
21
21
|
|
22
22
|
def validate(value, errors)
|
@@ -48,6 +48,9 @@ module Property
|
|
48
48
|
@klass || super
|
49
49
|
end
|
50
50
|
|
51
|
+
# Property type used instead of 'type' when column is stored
|
52
|
+
alias ptype type
|
53
|
+
|
51
54
|
def type_cast(value)
|
52
55
|
if type == :string
|
53
56
|
value = value.to_s
|
@@ -62,6 +65,15 @@ module Property
|
|
62
65
|
private
|
63
66
|
def extract_property_options(options)
|
64
67
|
@index = options.delete(:index) || options.delete(:indexed)
|
68
|
+
if @index == true
|
69
|
+
@index = ptype
|
70
|
+
end
|
71
|
+
|
72
|
+
if @index.blank?
|
73
|
+
@index = nil
|
74
|
+
elsif @index.kind_of?(Symbol)
|
75
|
+
@index = @index.to_s
|
76
|
+
end
|
65
77
|
end
|
66
78
|
|
67
79
|
def extract_default(default)
|
data/lib/property/declaration.rb
CHANGED
@@ -3,39 +3,50 @@ module Property
|
|
3
3
|
# Property::Declaration module is used to declare property definitions in a Class. The module
|
4
4
|
# also manages property inheritence in sub-classes.
|
5
5
|
module Declaration
|
6
|
-
|
7
6
|
def self.included(base)
|
8
7
|
base.class_eval do
|
9
|
-
|
10
|
-
|
8
|
+
include Base
|
9
|
+
validate :properties_validation, :if => :properties
|
10
|
+
end
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
module Base
|
14
|
+
def self.included(base)
|
15
|
+
base.class_eval do
|
16
|
+
extend ClassMethods
|
17
|
+
include InstanceMethods
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
end
|
19
|
+
class << self
|
20
|
+
attr_accessor :schema
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
schema = Property::Schema.new(self.to_s, self)
|
22
|
-
if superclass.respond_to?(:schema)
|
23
|
-
schema.behave_like superclass
|
24
|
-
end
|
25
|
-
schema
|
22
|
+
def schema
|
23
|
+
@schema ||= make_schema
|
26
24
|
end
|
27
|
-
end
|
28
25
|
|
29
|
-
|
26
|
+
private
|
27
|
+
def make_schema
|
28
|
+
schema = Property::Schema.new(self.to_s, self)
|
29
|
+
if superclass.respond_to?(:schema)
|
30
|
+
schema.has_role superclass
|
31
|
+
end
|
32
|
+
schema
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
33
39
|
module ClassMethods
|
34
40
|
|
35
|
-
# Include a new set of property definitions (
|
41
|
+
# Include a new set of property definitions (Role) into the current class schema.
|
36
42
|
# You can also provide a class to simulate multiple inheritance.
|
37
|
-
def
|
38
|
-
schema.
|
43
|
+
def has_role(role)
|
44
|
+
schema.has_role role
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return true if the current object has all the roles of the given object, class or role.
|
48
|
+
def has_role?(role)
|
49
|
+
schema.has_role? role
|
39
50
|
end
|
40
51
|
|
41
52
|
# Use this class method to declare properties and indices that will be used in your models.
|
@@ -52,21 +63,32 @@ module Property
|
|
52
63
|
# end
|
53
64
|
# end
|
54
65
|
def property(&block)
|
55
|
-
schema.
|
66
|
+
schema.role.property(&block)
|
56
67
|
end
|
57
68
|
end # ClassMethods
|
58
69
|
|
59
70
|
module InstanceMethods
|
60
|
-
# Instance's schema (can be different from the instance's class schema if
|
71
|
+
# Instance's schema (can be different from the instance's class schema if roles have been
|
61
72
|
# added to the instance.
|
62
73
|
def schema
|
63
74
|
@own_schema || self.class.schema
|
64
75
|
end
|
65
76
|
|
66
|
-
# Include a new set of property definitions (
|
77
|
+
# Include a new set of property definitions (Role) into the current instance's schema.
|
67
78
|
# You can also provide a class to simulate multiple inheritance.
|
68
|
-
def
|
69
|
-
own_schema.
|
79
|
+
def has_role(role)
|
80
|
+
own_schema.has_role role
|
81
|
+
end
|
82
|
+
|
83
|
+
# Return the list of active roles. The active roles are all the Roles included
|
84
|
+
# in the current object for which properties have been defined (not blank).
|
85
|
+
def used_roles
|
86
|
+
own_schema.used_roles_in(self)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Return true if the current object has all the roles of the given object, class or role.
|
90
|
+
def has_role?(role)
|
91
|
+
own_schema.has_role? role
|
70
92
|
end
|
71
93
|
|
72
94
|
protected
|
@@ -81,7 +103,7 @@ module Property
|
|
81
103
|
def make_own_schema
|
82
104
|
this = class << self; self; end
|
83
105
|
schema = Property::Schema.new(nil, this)
|
84
|
-
schema.
|
106
|
+
schema.has_role self.class
|
85
107
|
schema
|
86
108
|
end
|
87
109
|
end # InsanceMethods
|
data/lib/property/index.rb
CHANGED
@@ -23,37 +23,120 @@ module Property
|
|
23
23
|
def get_indices(group_name)
|
24
24
|
return {} if new_record?
|
25
25
|
res = {}
|
26
|
-
Property::Db.fetch_attributes(['key', 'value'], index_table_name(group_name), index_reader_sql).each do |row|
|
26
|
+
Property::Db.fetch_attributes(['key', 'value'], index_table_name(group_name), index_reader_sql(group_name)).each do |row|
|
27
27
|
res[row['key']] = row['value']
|
28
28
|
end
|
29
29
|
res
|
30
30
|
end
|
31
31
|
|
32
|
-
def index_reader_sql
|
33
|
-
index_reader.map
|
32
|
+
def index_reader_sql(group_name)
|
33
|
+
index_reader(group_name).map do |k, v|
|
34
|
+
if k == :with
|
35
|
+
v.map do |subk, subv|
|
36
|
+
if subv.kind_of?(Array)
|
37
|
+
"`#{subk}` IN (#{subv.map {|ssubv| connection.quote(ssubv)}.join(',')})"
|
38
|
+
else
|
39
|
+
"`#{subk}` = #{self.class.connection.quote(subv)}"
|
40
|
+
end
|
41
|
+
end.join(' AND ')
|
42
|
+
else
|
43
|
+
"`#{k}` = #{self.class.connection.quote(v)}"
|
44
|
+
end
|
45
|
+
end.join(' AND ')
|
34
46
|
end
|
35
47
|
|
36
|
-
def index_reader
|
48
|
+
def index_reader(group_name)
|
37
49
|
{index_foreign_key => self.id}
|
38
50
|
end
|
39
51
|
|
40
|
-
|
52
|
+
def index_writer(group_name)
|
53
|
+
index_reader(group_name)
|
54
|
+
end
|
41
55
|
|
42
56
|
def index_table_name(group_name)
|
43
57
|
"i_#{group_name}_#{self.class.table_name}"
|
44
58
|
end
|
45
59
|
|
46
60
|
def index_foreign_key
|
47
|
-
self.class.table_name.singularize.foreign_key
|
61
|
+
@index_foreign_key ||=self.class.table_name.singularize.foreign_key
|
62
|
+
end
|
63
|
+
|
64
|
+
# Create a list of index entries
|
65
|
+
def create_indices(group_name, new_keys, cur_indices)
|
66
|
+
# Build insert_many query
|
67
|
+
writer = index_writer(group_name)
|
68
|
+
foreign_keys = index_foreign_keys(writer)
|
69
|
+
|
70
|
+
Property::Db.insert_many(
|
71
|
+
index_table_name(group_name),
|
72
|
+
foreign_keys + %w{key value},
|
73
|
+
map_index_values(new_keys, cur_indices, foreign_keys, writer)
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
def index_foreign_keys(writer)
|
78
|
+
if with = writer[:with]
|
79
|
+
writer.keys - [:with] + with.keys
|
80
|
+
else
|
81
|
+
writer.keys
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def map_index_values(new_keys, cur_indices, index_foreign_keys, index_writer)
|
86
|
+
if with = index_writer[:with]
|
87
|
+
foreign_values = explode_list(index_foreign_keys.map {|k| index_writer[k] || with[k]})
|
88
|
+
else
|
89
|
+
foreign_values = [index_foreign_keys.map {|k| index_writer[k]}]
|
90
|
+
end
|
91
|
+
|
92
|
+
values = new_keys.map do |key|
|
93
|
+
[connection.quote(key), connection.quote(cur_indices[key])]
|
94
|
+
end
|
95
|
+
|
96
|
+
res = []
|
97
|
+
foreign_values.each do |list|
|
98
|
+
list = list.map {|k| connection.quote(k)}
|
99
|
+
values.each do |value|
|
100
|
+
res << (list + value)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
res
|
104
|
+
end
|
105
|
+
|
106
|
+
# Takes a mixed array and explodes it
|
107
|
+
# [x, ['en','fr'], y, [a,b]] ==> [[x,'en',y,a], [x,'en',y',b], [x,'fr',y,a], [x,'fr',y,b]]
|
108
|
+
def explode_list(list)
|
109
|
+
res = [[]]
|
110
|
+
list.each do |key|
|
111
|
+
if key.kind_of?(Array)
|
112
|
+
res_bak = res
|
113
|
+
res = []
|
114
|
+
key.each do |k|
|
115
|
+
res_bak.each do |list|
|
116
|
+
res << (list + [k])
|
117
|
+
end
|
118
|
+
end
|
119
|
+
else
|
120
|
+
res.each do |list|
|
121
|
+
list << key
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
res
|
126
|
+
end
|
127
|
+
|
128
|
+
# Update an index entry
|
129
|
+
def update_index(group_name, key, value)
|
130
|
+
self.class.connection.execute "UPDATE #{index_table_name(group_name)} SET `value` = #{connection.quote(value)} WHERE #{index_reader_sql(group_name)} AND `key` = #{connection.quote(key)}"
|
131
|
+
end
|
132
|
+
|
133
|
+
# Delete a list of indices (value became blank).
|
134
|
+
def delete_indices(group_name, keys)
|
135
|
+
self.class.connection.execute "DELETE FROM #{index_table_name(group_name)} WHERE #{index_reader_sql(group_name)} AND `key` IN (#{keys.map{|key| connection.quote(key)}.join(',')})"
|
48
136
|
end
|
49
137
|
|
50
138
|
# This method prepares the index
|
51
139
|
def property_index
|
52
|
-
connection = self.class.connection
|
53
|
-
reader_sql = index_reader_sql
|
54
|
-
foreign_keys = nil
|
55
|
-
foreign_values = nil
|
56
|
-
|
57
140
|
schema.index_groups.each do |group_name, definitions|
|
58
141
|
cur_indices = {}
|
59
142
|
definitions.each do |key, proc|
|
@@ -61,12 +144,16 @@ module Property
|
|
61
144
|
value = prop[key]
|
62
145
|
if !value.blank?
|
63
146
|
if proc
|
147
|
+
# Get value(s) to index through proc
|
64
148
|
cur_indices.merge!(proc.call(self))
|
65
149
|
else
|
150
|
+
# Set current value from prop
|
66
151
|
cur_indices[key] = value
|
67
152
|
end
|
68
153
|
end
|
69
154
|
else
|
155
|
+
# No key: group index generated with
|
156
|
+
# p.index(group_name) do |record| ...
|
70
157
|
cur_indices.merge!(proc.call(self))
|
71
158
|
end
|
72
159
|
end
|
@@ -74,7 +161,7 @@ module Property
|
|
74
161
|
if group_name.kind_of?(Class)
|
75
162
|
# Use a custom indexer
|
76
163
|
group_name.set_property_index(self, cur_indices)
|
77
|
-
|
164
|
+
elsif index_reader(group_name)
|
78
165
|
# Add key/value pairs to the default tables
|
79
166
|
old_indices = get_indices(group_name)
|
80
167
|
|
@@ -85,34 +172,22 @@ module Property
|
|
85
172
|
del_keys = old_keys - cur_keys
|
86
173
|
upd_keys = cur_keys & old_keys
|
87
174
|
|
88
|
-
table_name = index_table_name(group_name)
|
89
|
-
|
90
175
|
upd_keys.each do |key|
|
91
176
|
value = cur_indices[key]
|
92
177
|
if value.blank?
|
93
178
|
del_keys << key
|
94
|
-
|
95
|
-
|
179
|
+
elsif value != old_indices[key]
|
180
|
+
update_index(group_name, key, value)
|
96
181
|
end
|
97
182
|
end
|
98
183
|
|
99
184
|
if !del_keys.empty?
|
100
|
-
|
185
|
+
delete_indices(group_name, del_keys)
|
101
186
|
end
|
102
187
|
|
103
188
|
new_keys.reject! {|k| cur_indices[k].blank? }
|
104
189
|
if !new_keys.empty?
|
105
|
-
|
106
|
-
foreign_keys ||= index_writer.keys
|
107
|
-
foreign_values ||= foreign_keys.map {|k| index_writer[k]}
|
108
|
-
|
109
|
-
Property::Db.insert_many(
|
110
|
-
table_name,
|
111
|
-
foreign_keys + ['key', 'value'],
|
112
|
-
new_keys.map do |key|
|
113
|
-
foreign_values + [connection.quote(key), connection.quote(cur_indices[key])]
|
114
|
-
end
|
115
|
-
)
|
190
|
+
create_indices(group_name, new_keys, cur_indices)
|
116
191
|
end
|
117
192
|
end
|
118
193
|
end
|
@@ -127,7 +202,7 @@ module Property
|
|
127
202
|
if group_name.kind_of?(Class)
|
128
203
|
group_name.delete_property_index(self)
|
129
204
|
else
|
130
|
-
connection.execute "DELETE FROM #{index_table_name(group_name)} WHERE
|
205
|
+
connection.execute "DELETE FROM #{index_table_name(group_name)} WHERE `#{foreign_key}` = #{current_id}"
|
131
206
|
end
|
132
207
|
end
|
133
208
|
end
|