ooor 2.0.4 → 2.0.5

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.
@@ -3,26 +3,19 @@ require 'active_support/core_ext/class/attribute_accessors'
3
3
  require 'active_model'
4
4
 
5
5
  module Ooor
6
+ # Ooor::MiniActiveResource is a shrinked version of ActiveResource::Base with the bare minimum we need for Ooor.
7
+ # as a reminder ActiveResource::Base is the main class for mapping RESTful resources as models in a Rails application.
8
+ # Ooor is a bit like ActiveResource but eventually it can use more OpenERP metadata and a richer API
9
+ # to become closer to ActiveRecord or Mongoid than Activeresource. Also OpenERP isn't really good at REST
10
+ # so the part of ActiveResource dedicated to REST is of little help here.
11
+ # An other fundamental difference is Ooor is multi OpenERP instances and multi-sessions.
12
+ # for each session, proxies to OpenERP may be different.
6
13
  class MiniActiveResource
7
14
 
8
15
  class << self
9
16
  def element_name
10
17
  @element_name ||= model_name.element
11
18
  end
12
-
13
- private
14
- # split an option hash into two hashes, one containing the prefix options,
15
- # and the other containing the leftovers.
16
- def split_options(options = {})
17
- prefix_options, query_options = {}, {}
18
-
19
- (options || {}).each do |key, value|
20
- next if key.blank? || !key.respond_to?(:to_sym)
21
- query_options[key.to_sym] = value
22
- end
23
-
24
- [ prefix_options, query_options ]
25
- end
26
19
  end
27
20
 
28
21
  attr_accessor :attributes, :id
@@ -35,6 +28,7 @@ module Ooor
35
28
  super({ :root => self.class.element_name }.merge(options))
36
29
  end
37
30
 
31
+ # Returns +true+ if this object hasn't yet been saved, otherwise, returns +false+.
38
32
  def new?
39
33
  !@persisted
40
34
  end
@@ -50,11 +44,16 @@ module Ooor
50
44
 
51
45
  # Sets the <tt>\id</tt> attribute of the resource.
52
46
  def id=(id)
53
- attributes["id"] = id
47
+ attributes["id"] = id.to_i # NOTE added to_i for Ooor (HTML forms can pass it as a string)
54
48
  end
55
49
 
56
- def reload
57
- self.class.find(id)
50
+ # Reloads the record from the database.
51
+ #
52
+ # This method finds record by its primary key (which could be assigned manually) and
53
+ # modifies the receiver in-place
54
+ # NOTE in Ooor, like ActiveRecord and unlike ActiveResource, reload can take an options parameter
55
+ def reload(options = nil)
56
+ self.class.find(id, options)
58
57
  end
59
58
 
60
59
  # Returns the Errors object that holds all information about attribute error messages.
@@ -62,11 +61,6 @@ module Ooor
62
61
  @errors ||= ActiveModel::Errors.new(self)
63
62
  end
64
63
 
65
- private
66
-
67
- def split_options(options = {})
68
- self.class.__send__(:split_options, options)
69
- end
70
64
 
71
65
  include ActiveModel::Conversion
72
66
  include ActiveModel::Serializers::JSON
@@ -1,8 +1,13 @@
1
1
  module Ooor
2
+ # Enables to cache expensive model metadata and reuse these metadata
3
+ # according to connection parameters. Indeed, these metadata are
4
+ # expensive before they require a fields_get request to OpenERP
5
+ # so in a web application with several worker processes, it's a good
6
+ # idea to cache them and share them using a data store like Memcache
2
7
  class ModelRegistry
3
8
 
4
9
  def cache_key(config, model_name)
5
- h = config.slice(:url, :database, :username, :scope_prefix) #sure we want username?
10
+ h = {url: config[:url], database: config[:database], username: config[:username], scope_prefix: config[:scope_prefix]}
6
11
  (h.map{|k, v| v} + [model_name]).join('-')
7
12
  end
8
13
 
