openstax_active_force 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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.mailmap +3 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +98 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +174 -0
- data/Rakefile +6 -0
- data/active_force.gemspec +30 -0
- data/lib/active_attr/dirty.rb +33 -0
- data/lib/active_force/active_query.rb +155 -0
- data/lib/active_force/association/association.rb +50 -0
- data/lib/active_force/association/belongs_to_association.rb +26 -0
- data/lib/active_force/association/eager_load_projection_builder.rb +60 -0
- data/lib/active_force/association/has_many_association.rb +33 -0
- data/lib/active_force/association/relation_model_builder.rb +70 -0
- data/lib/active_force/association.rb +28 -0
- data/lib/active_force/attribute.rb +30 -0
- data/lib/active_force/mapping.rb +78 -0
- data/lib/active_force/query.rb +110 -0
- data/lib/active_force/sobject.rb +210 -0
- data/lib/active_force/standard_types.rb +357 -0
- data/lib/active_force/table.rb +37 -0
- data/lib/active_force/version.rb +3 -0
- data/lib/active_force.rb +13 -0
- data/lib/generators/active_force/model/USAGE +8 -0
- data/lib/generators/active_force/model/model_generator.rb +62 -0
- data/lib/generators/active_force/model/templates/model.rb.erb +5 -0
- data/spec/active_force/active_query_spec.rb +178 -0
- data/spec/active_force/association/relation_model_builder_spec.rb +62 -0
- data/spec/active_force/association_spec.rb +157 -0
- data/spec/active_force/attribute_spec.rb +27 -0
- data/spec/active_force/callbacks_spec.rb +20 -0
- data/spec/active_force/mapping_spec.rb +18 -0
- data/spec/active_force/query_spec.rb +126 -0
- data/spec/active_force/sobject/includes_spec.rb +290 -0
- data/spec/active_force/sobject/table_name_spec.rb +27 -0
- data/spec/active_force/sobject_spec.rb +398 -0
- data/spec/active_force/table_spec.rb +25 -0
- data/spec/active_force_spec.rb +7 -0
- data/spec/fixtures/sobject/single_sobject_hash.yml +26 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/fixture_helpers.rb +45 -0
- data/spec/support/restforce_factories.rb +9 -0
- data/spec/support/sobjects.rb +97 -0
- data/spec/support/whizbang.rb +30 -0
- metadata +196 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
module ActiveForce
|
2
|
+
module Association
|
3
|
+
class EagerLoadProjectionBuilder
|
4
|
+
class << self
|
5
|
+
def build(association)
|
6
|
+
new(association).projections
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :association
|
11
|
+
|
12
|
+
def initialize(association)
|
13
|
+
@association = association
|
14
|
+
end
|
15
|
+
|
16
|
+
def projections
|
17
|
+
klass = association.class.name.split('::').last
|
18
|
+
builder_class = ActiveForce::Association.const_get "#{klass}ProjectionBuilder"
|
19
|
+
builder_class.new(association).projections
|
20
|
+
rescue NameError
|
21
|
+
raise "Don't know how to build projections for #{klass}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class AbstractProjectionBuilder
|
26
|
+
attr_reader :association
|
27
|
+
|
28
|
+
def initialize(association)
|
29
|
+
@association = association
|
30
|
+
end
|
31
|
+
|
32
|
+
def projections
|
33
|
+
raise "Must define #{self.class.name}#projections"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class HasManyAssociationProjectionBuilder < AbstractProjectionBuilder
|
38
|
+
###
|
39
|
+
# Use ActiveForce::Query to build a subquery for the SFDC
|
40
|
+
# relationship name. Per SFDC convention, the name needs
|
41
|
+
# to be pluralized
|
42
|
+
def projections
|
43
|
+
match = association.sfdc_association_field.match /__r\z/
|
44
|
+
# pluralize the table name, and append '__r' if it was there to begin with
|
45
|
+
relationship_name = association.sfdc_association_field.sub(match.to_s, '').pluralize + match.to_s
|
46
|
+
query = Query.new relationship_name
|
47
|
+
query.fields association.relation_model.fields
|
48
|
+
["(#{query.to_s})"]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class BelongsToAssociationProjectionBuilder < AbstractProjectionBuilder
|
53
|
+
def projections
|
54
|
+
association.relation_model.fields.map do |field|
|
55
|
+
"#{ association.sfdc_association_field }.#{ field }"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module ActiveForce
|
2
|
+
module Association
|
3
|
+
class HasManyAssociation < Association
|
4
|
+
private
|
5
|
+
|
6
|
+
def default_foreign_key
|
7
|
+
infer_foreign_key_from_model @parent
|
8
|
+
end
|
9
|
+
|
10
|
+
def define_relation_method
|
11
|
+
association = self
|
12
|
+
_method = @relation_name
|
13
|
+
@parent.send :define_method, _method do
|
14
|
+
association_cache.fetch _method do
|
15
|
+
query = association.relation_model.query
|
16
|
+
if scope = association.options[:scoped_as]
|
17
|
+
if scope.arity > 0
|
18
|
+
query.instance_exec self, &scope
|
19
|
+
else
|
20
|
+
query.instance_exec &scope
|
21
|
+
end
|
22
|
+
end
|
23
|
+
association_cache[_method] = query.where association.foreign_key => self.id
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
@parent.send :define_method, "#{_method}=" do |associated|
|
28
|
+
association_cache[_method] = associated
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ActiveForce
|
2
|
+
module Association
|
3
|
+
class RelationModelBuilder
|
4
|
+
class << self
|
5
|
+
def build(association, value)
|
6
|
+
new(association, value).build_relation_model
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(association, value)
|
11
|
+
@association = association
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_relation_model
|
16
|
+
klass = resolve_class
|
17
|
+
klass.new(@association, @value).call
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def resolve_class
|
23
|
+
association_builder = @value.class.name.gsub('::', '_')
|
24
|
+
ActiveForce::Association.const_get "BuildFrom#{association_builder}"
|
25
|
+
rescue NameError
|
26
|
+
raise "Don't know how to build relation from #{@value.class.name}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class AbstractBuildFrom
|
31
|
+
attr_reader :association, :value
|
32
|
+
|
33
|
+
def initialize(association, value)
|
34
|
+
@association = association
|
35
|
+
@value = value
|
36
|
+
end
|
37
|
+
|
38
|
+
def call
|
39
|
+
raise "Must implement #{self.class.name}#call"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class BuildFromHash < AbstractBuildFrom
|
44
|
+
def call
|
45
|
+
association.build value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class BuildFromArray < AbstractBuildFrom
|
50
|
+
def call
|
51
|
+
value.map { |mash| association.build mash }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class BuildFromNilClass < AbstractBuildFrom
|
56
|
+
def call
|
57
|
+
association.is_a?(BelongsToAssociation) ? nil : []
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class BuildFromRestforce_SObject < BuildFromHash
|
62
|
+
end
|
63
|
+
|
64
|
+
class BuildFromRestforce_Mash < BuildFromHash
|
65
|
+
end
|
66
|
+
|
67
|
+
class BuildFromRestforce_Collection < BuildFromArray
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'active_force/association/association'
|
2
|
+
require 'active_force/association/eager_load_projection_builder'
|
3
|
+
require 'active_force/association/relation_model_builder'
|
4
|
+
require 'active_force/association/has_many_association'
|
5
|
+
require 'active_force/association/belongs_to_association'
|
6
|
+
|
7
|
+
module ActiveForce
|
8
|
+
module Association
|
9
|
+
def associations
|
10
|
+
@associations ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# i.e name = 'Quota__r'
|
14
|
+
def find_association name
|
15
|
+
associations.values.detect do |association|
|
16
|
+
association.represents_sfdc_table? name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def has_many relation_name, options = {}
|
21
|
+
associations[relation_name] = HasManyAssociation.new(self, relation_name, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def belongs_to relation_name, options = {}
|
25
|
+
associations[relation_name] = BelongsToAssociation.new(self, relation_name, options)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActiveForce
|
2
|
+
class Attribute
|
3
|
+
|
4
|
+
attr_accessor :local_name, :sfdc_name, :as
|
5
|
+
|
6
|
+
def initialize name, options = {}
|
7
|
+
self.local_name = name
|
8
|
+
self.sfdc_name = options[:sfdc_name] || options[:from] || default_api_name
|
9
|
+
self.as = options[:as] || :string
|
10
|
+
end
|
11
|
+
|
12
|
+
def value_for_hash value
|
13
|
+
case as
|
14
|
+
when :multi_picklist
|
15
|
+
value.reject(&:empty?).join(';')
|
16
|
+
else
|
17
|
+
value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
###
|
24
|
+
# Transforms +attribute+ to the conventional Salesforce API name.
|
25
|
+
#
|
26
|
+
def default_api_name
|
27
|
+
local_name.to_s.split('_').map(&:capitalize).join('_') << '__c'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'active_force/attribute'
|
2
|
+
require 'active_force/table'
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module ActiveForce
|
6
|
+
class Mapping
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
STRINGLIKE_TYPES = [
|
10
|
+
nil, :string, :base64, :byte, :ID, :reference, :currency, :textarea,
|
11
|
+
:phone, :url, :email, :combobox, :picklist, :multipicklist, :anyType,
|
12
|
+
:location
|
13
|
+
]
|
14
|
+
|
15
|
+
def_delegators :table, :custom_table?, :table_name
|
16
|
+
|
17
|
+
def initialize model
|
18
|
+
@model = model
|
19
|
+
end
|
20
|
+
|
21
|
+
def mappings
|
22
|
+
Hash[fields.map { |field, attr| [field, attr.sfdc_name] }]
|
23
|
+
end
|
24
|
+
|
25
|
+
def sfdc_names
|
26
|
+
mappings.values
|
27
|
+
end
|
28
|
+
|
29
|
+
def field name, options
|
30
|
+
fields.merge!({ name => ActiveForce::Attribute.new(name, options) })
|
31
|
+
end
|
32
|
+
|
33
|
+
def table
|
34
|
+
@table ||= ActiveForce::Table.new @model
|
35
|
+
end
|
36
|
+
|
37
|
+
def translate_to_sf attributes
|
38
|
+
attrs = attributes.map do |attribute, value|
|
39
|
+
attr = fields[attribute.to_sym]
|
40
|
+
[attr.sfdc_name, attr.value_for_hash(value)]
|
41
|
+
end
|
42
|
+
Hash[attrs]
|
43
|
+
end
|
44
|
+
|
45
|
+
def translate_value value, field_name
|
46
|
+
return value unless !!field_name
|
47
|
+
typecast_value value, fields[field_name].as
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def fields
|
54
|
+
@fields ||= {}
|
55
|
+
end
|
56
|
+
|
57
|
+
# Handles Salesforce FieldTypes as described here:
|
58
|
+
# http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_calls_describesobjects_describesobjectresult.htm#i1427700
|
59
|
+
def typecast_value value, type
|
60
|
+
case type
|
61
|
+
when *STRINGLIKE_TYPES
|
62
|
+
value.to_s
|
63
|
+
when :boolean
|
64
|
+
!['false','0','f'].include? value.to_s.downcase
|
65
|
+
when :int
|
66
|
+
value.to_i
|
67
|
+
when :double, :percent
|
68
|
+
value.to_f
|
69
|
+
when :date
|
70
|
+
Date.parse value
|
71
|
+
when :datetime
|
72
|
+
DateTime.parse value
|
73
|
+
else
|
74
|
+
value
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module ActiveForce
|
2
|
+
class Query
|
3
|
+
attr_reader :table
|
4
|
+
|
5
|
+
def initialize table
|
6
|
+
@table = table
|
7
|
+
@conditions = []
|
8
|
+
@table_id = 'Id'
|
9
|
+
@query_fields = [@table_id]
|
10
|
+
end
|
11
|
+
|
12
|
+
def fields fields_collection = []
|
13
|
+
@query_fields += fields_collection.to_a
|
14
|
+
end
|
15
|
+
|
16
|
+
def all
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
<<-SOQL.gsub(/\s+/, " ").strip
|
22
|
+
SELECT
|
23
|
+
#{ build_select }
|
24
|
+
FROM
|
25
|
+
#{ @table }
|
26
|
+
#{ build_where }
|
27
|
+
#{ build_order }
|
28
|
+
#{ build_limit }
|
29
|
+
#{ build_offset }
|
30
|
+
SOQL
|
31
|
+
end
|
32
|
+
|
33
|
+
def select *columns
|
34
|
+
@query_fields = columns
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def where condition
|
39
|
+
@conditions << condition if condition
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def order order
|
44
|
+
@order = order if order
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def limit size
|
49
|
+
@size = size if size
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def limit_value
|
54
|
+
@size
|
55
|
+
end
|
56
|
+
|
57
|
+
def offset offset
|
58
|
+
@offset = offset
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def offset_value
|
63
|
+
@offset
|
64
|
+
end
|
65
|
+
|
66
|
+
def find id
|
67
|
+
where "#{ @table_id } = '#{ id }'"
|
68
|
+
limit 1
|
69
|
+
end
|
70
|
+
|
71
|
+
def first
|
72
|
+
limit 1
|
73
|
+
end
|
74
|
+
|
75
|
+
def last
|
76
|
+
order("Id DESC").limit(1)
|
77
|
+
end
|
78
|
+
|
79
|
+
def join object_query
|
80
|
+
fields ["(#{ object_query.to_s })"]
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
def count
|
85
|
+
@query_fields = ["count(Id)"]
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
90
|
+
def build_select
|
91
|
+
@query_fields.compact.uniq.join(', ')
|
92
|
+
end
|
93
|
+
|
94
|
+
def build_where
|
95
|
+
"WHERE (#{ @conditions.join(') AND (') })" unless @conditions.empty?
|
96
|
+
end
|
97
|
+
|
98
|
+
def build_limit
|
99
|
+
"LIMIT #{ @size }" if @size
|
100
|
+
end
|
101
|
+
|
102
|
+
def build_order
|
103
|
+
"ORDER BY #{ @order }" if @order
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_offset
|
107
|
+
"OFFSET #{ @offset }" if @offset
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
require 'active_attr'
|
3
|
+
require 'active_attr/dirty'
|
4
|
+
require 'active_force/active_query'
|
5
|
+
require 'active_force/association'
|
6
|
+
require 'active_force/mapping'
|
7
|
+
require 'yaml'
|
8
|
+
require 'forwardable'
|
9
|
+
require 'logger'
|
10
|
+
require 'restforce'
|
11
|
+
|
12
|
+
module ActiveForce
|
13
|
+
class RecordInvalid < StandardError;end
|
14
|
+
|
15
|
+
class SObject
|
16
|
+
include ActiveAttr::Model
|
17
|
+
include ActiveAttr::Dirty
|
18
|
+
extend ActiveForce::Association
|
19
|
+
extend ActiveModel::Callbacks
|
20
|
+
|
21
|
+
define_model_callbacks :save, :create, :update
|
22
|
+
|
23
|
+
class_attribute :mappings, :table_name
|
24
|
+
|
25
|
+
class << self
|
26
|
+
extend Forwardable
|
27
|
+
def_delegators :query, :where, :first, :last, :all, :find, :find_by, :count, :includes, :limit, :order, :select, :none
|
28
|
+
def_delegators :mapping, :table, :table_name, :custom_table?, :mappings
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
###
|
33
|
+
# Provide each subclass with a default id field. Can be overridden
|
34
|
+
# in the subclass if needed
|
35
|
+
def inherited(subclass)
|
36
|
+
subclass.field :id, from: 'Id'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.mapping
|
41
|
+
@mapping ||= ActiveForce::Mapping.new name
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.fields
|
45
|
+
mapping.sfdc_names
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.query
|
49
|
+
ActiveForce::ActiveQuery.new self
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.build mash
|
53
|
+
return unless mash
|
54
|
+
sobject = new
|
55
|
+
mash.each do |column, sf_value|
|
56
|
+
sobject.write_value column, sf_value
|
57
|
+
end
|
58
|
+
sobject.clear_changes_information
|
59
|
+
sobject
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_attributes! attributes = {}
|
63
|
+
assign_attributes attributes
|
64
|
+
validate!
|
65
|
+
run_callbacks :save do
|
66
|
+
run_callbacks :update do
|
67
|
+
sfdc_client.update! table_name, attributes_for_sfdb
|
68
|
+
changes_applied
|
69
|
+
end
|
70
|
+
end
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
alias_method :update!, :update_attributes!
|
75
|
+
|
76
|
+
def update_attributes attributes = {}
|
77
|
+
update_attributes! attributes
|
78
|
+
rescue Faraday::Error::ClientError, RecordInvalid => error
|
79
|
+
handle_save_error error
|
80
|
+
end
|
81
|
+
|
82
|
+
alias_method :update, :update_attributes
|
83
|
+
|
84
|
+
def create!
|
85
|
+
validate!
|
86
|
+
run_callbacks :save do
|
87
|
+
run_callbacks :create do
|
88
|
+
self.id = sfdc_client.create! table_name, attributes_for_sfdb
|
89
|
+
changes_applied
|
90
|
+
end
|
91
|
+
end
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
def create
|
96
|
+
create!
|
97
|
+
rescue Faraday::Error::ClientError, RecordInvalid => error
|
98
|
+
handle_save_error error
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def destroy
|
103
|
+
sfdc_client.destroy! self.class.table_name, id
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.create args
|
107
|
+
new(args).create
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.create! args
|
111
|
+
new(args).create!
|
112
|
+
end
|
113
|
+
|
114
|
+
def save!
|
115
|
+
run_callbacks :save do
|
116
|
+
if persisted?
|
117
|
+
!!update!
|
118
|
+
else
|
119
|
+
!!create!
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def save
|
125
|
+
save!
|
126
|
+
rescue Faraday::Error::ClientError, RecordInvalid => error
|
127
|
+
handle_save_error error
|
128
|
+
end
|
129
|
+
|
130
|
+
def to_param
|
131
|
+
id
|
132
|
+
end
|
133
|
+
|
134
|
+
def persisted?
|
135
|
+
!!id
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.field field_name, args = {}
|
139
|
+
mapping.field field_name, args
|
140
|
+
attribute field_name
|
141
|
+
end
|
142
|
+
|
143
|
+
def reload
|
144
|
+
association_cache.clear
|
145
|
+
reloaded = self.class.find(id)
|
146
|
+
self.attributes = reloaded.attributes
|
147
|
+
clear_changes_information
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
def write_value column, value
|
152
|
+
if association = self.class.find_association(column)
|
153
|
+
field = association.relation_name
|
154
|
+
value = Association::RelationModelBuilder.build(association, value)
|
155
|
+
else
|
156
|
+
field = mappings.invert[column]
|
157
|
+
value = self.class.mapping.translate_value value, field unless value.nil?
|
158
|
+
end
|
159
|
+
send "#{field}=", value if field
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def validate!
|
165
|
+
unless valid?
|
166
|
+
raise RecordInvalid.new(
|
167
|
+
"Validation failed: #{errors.full_messages.join(', ')}"
|
168
|
+
)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def handle_save_error error
|
173
|
+
return false if error.class == RecordInvalid
|
174
|
+
logger_output __method__, error, attributes
|
175
|
+
end
|
176
|
+
|
177
|
+
def association_cache
|
178
|
+
@association_cache ||= {}
|
179
|
+
end
|
180
|
+
|
181
|
+
def logger_output action, exception, params = {}
|
182
|
+
logger = Logger.new($stdout)
|
183
|
+
logger.info("[SFDC] [#{self.class.model_name}] [#{self.class.table_name}] Error while #{ action }, params: #{params}, error: #{exception.inspect}")
|
184
|
+
errors[:base] << exception.message
|
185
|
+
false
|
186
|
+
end
|
187
|
+
|
188
|
+
def attributes_for_sfdb
|
189
|
+
attrs = self.class.mapping.translate_to_sf(attributes_and_changes)
|
190
|
+
attrs.merge!({'Id' => id }) if persisted?
|
191
|
+
attrs
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.picklist field
|
195
|
+
picks = sfdc_client.picklist_values(table_name, mappings[field])
|
196
|
+
picks.map do |value|
|
197
|
+
[value[:label], value[:value]]
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def self.sfdc_client
|
202
|
+
ActiveForce.sfdc_client
|
203
|
+
end
|
204
|
+
|
205
|
+
def sfdc_client
|
206
|
+
self.class.sfdc_client
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|