ooor 2.0.4 → 2.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ooor.rb +7 -2
- data/lib/ooor/associations.rb +37 -13
- data/lib/ooor/autosave_association.rb +197 -0
- data/lib/ooor/base.rb +21 -28
- data/lib/ooor/errors.rb +1 -1
- data/lib/ooor/field_methods.rb +37 -27
- data/lib/ooor/mini_active_resource.rb +16 -22
- data/lib/ooor/model_registry.rb +6 -1
- data/lib/ooor/model_schema.rb +25 -0
- data/lib/ooor/naming.rb +27 -13
- data/lib/ooor/nested_attributes.rb +57 -0
- data/lib/ooor/persistence.rb +247 -49
- data/lib/ooor/reflection.rb +9 -7
- data/lib/ooor/reflection_ooor.rb +17 -17
- data/lib/ooor/relation.rb +0 -1
- data/lib/ooor/relation/finder_methods.rb +4 -4
- data/lib/ooor/report.rb +9 -9
- data/lib/ooor/services.rb +1 -1
- data/lib/ooor/session.rb +72 -22
- data/lib/ooor/session_handler.rb +17 -21
- data/lib/ooor/type_casting.rb +34 -37
- data/lib/ooor/version.rb +1 -1
- data/spec/ooor_spec.rb +192 -43
- metadata +7 -9
- data/lib/ooor/connection.rb +0 -37
- data/spec/install_nightly.sh +0 -17
- data/spec/requirements.txt +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68bb22d821a0337958de6835edebec32672e31d5
|
4
|
+
data.tar.gz: e515ccba848078b48a39b2ab22dae262dd717bda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 070ab8305192ceaa8c77c959c656c89bdd06f2250e3818a2ed088f5a6920bfda147420d583e748d5ceb2ddfec0dbe7f826ea37bf068bc92cbc2a8784028fd294
|
7
|
+
data.tar.gz: fdf089b8708e2e6912945976f3d85bf328af15e62bbe8e48e08553ddc0bd8887c2ca06b788ee389831424df8a70fec0a17ec5919e1feee3bfd6fe4fef73ea39a
|
data/lib/ooor.rb
CHANGED
@@ -12,7 +12,10 @@ require 'logger'
|
|
12
12
|
module Ooor
|
13
13
|
extend ActiveSupport::Autoload
|
14
14
|
autoload :Base
|
15
|
+
autoload :ModelSchema
|
15
16
|
autoload :Persistence
|
17
|
+
autoload :AutosaveAssociation
|
18
|
+
autoload :NestedAttributes
|
16
19
|
autoload :Callbacks
|
17
20
|
autoload :Cache, 'active_support/cache'
|
18
21
|
autoload :Serialization
|
@@ -96,8 +99,10 @@ module Ooor
|
|
96
99
|
end
|
97
100
|
|
98
101
|
|
99
|
-
def with_ooor_session(config={}, id
|
100
|
-
|
102
|
+
def with_ooor_session(config={}, id=:noweb)
|
103
|
+
session = Ooor.session_handler.retrieve_session(config, id)
|
104
|
+
Ooor.session_handler.register_session(session)
|
105
|
+
yield session
|
101
106
|
end
|
102
107
|
|
103
108
|
def with_ooor_default_session(config={})
|
data/lib/ooor/associations.rb
CHANGED
@@ -26,25 +26,49 @@ module Ooor
|
|
26
26
|
|
27
27
|
# fakes associations like much like ActiveRecord according to the cached OpenERP data model
|
28
28
|
def relationnal_result(method_name, *arguments)
|
29
|
-
self.class.reload_fields_definition(false
|
29
|
+
self.class.reload_fields_definition(false)
|
30
30
|
if self.class.many2one_associations.has_key?(method_name)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
load_m2o_association(method_name, *arguments)
|
32
|
+
elsif self.class.polymorphic_m2o_associations.has_key?(method_name)# && @associations[method_name]
|
33
|
+
load_polymorphic_m2o_association(method_name, *arguments)
|
34
|
+
# values = @associations[method_name].split(',')
|
35
|
+
# self.class.const_get(values[0]).find(values[1], arguments.extract_options!)
|
36
|
+
else # o2m or m2m
|
37
|
+
load_x2m_association(method_name, *arguments)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def load_polymorphic_m2o_association(method_name, *arguments)
|
44
|
+
if @associations[method_name]
|
39
45
|
values = @associations[method_name].split(',')
|
40
46
|
self.class.const_get(values[0]).find(values[1], arguments.extract_options!)
|
41
|
-
else
|
42
|
-
|
43
|
-
|
47
|
+
else
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def load_m2o_association(method_name, *arguments)
|
53
|
+
if !@associations[method_name]
|
54
|
+
nil
|
55
|
+
else
|
56
|
+
if @associations[method_name].is_a?(Integer)
|
57
|
+
id = @associations[method_name]
|
58
|
+
display_name = nil
|
59
|
+
else
|
60
|
+
id = @associations[method_name][0]
|
61
|
+
display_name = @associations[method_name][1]
|
62
|
+
end
|
63
|
+
rel = self.class.many2one_associations[method_name]['relation']
|
64
|
+
self.class.const_get(rel).new({id: id, _display_name: display_name}, [], true, false, true)
|
65
|
+
# self.class.const_get(rel).find(id, arguments.extract_options!)
|
44
66
|
end
|
45
67
|
end
|
46
68
|
|
47
|
-
def load_x2m_association(
|
69
|
+
def load_x2m_association(method_name, *arguments)
|
70
|
+
model_key = self.class.all_fields[method_name]['relation']
|
71
|
+
ids = @associations[method_name] || []
|
48
72
|
options = arguments.extract_options!
|
49
73
|
related_class = self.class.const_get(model_key)
|
50
74
|
CollectionProxy.new(related_class, {}).apply_finder_options(options.merge(ids: ids))
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'active_support/concern'
|
3
|
+
|
4
|
+
module Ooor
|
5
|
+
# = Ooor Autosave Association, adapted from ActiveRecord 4.1
|
6
|
+
#
|
7
|
+
# +AutosaveAssociation+ is a module that takes care of automatically saving
|
8
|
+
# associated records when their parent is saved. In addition to saving, it
|
9
|
+
# also destroys any associated records that were marked for destruction.
|
10
|
+
# (See +mark_for_destruction+ and <tt>marked_for_destruction?</tt>).
|
11
|
+
#
|
12
|
+
# Saving of the parent, its associations, and the destruction of marked
|
13
|
+
# associations, all happen inside a transaction. This should never leave the
|
14
|
+
# database in an inconsistent state.
|
15
|
+
#
|
16
|
+
# If validations for any of the associations fail, their error messages will
|
17
|
+
# be applied to the parent (TODO)
|
18
|
+
module AutosaveAssociation
|
19
|
+
extend ActiveSupport::Concern
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
private
|
23
|
+
|
24
|
+
# same as ActiveRecord
|
25
|
+
def define_non_cyclic_method(name, &block)
|
26
|
+
define_method(name) do |*args|
|
27
|
+
result = true; @_already_called ||= {}
|
28
|
+
# Loop prevention for validation of associations
|
29
|
+
unless @_already_called[name]
|
30
|
+
begin
|
31
|
+
@_already_called[name]=true
|
32
|
+
result = instance_eval(&block)
|
33
|
+
ensure
|
34
|
+
@_already_called[name]=false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
result
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Adds validation and save callbacks for the association as specified by
|
43
|
+
# the +reflection+.
|
44
|
+
#
|
45
|
+
# For performance reasons, we don't check whether to validate at runtime.
|
46
|
+
# However the validation and callback methods are lazy and those methods
|
47
|
+
# get created when they are invoked for the very first time. However,
|
48
|
+
# this can change, for instance, when using nested attributes, which is
|
49
|
+
# called _after_ the association has been defined. Since we don't want
|
50
|
+
# the callbacks to get defined multiple times, there are guards that
|
51
|
+
# check if the save or validation methods have already been defined
|
52
|
+
# before actually defining them.
|
53
|
+
def add_autosave_association_callbacks(reflection) # TODO add support for m2o
|
54
|
+
save_method = :"autosave_associated_records_for_#{reflection.name}"
|
55
|
+
validation_method = :"validate_associated_records_for_#{reflection.name}"
|
56
|
+
collection = true #reflection.collection?
|
57
|
+
unless method_defined?(save_method)
|
58
|
+
if collection
|
59
|
+
before_save :before_save_collection_association
|
60
|
+
define_non_cyclic_method(save_method) { save_collection_association(reflection) }
|
61
|
+
before_save save_method
|
62
|
+
# NOTE Ooor is different from ActiveRecord here: we run the nested callbacks before saving
|
63
|
+
# the whole hash of values including the nested records
|
64
|
+
# Doesn't use after_save as that would save associations added in after_create/after_update twice
|
65
|
+
# after_create save_method
|
66
|
+
# after_update save_method
|
67
|
+
else
|
68
|
+
raise raise ArgumentError, "Not implemented in Ooor; seems OpenERP won't support such nested attribute in the same transaction anyhow"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
if reflection.validate? && !method_defined?(validation_method)
|
73
|
+
method = (collection ? :validate_collection_association : :validate_single_association)
|
74
|
+
define_non_cyclic_method(validation_method) { send(method, reflection) }
|
75
|
+
validate validation_method
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Reloads the attributes of the object as usual and clears <tt>marked_for_destruction</tt> flag.
|
81
|
+
def reload(options = nil)
|
82
|
+
@marked_for_destruction = false
|
83
|
+
@destroyed_by_association = nil
|
84
|
+
super
|
85
|
+
end
|
86
|
+
|
87
|
+
# Marks this record to be destroyed as part of the parents save transaction.
|
88
|
+
# This does _not_ actually destroy the record instantly, rather child record will be destroyed
|
89
|
+
# when <tt>parent.save</tt> is called.
|
90
|
+
#
|
91
|
+
# Only useful if the <tt>:autosave</tt> option on the parent is enabled for this associated model.
|
92
|
+
def mark_for_destruction
|
93
|
+
@marked_for_destruction = true
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns whether or not this record will be destroyed as part of the parents save transaction.
|
97
|
+
#
|
98
|
+
# Only useful if the <tt>:autosave</tt> option on the parent is enabled for this associated model.
|
99
|
+
def marked_for_destruction?
|
100
|
+
@marked_for_destruction
|
101
|
+
end
|
102
|
+
|
103
|
+
# Records the association that is being destroyed and destroying this
|
104
|
+
# record in the process.
|
105
|
+
def destroyed_by_association=(reflection)
|
106
|
+
@destroyed_by_association = reflection
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns the association for the parent being destroyed.
|
110
|
+
#
|
111
|
+
# Used to avoid updating the counter cache unnecessarily.
|
112
|
+
def destroyed_by_association
|
113
|
+
@destroyed_by_association
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns whether or not this record has been changed in any way (including whether
|
117
|
+
# any of its nested autosave associations are likewise changed)
|
118
|
+
def changed_for_autosave?
|
119
|
+
new_record? || changed? || marked_for_destruction? # TODO || nested_records_changed_for_autosave?
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
# Returns the record for an association collection that should be validated
|
125
|
+
# or saved. If +autosave+ is +false+ only new records will be returned,
|
126
|
+
# unless the parent is/was a new record itself.
|
127
|
+
def associated_records_to_validate_or_save(association, new_record, autosave)
|
128
|
+
if new_record
|
129
|
+
association && association.target
|
130
|
+
elsif autosave
|
131
|
+
association.target.find_all { |record| record.changed_for_autosave? }
|
132
|
+
else
|
133
|
+
association.target.find_all { |record| record.new_record? }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# go through nested autosave associations that are loaded in memory (without loading
|
138
|
+
# any new ones), and return true if is changed for autosave
|
139
|
+
# def nested_records_changed_for_autosave?
|
140
|
+
# self.class.reflect_on_all_autosave_associations.any? do |reflection|
|
141
|
+
# association = association_instance_get(reflection.name)
|
142
|
+
# association && Array.wrap(association.target).any? { |a| a.changed_for_autosave? }
|
143
|
+
# end
|
144
|
+
# end
|
145
|
+
|
146
|
+
# Is used as a before_save callback to check while saving a collection
|
147
|
+
# association whether or not the parent was a new record before saving.
|
148
|
+
def before_save_collection_association
|
149
|
+
@new_record_before_save = new_record?
|
150
|
+
true
|
151
|
+
end
|
152
|
+
|
153
|
+
# Saves any new associated records, or all loaded autosave associations if
|
154
|
+
# <tt>:autosave</tt> is enabled on the association.
|
155
|
+
#
|
156
|
+
# In addition, it destroys all children that were marked for destruction
|
157
|
+
# with mark_for_destruction.
|
158
|
+
#
|
159
|
+
# This all happens inside a transaction, _if_ the Transactions module is included into
|
160
|
+
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
|
161
|
+
def save_collection_association(reflection)
|
162
|
+
# if association = association_instance_get(reflection.name)
|
163
|
+
if target = @loaded_associations[reflection.name] #TODO use a real Association wrapper
|
164
|
+
association = OpenStruct.new(target: target)
|
165
|
+
autosave = reflection.options[:autosave]
|
166
|
+
|
167
|
+
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
|
168
|
+
# NOTE saving the object with its nested associations will properly destroy records in OpenERP
|
169
|
+
# no need to do it now like in ActiveRecord
|
170
|
+
records.each do |record|
|
171
|
+
next if record.destroyed?
|
172
|
+
|
173
|
+
saved = true
|
174
|
+
|
175
|
+
if autosave != false && (@new_record_before_save || record.new_record?)
|
176
|
+
if autosave
|
177
|
+
# saved = association.insert_record(record, false)
|
178
|
+
record.run_callbacks(:save) { false }
|
179
|
+
record.run_callbacks(:create) { false }
|
180
|
+
# else
|
181
|
+
# association.insert_record(record) unless reflection.nested?
|
182
|
+
end
|
183
|
+
elsif autosave
|
184
|
+
record.run_callbacks(:save) {false}
|
185
|
+
record.run_callbacks(:update) {false}
|
186
|
+
# saved = record.save(:validate => false)
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
191
|
+
# reconstruct the scope now that we know the owner's id
|
192
|
+
# association.reset_scope if association.respond_to?(:reset_scope)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
end
|
data/lib/ooor/base.rb
CHANGED
@@ -12,36 +12,19 @@ require 'ooor/errors'
|
|
12
12
|
|
13
13
|
module Ooor
|
14
14
|
|
15
|
-
# meta data shared across sessions, a cache of the data in ir_model in OpenERP.
|
16
|
-
# reused accross workers in a multi-process web app (via memcache for instance).
|
17
|
-
class ModelTemplate
|
18
|
-
|
19
|
-
TEMPLATE_PROPERTIES = [:name, :openerp_id, :info, :access_ids, :description,
|
20
|
-
:openerp_model, :field_ids, :state, :fields,
|
21
|
-
:many2one_associations, :one2many_associations, :many2many_associations,
|
22
|
-
:polymorphic_m2o_associations, :associations_keys,
|
23
|
-
:associations, :columns]
|
24
|
-
|
25
|
-
attr_accessor *TEMPLATE_PROPERTIES, :columns_hash
|
26
|
-
end
|
27
|
-
|
28
15
|
# the base class for proxies to OpenERP objects
|
29
16
|
class Base < Ooor::MiniActiveResource
|
30
17
|
include Naming, TypeCasting, Serialization, ReflectionOoor, Reflection
|
31
|
-
include Associations, Report, FinderMethods, FieldMethods
|
18
|
+
include Associations, Report, FinderMethods, FieldMethods, AutosaveAssociation, NestedAttributes
|
32
19
|
|
33
20
|
# ********************** class methods ************************************
|
34
21
|
class << self
|
35
22
|
|
36
|
-
attr_accessor
|
37
|
-
delegate *
|
23
|
+
attr_accessor :name, :session, :t, :scope_prefix
|
24
|
+
delegate *ModelSchema::TEMPLATE_PROPERTIES, to: :t
|
38
25
|
|
39
26
|
# ******************** remote communication *****************************
|
40
27
|
|
41
|
-
def create(attributes = {}, context={}, default_get_list=false, reload=true)
|
42
|
-
self.new(attributes, default_get_list, context).tap { |resource| resource.save(context, reload) }
|
43
|
-
end
|
44
|
-
|
45
28
|
#OpenERP search method
|
46
29
|
def search(domain=[], offset=0, limit=false, order=false, context={}, count=false)
|
47
30
|
rpc_execute(:search, to_openerp_domain(domain), offset, limit, order, context, count)
|
@@ -60,8 +43,12 @@ module Ooor
|
|
60
43
|
end
|
61
44
|
|
62
45
|
def object_service(service, obj, method, *args)
|
63
|
-
reload_fields_definition(false
|
64
|
-
cast_answer_to_ruby!(
|
46
|
+
reload_fields_definition(false)
|
47
|
+
cast_answer_to_ruby!(session.object.object_service(service, obj, method, *cast_request_to_openerp(args)))
|
48
|
+
end
|
49
|
+
|
50
|
+
def context
|
51
|
+
session.session_context
|
65
52
|
end
|
66
53
|
|
67
54
|
def method_missing(method_symbol, *args)
|
@@ -71,8 +58,6 @@ module Ooor
|
|
71
58
|
|
72
59
|
# ******************** AREL Minimal implementation ***********************
|
73
60
|
|
74
|
-
def relation(context={}); @relation ||= Relation.new(self, context); end #TODO template
|
75
|
-
def scoped(context={}); relation(context); end
|
76
61
|
def where(opts, *rest); relation.where(opts, *rest); end
|
77
62
|
def all(*args); relation.all(*args); end
|
78
63
|
def limit(value); relation.limit(value); end
|
@@ -83,18 +68,22 @@ module Ooor
|
|
83
68
|
|
84
69
|
def logger; Ooor.logger; end
|
85
70
|
|
71
|
+
private
|
72
|
+
|
73
|
+
def relation; @relation ||= Relation.new(self); end
|
74
|
+
|
86
75
|
end
|
87
76
|
|
88
77
|
self.name = "Base"
|
89
78
|
|
90
79
|
# ********************** instance methods **********************************
|
91
80
|
|
92
|
-
attr_accessor :associations, :loaded_associations, :ir_model_data_id
|
81
|
+
attr_accessor :associations, :loaded_associations, :ir_model_data_id
|
93
82
|
|
94
83
|
include Persistence, Callbacks, ActiveModel::Dirty
|
95
84
|
|
96
85
|
def rpc_execute(method, *args)
|
97
|
-
args += [self.class.
|
86
|
+
args += [self.class.context] unless args[-1].is_a? Hash
|
98
87
|
self.class.object_service(:execute, self.class.openerp_model, method, *args)
|
99
88
|
end
|
100
89
|
|
@@ -111,8 +100,8 @@ module Ooor
|
|
111
100
|
|
112
101
|
#wrapper for OpenERP exec_workflow Business Process Management engine
|
113
102
|
def wkf_action(action, context={}, reload=true)
|
114
|
-
self.class.object_service(:exec_workflow, self.class.openerp_model, action, self.id,
|
115
|
-
reload_fields
|
103
|
+
self.class.object_service(:exec_workflow, self.class.openerp_model, action, self.id, context)
|
104
|
+
reload_fields if reload
|
116
105
|
end
|
117
106
|
|
118
107
|
#Add get_report_data to obtain [report["result"],report["format]] of a concrete openERP Object
|
@@ -124,6 +113,10 @@ module Ooor
|
|
124
113
|
|
125
114
|
private
|
126
115
|
|
116
|
+
def context
|
117
|
+
self.class.context
|
118
|
+
end
|
119
|
+
|
127
120
|
# Ruby 1.9.compat, See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary/
|
128
121
|
def to_ary; nil; end # :nodoc:
|
129
122
|
|
data/lib/ooor/errors.rb
CHANGED
@@ -25,7 +25,7 @@ module Ooor
|
|
25
25
|
return ValueError.new(method, faultCode, faultString, *args)
|
26
26
|
elsif faultCode =~ /ValidateError/
|
27
27
|
return ValidationError.new(method, faultCode, faultString, *args)
|
28
|
-
elsif faultCode =~ /AccessDenied/
|
28
|
+
elsif faultCode =~ /AccessDenied/ || faultCode =~ /Access Denied/
|
29
29
|
return UnAuthorizedError.new(method, faultCode, faultString, *args)
|
30
30
|
elsif faultCode =~ /AuthenticationError: Credentials not provided/
|
31
31
|
return InvalidSessionError.new(method, faultCode, faultString, *args)
|
data/lib/ooor/field_methods.rb
CHANGED
@@ -6,7 +6,7 @@ module Ooor
|
|
6
6
|
|
7
7
|
module ClassMethods
|
8
8
|
|
9
|
-
def reload_fields_definition(force=false
|
9
|
+
def reload_fields_definition(force=false)
|
10
10
|
if force || !fields
|
11
11
|
@t.fields = {}
|
12
12
|
@columns_hash = {}
|
@@ -14,7 +14,7 @@ module Ooor
|
|
14
14
|
fields_get.each { |k, field| reload_field_definition(k, field) }
|
15
15
|
@t.associations_keys = many2one_associations.keys + one2many_associations.keys + many2many_associations.keys + polymorphic_m2o_associations.keys
|
16
16
|
logger.debug "#{fields.size} fields loaded in model #{self.name}"
|
17
|
-
Ooor.model_registry.set_template(
|
17
|
+
Ooor.model_registry.set_template(session.config, @t)
|
18
18
|
end
|
19
19
|
generate_accessors if fields != {} && (force || !@accessor_defined) #TODOmove in define_accessors method
|
20
20
|
end
|
@@ -30,44 +30,28 @@ module Ooor
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
# this is used by fields_for in ActionView FormHelper
|
34
|
-
def define_nested_attributes_method(meth)
|
35
|
-
unless self.respond_to?(meth)
|
36
|
-
self.instance_eval do
|
37
|
-
define_method "#{meth}_attributes=" do |*args|
|
38
|
-
send("#{meth}_will_change!")
|
39
|
-
@associations[meth] = args[0]
|
40
|
-
@loaded_associations[meth] = args[0]
|
41
|
-
end
|
42
|
-
define_method "#{meth}_attributes" do |*args|
|
43
|
-
@loaded_associations[meth]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
33
|
private
|
50
34
|
|
51
35
|
def generate_accessors #TODO we should cache this is a module cached like the template, or eventually generate source code or both
|
52
36
|
fields.keys.each { |meth| define_field_method meth }
|
53
37
|
associations_keys.each { |meth| define_association_method meth }
|
54
|
-
one2many_associations.keys.each { |meth|
|
38
|
+
one2many_associations.keys.each { |meth| accepts_nested_attributes_for meth } #TODO do it for m2o too
|
55
39
|
many2one_associations.keys.each do |meth|
|
56
40
|
define_association_method meth
|
57
41
|
define_m2o_association_method meth
|
58
42
|
end
|
59
43
|
(one2many_associations.keys + many2many_associations.keys).each do |meth|
|
60
44
|
define_association_method meth
|
61
|
-
alias_method "#{meth}_ids", meth
|
62
45
|
alias_method "#{meth}_ids=", "#{meth}="
|
63
|
-
alias_method "#{meth.to_s.singularize}_ids", meth
|
64
46
|
alias_method "#{meth.to_s.singularize}_ids=", "#{meth}="
|
47
|
+
define_x2m_ids_association_method meth
|
48
|
+
alias_method "#{meth.to_s.singularize}_ids", "#{meth}_ids"
|
65
49
|
end
|
66
50
|
@accessor_defined = true
|
67
51
|
end
|
68
52
|
|
69
53
|
def define_field_method(meth)
|
70
|
-
|
54
|
+
define_attribute_method meth
|
71
55
|
define_method meth do |*args|
|
72
56
|
get_attribute(meth, *args)
|
73
57
|
end
|
@@ -78,7 +62,7 @@ module Ooor
|
|
78
62
|
end
|
79
63
|
|
80
64
|
def define_association_method(meth)
|
81
|
-
|
65
|
+
define_attribute_method meth
|
82
66
|
define_method meth do |*args|
|
83
67
|
get_association(meth, *args)
|
84
68
|
end
|
@@ -88,6 +72,12 @@ module Ooor
|
|
88
72
|
end
|
89
73
|
end
|
90
74
|
|
75
|
+
def define_x2m_ids_association_method(meth)
|
76
|
+
define_method "#{meth}_ids" do |*args|
|
77
|
+
@associations[meth]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
91
81
|
def define_m2o_association_method(meth)
|
92
82
|
define_method "#{meth}_id" do |*args|
|
93
83
|
if @associations[meth].is_a? Array
|
@@ -116,12 +106,31 @@ module Ooor
|
|
116
106
|
|
117
107
|
end
|
118
108
|
|
109
|
+
attr_accessor :_display_name
|
110
|
+
alias _name _display_name
|
111
|
+
|
112
|
+
def _destroy=(dummy)
|
113
|
+
@marked_for_destruction = true unless dummy.blank? || ["false", "0", 0].index(dummy)
|
114
|
+
end
|
115
|
+
|
116
|
+
def _destroy
|
117
|
+
@marked_for_destruction
|
118
|
+
end
|
119
|
+
|
120
|
+
def lazy_load(meth, *args)
|
121
|
+
@lazy = false
|
122
|
+
load(rpc_execute('read', [id], (self.class.fast_fields + [meth]).uniq, *args || context)[0]).tap do
|
123
|
+
@lazy = false
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
119
127
|
def get_attribute(meth, *args)
|
128
|
+
lazy_load(meth, *args) if @lazy
|
120
129
|
if @attributes.has_key?(meth)
|
121
130
|
@attributes[meth]
|
122
131
|
else #lazy loading
|
123
132
|
if @attributes["id"]
|
124
|
-
@attributes[meth] = rpc_execute('read', [@attributes["id"]], [meth], *args ||
|
133
|
+
@attributes[meth] = rpc_execute('read', [@attributes["id"]], [meth], *args || context)[0][meth]
|
125
134
|
else
|
126
135
|
nil
|
127
136
|
end
|
@@ -137,16 +146,17 @@ module Ooor
|
|
137
146
|
|
138
147
|
def get_association(meth, *args)
|
139
148
|
return @associations[meth] || :undef if @skip
|
149
|
+
lazy_load(meth, *args) if @lazy
|
140
150
|
if @loaded_associations.has_key?(meth)
|
141
151
|
@loaded_associations[meth]
|
142
152
|
elsif @associations.has_key?(meth)
|
143
153
|
@loaded_associations[meth] = relationnal_result(meth, *args)
|
144
154
|
else
|
145
155
|
if @attributes["id"]
|
146
|
-
@associations[meth] = rpc_execute('read', [@attributes["id"]], [meth], *args ||
|
156
|
+
@associations[meth] = rpc_execute('read', [@attributes["id"]], [meth], *args || context)[0][meth]
|
147
157
|
@loaded_associations[meth] = relationnal_result(meth, *args)
|
148
158
|
elsif self.class.one2many_associations.has_key?(meth) || self.class.many2many_associations.has_key?(meth)
|
149
|
-
load_x2m_association(
|
159
|
+
load_x2m_association(meth, [], *args)
|
150
160
|
else
|
151
161
|
nil
|
152
162
|
end
|
@@ -185,7 +195,7 @@ module Ooor
|
|
185
195
|
# end
|
186
196
|
|
187
197
|
def method_missing(method_symbol, *arguments)
|
188
|
-
self.class.reload_fields_definition(false
|
198
|
+
self.class.reload_fields_definition(false)
|
189
199
|
if id
|
190
200
|
rpc_execute(method_symbol, [id], *arguments) #we assume that's an action
|
191
201
|
else
|