@@ -0,0 +1,25 @@
1
+ # OOOR: OpenObject On Ruby
2
+ # Copyright (C) 2009-2014 Akretion LTDA (<http://www.akretion.com>).
3
+ # Author: Raphaël Valyi
4
+ # Licensed under the MIT license, see MIT-LICENSE file
5
+
6
+ module Ooor
7
+
8
+ # Meta data shared across sessions, a cache of the data in ir_model in OpenERP.
9
+ # in Activerecord, ModelSchema is a module and its properties are carried by the
10
+ # ActiveRecord object. But in Ooor we don't want do do that because the Ooor::Base
11
+ # object is different for each session, so instead we delegate the schema
12
+ # properties to some ModelSchema instance that is shared between sessions,
13
+ # reused accross workers in a multi-process web app (via memcache for instance).
14
+ class ModelSchema
15
+
16
+ TEMPLATE_PROPERTIES = [:openerp_id, :info, :access_ids, :description,
17
+ :openerp_model, :field_ids, :state, :fields,
18
+ :many2one_associations, :one2many_associations, :many2many_associations,
19
+ :polymorphic_m2o_associations, :associations_keys,
20
+ :associations, :columns]
21
+
22
+ attr_accessor *TEMPLATE_PROPERTIES, :name, :columns_hash
23
+ end
24
+
25
+ end
@@ -4,16 +4,30 @@ module Ooor
4
4
  module Naming
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ class Name < ActiveModel::Name
8
+ def initialize(klass, namespace = nil, name = nil)
9
+ super
10
+ @singular = klass.openerp_model
11
+ @plural = klass.openerp_model # OpenERP doesn't enforce plural / singular conventions sadly...
12
+ @element = klass.openerp_model
13
+ @human = klass.description || klass.openerp_model
14
+ @param_key = klass.openerp_model.gsub('.', '_')
15
+ @i18n_key = klass.openerp_model
16
+ @route_key = klass.openerp_model.gsub('.', '-')
17
+ @singular_route_key = klass.openerp_model.gsub('.', '-')
18
+ end
19
+ end
20
+
7
21
  module ClassMethods
8
22
  def model_name
9
23
  @_model_name ||= begin
10
- namespace = self.parents.detect do |n|
11
- n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
12
- end
13
- ActiveModel::Name.new(self, namespace, self.description || self.openerp_model).tap do |r|
14
- def r.param_key
15
- @klass.openerp_model.gsub('.', '_')
24
+ if self.respond_to?(:openerp_model) && self.t
25
+ namespace = self.parents.detect do |n|
26
+ n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
16
27
  end
28
+ Ooor::Naming::Name.new(self, namespace)
29
+ else
30
+ super
17
31
  end
18
32
  end
19
33
  end
@@ -25,11 +39,11 @@ module Ooor
25
39
  #similar to Object#const_get but for OpenERP model key
26
40
  def const_get(model_key)
27
41
  scope = self.scope_prefix ? Object.const_get(self.scope_prefix) : Object
28
- klass_name = connection.class_name_from_model_key(model_key)
29
- if scope.const_defined?(klass_name) && Ooor.session_handler.connection_spec(scope.const_get(klass_name).connection.config) == Ooor.session_handler.connection_spec(connection.config)
42
+ klass_name = session.class_name_from_model_key(model_key)
43
+ if scope.const_defined?(klass_name) && Ooor.session_handler.noweb_session_spec(scope.const_get(klass_name).session.config) == Ooor.session_handler.noweb_session_spec(session.config)
30
44
  scope.const_get(klass_name)
31
45
  else
32
- connection.define_openerp_model(model: model_key, scope_prefix: self.scope_prefix)
46
+ session.define_openerp_model(model: model_key, scope_prefix: self.scope_prefix)
33
47
  end
34
48
  end
35
49
 
@@ -39,7 +53,7 @@ module Ooor
39
53
  end
40
54
 
41
55
  def param_field
42
- connection.config[:param_keys] && connection.config[:param_keys][openerp_model] || :id
56
+ session.config[:param_keys] && session.config[:param_keys][openerp_model] || :id
43
57
  end
44
58
 
45
59
  def find_by_permalink(param, options={})
@@ -51,9 +65,9 @@ module Ooor
51
65
 
52
66
  def alias(context={})
53
67
  # NOTE in v8, see if we can use ModelConvert here https://github.com/akretion/openerp-addons/blob/trunk-website-al/website/models/ir_http.py#L126
54
- if connection.config[:aliases]
55
- lang = context['lang'] || connection.config['lang'] || 'en_US'
56
- if alias_data = connection.config[:aliases][lang]
68
+ if session.config[:aliases]
69
+ lang = context['lang'] || session.config['lang'] || 'en_US'
70
+ if alias_data = session.config[:aliases][lang]
57
71
  alias_data.select{|key, value| value == openerp_model }.keys[0] || openerp_model
