property 0.9.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|