58
72
  else
59
73
  openerp_model
@@ -0,0 +1,57 @@
1
+ require 'ostruct'
2
+ require 'active_support/concern'
3
+
4
+ module Ooor
5
+ module NestedAttributes #:nodoc:
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+
10
+ # Defines an attributes writer for the specified association(s).
11
+ # Note that in Ooor this is active by default for all one2many and many2one associations
12
+ def accepts_nested_attributes_for(*attr_names)
13
+ attr_names.each do |association_name|
14
+ if rel = all_fields[association_name]
15
+ reflection = OpenStruct.new(rel.merge({options: {autosave: true}, name: association_name})) #TODO use a reflection class
16
+ generate_association_writer(association_name, :collection) #TODO add support for m2o
17
+ add_autosave_association_callbacks(reflection)
18
+ else
19
+ raise ArgumentError, "No association found for name `#{association_name}'. Has it been defined yet?"
20
+ end
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ # Generates a writer method for this association. Serves as a point for
27
+ # accessing the objects in the association. For example, this method
28
+ # could generate the following:
29
+ #
30
+ # def pirate_attributes=(attributes)
31
+ # assign_nested_attributes_for_one_to_one_association(:pirate, attributes)
32
+ # end
33
+ #
34
+ # This redirects the attempts to write objects in an association through
35
+ # the helper methods defined below. Makes it seem like the nested
36
+ # associations are just regular associations.
37
+ def generate_association_writer(association_name, type)
38
+ unless self.respond_to?(association_name)
39
+ self.instance_eval do
40
+ define_method "#{association_name}_attributes=" do |*args|
41
+ send("#{association_name}_will_change!")
42
+ # @associations[association_name] = args[0] # TODO what do we do here?
43
+ association_obj = self.class.reflect_on_association(association_name).klass
44
+ associations = []
45
+ (args[0] || {}).each do |k, v|
46
+ persisted = !v['id'].blank? || v[:id]
47
+ associations << association_obj.new(v, [], persisted, true) #TODO eventually use k to set sequence
48
+ end
49
+ @loaded_associations[association_name] = associations
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -9,65 +9,272 @@ require 'active_model/dirty'
9
9
  require 'ooor/errors'
10
10
 
11
11
  module Ooor
12
+ # = Ooor RecordInvalid
13
+ #
14
+ # Raised by <tt>save!</tt> and <tt>create!</tt> when the record is invalid. Use the
15
+ # +record+ method to retrieve the record which did not validate.
16
+ #
17
+ # begin
18
+ # complex_operation_that_calls_save!_internally
19
+ # rescue ActiveRecord::RecordInvalid => invalid
20
+ # puts invalid.record.errors
21
+ # end
22
+ class RecordInvalid < OpenERPServerError
23
+ attr_reader :record # :nodoc:
24
+ def initialize(record) # :nodoc:
25
+ @record = record
26
+ errors = @record.errors.full_messages.join(", ")
27
+ super(I18n.t(:"#{@record.class.i18n_scope}.errors.messages.record_invalid", :errors => errors, :default => :"errors.messages.record_invalid"))
28
+ end
29
+ end
12
30
 
13
- # the base class for proxies to OpenERP objects
31
+ # = Ooor Persistence
32
+ # Note that at the moment it also includes the Validations stuff as it is quite superficial in Ooor
33
+ # Most of the time, when we talk about validation here we talk about extra Rails validations
34
+ # as OpenERP validations will happen anyhow when persisting records to OpenERP.
35
+ # some of the methods found in ActiveRecord Persistence which are identical in ActiveResource
36
+ # may be found in the Ooor::MiniActiveResource module instead
14
37
  module Persistence
38
+ extend ActiveSupport::Concern
39
+ include ActiveModel::Validations
40
+
41
+ module ClassMethods
42
+
43
+ # Creates an object (or multiple objects) and saves it to the database, if validations pass.
44
+ # The resulting object is returned whether the object was saved successfully to the database or not.
45
+ #
46
+ # The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
47
+ # attributes on the objects that are to be created.
48
+ #
49
+ # the +default_get_list+ parameter differs from the ActiveRecord API
50
+ # it is used to tell OpenERP the list of fields for which we want the default values
51
+ # false will request all default values while [] will not ask for any default value (faster)
52
+ # +reload+ can be set to false to indicate you don't want to reload the record after it is saved
53
+ # which will save a roundtrip to OpenERP and perform faster.
54
+ def create(attributes = {}, default_get_list = false, reload = true, &block)
55
+ if attributes.is_a?(Array)
56
+ attributes.collect { |attr| create(attr, &block) }
57
+ else
58
+ object = new(attributes, default_get_list, &block)
59
+ object.save(reload)
60
+ object
61
+ end
62
+ end
63
+
64
+ # Creates an object just like Base.create but calls <tt>save!</tt> instead of +save+
65
+ # so an exception is raised if the record is invalid.
66
+ def create!(attributes = {}, default_get_list = false, reload = true, &block)
67
+ if attributes.is_a?(Array)
68
+ attributes.collect { |attr| create!(attr, &block) }
69
+ else
70
+ object = new(attributes, default_get_list)
71
+ yield(object) if block_given?
72
+ object.save!(reload)
73
+ object
74
+ end
75
+ end
15
76
 
16
- def load(attributes, remove_root=false, persisted=false)#an attribute might actually be a association too, will be determined here
17
- self.class.reload_fields_definition(false, object_session)
77
+ end
78
+
79
+ # Returns true if this object has been destroyed, otherwise returns false.
80
+ def destroyed?
81
+ @destroyed
82
+ end
83
+
84
+ # Flushes the current object and loads the +attributes+ Hash
85
+ # containing the attributes and the associations into the current object
86
+ def load(attributes)
87
+ self.class.reload_fields_definition(false)
18
88
  raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
19
- @prefix_options, attributes = split_options(attributes)
20
89
  @associations ||= {}
21
90
  @attributes ||= {}
22
91
  @loaded_associations = {}
23
92
  attributes.each do |key, value|
24
- self.send "#{key}=".to_sym, value if self.respond_to?("#{key}=".to_sym)
93
+ self.send "#{key}=", value if self.respond_to?("#{key}=")
25
94
  end
26
95
  self
27
96
  end
28
97
 
29
98
  #takes care of reading OpenERP default field values.
30
- def initialize(attributes = {}, default_get_list=false, context={}, persisted=false)
99
+ def initialize(attributes = {}, default_get_list = false, persisted = false, has_changed = false, lazy = false)
100
+ self.class.reload_fields_definition(false)
31
101
  @attributes = {}
32
- @prefix_options = {}
33
102
  @ir_model_data_id = attributes.delete(:ir_model_data_id)
34
- @object_session = {}
35
- @object_session = HashWithIndifferentAccess.new(context)
103
+ @marked_for_destruction = false
36
104
  @persisted = persisted
37
- self.class.reload_fields_definition(false, @object_session)
105
+ @lazy = lazy
38
106
  if default_get_list == []
39
107
  load(attributes)
40
108
  else
41
109
  load_with_defaults(attributes, default_get_list)
42
110
  end.tap do
43
- if id
111
+ if id && !has_changed
44
112
  @previously_changed = ActiveSupport::HashWithIndifferentAccess.new # see ActiveModel::Dirty reset_changes
45
113
  @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
46
114
  end
47
115
  end
48
116
  end
49
117
 
50
- # Saves (+create+) or \updates (+write+) a resource. Delegates to +create+ if the object is \new,
51
- # +update+ if it exists.
52
- def save(context={}, reload=true)
53
- create_or_update(context, reload)
118
+ # Saves the model.
119
+ #
120
+ # If the model is new a record gets created in OpenERP, otherwise
121
+ # the existing record gets updated.
122
+ #
123
+ # By default, save always run validations. If any of them fail the action
124
+ # is cancelled and +save+ returns +false+. However, if you supply
125
+ # validate: false, validations are bypassed altogether.
126
+ # In Ooor however, real validations always happen on the OpenERP side
127
+ # so the only validations you can bypass or not are extra pre-validations
128
+ # in Ruby if you have any.
129
+ #
130
+ # There's a series of callbacks associated with +save+. If any of the
131
+ # <tt>before_*</tt> callbacks return +false+ the action is cancelled and
132
+ # +save+ returns +false+. See ActiveRecord::Callbacks for further
133
+ # details.
134
+ #
135
+ # Attributes marked as readonly are silently ignored if the record is
136
+ # being updated. (TODO)
137
+ def save(options = {})
138
+ perform_validations(options) ? save_without_raising(options) : false
139
+ end
140
+
141
+ # Attempts to save the record just like save but will raise a +RecordInvalid+
142
+ # exception instead of returning +false+ if the record is not valid.
143
+ def save!(options = {})
144
+ perform_validations(options) ? save_without_raising(options) : raise(RecordInvalid.new(self))
145
+ end
146
+
147
+ # Deletes the record in OpenERP and freezes this instance to
148
+ # reflect that no changes should be made (since they can't be
149
+ # persisted). Returns the frozen instance.
150
+ #
151
+ # no callbacks are executed.
152
+ #
153
+ # To enforce the object's +before_destroy+ and +after_destroy+
154
+ # callbacks or any <tt>:dependent</tt> association
155
+ # options, use <tt>#destroy</tt>.
156
+ def delete
157
+ rpc_execute('unlink', [id], context) if persisted?
158
+ @destroyed = true
159
+ freeze
160
+ end
161
+
162
+ # Deletes the record in OpenERP and freezes this instance to reflect
163
+ # that no changes should be made (since they can't be persisted).
164
+ #
165
+ # There's a series of callbacks associated with <tt>destroy</tt>. If
166
+ # the <tt>before_destroy</tt> callback return +false+ the action is cancelled
167
+ # and <tt>destroy</tt> returns +false+. See
168
+ # ActiveRecord::Callbacks for further details.
169
+ def destroy
170
+ run_callbacks :destroy do
171
+ rpc_execute('unlink', [id], context)
172
+ @destroyed = true
173
+ freeze
174
+ end
175
+ end
176
+
177
+ # Deletes the record in the database and freezes this instance to reflect
178
+ # that no changes should be made (since they can't be persisted).
179
+ #
180
+ # There's a series of callbacks associated with <tt>destroy!</tt>. If
181
+ # the <tt>before_destroy</tt> callback return +false+ the action is cancelled
182
+ # and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
183
+ # ActiveRecord::Callbacks for further details.
184
+ def destroy! #TODO
185
+ destroy || raise(ActiveRecord::RecordNotDestroyed)
186
+ end
187
+
188
+ #TODO implement becomes / becomes! eventually
189
+
190
+ # Updates a single attribute and saves the record.
191
+ # This is especially useful for boolean flags on existing records. Also note that
192
+ #
193
+ # * Validation is skipped.
194
+ # * Callbacks are invoked.
195
+ # * updated_at/updated_on column is updated if that column is available.
196
+ # * Updates all the attributes that are dirty in this object.
197
+ #
198
+ # This method raises an +ActiveRecord::ActiveRecordError+ if the
199
+ # attribute is marked as readonly.
200
+ #
201
+ # See also +update_column+.
202
+ def update_attribute(name, value)
203
+ send("#{name}=", value)
204
+ save(validate: false)
205
+ end
206
+
207
+ # Updates the attributes of the model from the passed-in hash and saves the
208
+ # record, all wrapped in a transaction. If the object is invalid, the saving
209
+ # will fail and false will be returned.
210
+ def update(attributes, reload=true)
211
+ load(attributes) && save(reload)
212
+ end
213
+
214
+ alias update_attributes update
215
+
216
+ # Updates its receiver just like +update+ but calls <tt>save!</tt> instead
217
+ # of +save+, so an exception is raised if the record is invalid.
218
+ def update!(attributes, reload=true)
219
+ load(attributes) && save!(reload)
220
+ end
221
+
222
+ alias update_attributes! update!
223
+
224
+ #OpenERP copy method, load persisted copied Object
225
+ def copy(defaults={}, context={})
226
+ self.class.find(rpc_execute('copy', id, defaults, context), context: context)
54
227
  end
55
228
 
56
- def create_or_update(context={}, reload=true)
229
+ # Runs all the validations within the specified context. Returns +true+ if
230
+ # no errors are found, +false+ otherwise.
231
+ #
232
+ # Aliased as validate.
233
+ #
234
+ # If the argument is +false+ (default is +nil+), the context is set to <tt>:create</tt> if
235
+ # <tt>new_record?</tt> is +true+, and to <tt>:update</tt> if it is not.
236
+ #
237
+ # Validations with no <tt>:on</tt> option will run no matter the context. Validations with
238
+ # some <tt>:on</tt> option will only run in the specified context.
239
+ def valid?(context = nil)
240
+ context ||= (new_record? ? :create : :update)
241
+ output = super(context)
242
+ errors.empty? && output
243
+ end
244
+
245
+ alias_method :validate, :valid?
246
+
247
+ protected
248
+
249
+ # Real validations happens on OpenERP side, only pre-validations can happen here eventually
250
+ def perform_validations(options={}) # :nodoc:
251
+ if options.is_a?(Hash)
252
+ options[:validate] == false || valid?(options[:context])
253
+ else
254
+ valid?
255
+ end
256
+ end
257
+
258
+ private
259
+
260
+ def create_or_update(options={})
57
261
  run_callbacks :save do
58
- new? ? create_record(context, reload) : update_record(context, reload)
262
+ new? ? create_record(options) : update_record(options)
59
263
  end
60
264
  rescue ValidationError => e
61
265
  e.extract_validation_error!(errors)
62
266
  return false
63
267
  end
64
268
 
65
- # Create (i.e., \save to OpenERP service) the \new resource.
66
- def create(context={}, reload=true)
67
- create_or_update(context, reload)
269
+ def update_record(options)
270
+ run_callbacks :update do
271
+ rpc_execute('write', [self.id], to_openerp_hash, context)
272
+ reload_fields if should_reload?(options)
273
+ @persisted = true
274
+ end
68
275
  end
69
276
 
70
- def create_record(context={}, reload=true)
277
+ def create_record(options={})
71
278
  run_callbacks :create do
72
279
  self.id = rpc_execute('create', to_openerp_hash, context)
73
280
  if @ir_model_data_id
@@ -77,45 +284,36 @@ module Ooor
77
284
  'res_id' => self.id)
78
285
  end
79
286
  @persisted = true
80
- reload_fields(context) if reload
287
+ reload_fields if should_reload?(options)
81
288
  end
82
289
  end
83
290
 
84
- def update_attributes(attributes, context={}, reload=true)
85
- load(attributes, false) && save(context, reload)
86
- end
87
-
88
- # Update the resource on the remote service.
89
- def update(context={}, reload=true, keys=nil)
90
- create_or_update(context, reload, keys)
291
+ def save_without_raising(options = {})
292
+ create_or_update(options)
293
+ rescue Ooor::RecordInvalid
294
+ false
91
295
  end
92
296
 
93
- def update_record(context={}, reload=true)
94
- run_callbacks :update do
95
- rpc_execute('write', [self.id], to_openerp_hash, context)
96
- reload_fields(context) if reload
97
- @persisted = true
297
+ def should_validate?(options)
298
+ if options.is_a?(Hash)
299
+ options[:validate] != false
300
+ else
301
+ true
98
302
  end
99
303
  end
100
304
 
101
- #Deletes the record in OpenERP and freezes this instance to reflect that no changes should be made (since they can’t be persisted).
102
- def destroy(context={})
103
- run_callbacks :destroy do
104
- rpc_execute('unlink', [self.id], context)
105
- @destroyed = true
106
- freeze
305
+ def should_reload?(options)
306
+ if options == false
307
+ false
308
+ elsif options.is_a?(Hash) && options[:reload] == false
309
+ false
310
+ else
311
+ true
107
312
  end
108
313
  end
109
314
 
110
- #OpenERP copy method, load persisted copied Object
111
- def copy(defaults={}, context={})
112
- self.class.find(rpc_execute('copy', self.id, defaults, context), context: context)
113
- end
114
-
115
- private
116
-
117
315
  def load_with_defaults(attributes, default_get_list)
118
- defaults = rpc_execute("default_get", default_get_list || self.class.fields.keys + self.class.associations_keys, object_session.dup)
316
+ defaults = rpc_execute("default_get", default_get_list || self.class.fields.keys + self.class.associations_keys, context)
119
317
  attributes = HashWithIndifferentAccess.new(defaults.merge(attributes.reject {|k, v| v.blank? }))
120
318
  load(attributes)
121
319
  end
@@ -130,7 +328,7 @@ module Ooor
130
328
  load(attrs)
131
329
  end
132
330
 
133
- def reload_fields(context)
331
+ def reload_fields
134
332
  record = self.class.find(self.id, context: context)
135
333
  load(record.attributes.merge(record.associations))
136
334
  @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new # see ActiveModel::Dirty