activesalesforce 0.0.3 → 0.0.4
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/README +18 -2
- data/lib/activesalesforce.rb +24 -0
- data/lib/salesforce_active_record.rb +37 -21
- data/lib/salesforce_connection_adapter.rb +66 -53
- data/test/unit/account_test.rb +28 -6
- metadata +4 -3
data/README
CHANGED
@@ -6,8 +6,24 @@
|
|
6
6
|
|
7
7
|
== Getting started
|
8
8
|
|
9
|
-
1.
|
10
|
-
|
9
|
+
1. gem install activesalesforce
|
10
|
+
2. if you have not already done so generate your initial rails app using "rails <myappname goes here>"
|
11
|
+
3. edit config/environment.rb and add "require_gem 'activesalesforce'" to the end of the "Rails::Initializer.run do |config|" block, e.g.
|
12
|
+
|
13
|
+
Rails::Initializer.run do |config|
|
14
|
+
...
|
15
|
+
|
16
|
+
require_gem 'activesalesforce'
|
17
|
+
end
|
18
|
+
|
19
|
+
4. edit database.yml
|
20
|
+
|
21
|
+
adapter: salesforce
|
22
|
+
url: <salesforce api server url goes here>
|
23
|
+
username: <salesforce user name goes here>
|
24
|
+
password: <salesforce password goes here>
|
25
|
+
|
26
|
+
5. proceed using standard Rails development techniques!
|
11
27
|
|
12
28
|
== Description of contents
|
13
29
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
=begin
|
2
|
+
ActiveSalesforce
|
3
|
+
Copyright (c) 2006 Doug Chasman
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
=end
|
23
|
+
|
24
|
+
require 'salesforce_connection_adapter'
|
@@ -32,38 +32,37 @@ module ActiveRecord
|
|
32
32
|
# This behavior can be turned off by setting <tt>ActiveRecord::Base.record_timestamps = false</tt>.
|
33
33
|
# This behavior can use GMT by setting <tt>ActiveRecord::Base.timestamps_gmt = true</tt>
|
34
34
|
module SalesforceRecord
|
35
|
-
include SOAP, XSD
|
36
|
-
|
37
|
-
NS1 = 'urn:partner.soap.sforce.com'
|
38
|
-
NS2 = "urn:sobject.partner.soap.sforce.com"
|
39
35
|
|
40
36
|
def self.append_features(base) # :nodoc:
|
41
37
|
super
|
42
|
-
|
38
|
+
|
43
39
|
base.class_eval do
|
44
40
|
alias_method :create, :create_with_sforce_api
|
45
41
|
alias_method :update, :update_with_sforce_api
|
46
42
|
end
|
47
43
|
end
|
48
|
-
|
44
|
+
|
49
45
|
def create_with_sforce_api
|
50
46
|
return if not @attributes.changed?
|
51
47
|
puts "create_with_sforce_api creating #{self.class}"
|
52
|
-
connection.create(:sObjects => create_sobject())
|
48
|
+
id = connection.create(:sObjects => create_sobject())
|
49
|
+
self.Id = id
|
50
|
+
@attributes.clear_changed!
|
53
51
|
end
|
54
|
-
|
52
|
+
|
55
53
|
def update_with_sforce_api
|
56
54
|
return if not @attributes.changed?
|
57
55
|
puts "update_with_sforce_api updating #{self.class}('#{self.Id}')"
|
58
56
|
connection.update(:sObjects => create_sobject())
|
57
|
+
@attributes.clear_changed!
|
59
58
|
end
|
60
59
|
|
61
60
|
def create_sobject()
|
62
61
|
fields = @attributes.changed_fields
|
63
|
-
|
62
|
+
|
64
63
|
sobj = [ 'type { :xmlns => "urn:sobject.partner.soap.sforce.com" }', self.class.name ]
|
65
64
|
sobj << 'Id { :xmlns => "urn:sobject.partner.soap.sforce.com" }' << self.Id if self.Id
|
66
|
-
|
65
|
+
|
67
66
|
# now add any changed fields
|
68
67
|
fieldValues = {}
|
69
68
|
fields.each do |fieldName|
|
@@ -73,7 +72,7 @@ module ActiveRecord
|
|
73
72
|
|
74
73
|
sobj
|
75
74
|
end
|
76
|
-
|
75
|
+
|
77
76
|
end
|
78
77
|
|
79
78
|
class Base
|
@@ -83,16 +82,29 @@ module ActiveRecord
|
|
83
82
|
default_timezone = :utc
|
84
83
|
|
85
84
|
def after_initialize()
|
85
|
+
sfdcObjectName = self.class.table_name
|
86
86
|
if not @attributes.is_a?(Salesforce::SObjectAttributes)
|
87
|
-
# Insure that SObjectAttributes is always used for our
|
87
|
+
# Insure that SObjectAttributes is always used for our attributes
|
88
88
|
originalAttributes = @attributes
|
89
89
|
|
90
|
-
@attributes = Salesforce::SObjectAttributes.new(connection.columns_map(
|
90
|
+
@attributes = Salesforce::SObjectAttributes.new(connection.columns_map(sfdcObjectName))
|
91
91
|
|
92
92
|
originalAttributes.each { |name, value| self[name] = value }
|
93
93
|
end
|
94
|
+
|
95
|
+
# Create relationships for any reference field
|
96
|
+
connection.columns(sfdcObjectName).each do |column|
|
97
|
+
if column.reference_to
|
98
|
+
referenceName = column.name.chop.chop
|
99
|
+
|
100
|
+
unless self.respond_to? referenceName.to_sym or column.reference_to == "Profile"
|
101
|
+
puts "Creating relationship from #{sfdcObjectName} to #{column.reference_to} for #{referenceName}"
|
102
|
+
self.class.belongs_to referenceName.to_sym, :class_name => column.reference_to, :foreign_key => column.name, :dependent => false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
94
106
|
end
|
95
|
-
|
107
|
+
|
96
108
|
def self.table_name
|
97
109
|
class_name_of_active_record_descendant(self)
|
98
110
|
end
|
@@ -100,7 +112,7 @@ module ActiveRecord
|
|
100
112
|
def self.primary_key
|
101
113
|
"Id"
|
102
114
|
end
|
103
|
-
|
115
|
+
|
104
116
|
def self.construct_finder_sql(options)
|
105
117
|
soql = "SELECT #{column_names.join(', ')} FROM #{table_name} "
|
106
118
|
add_conditions!(soql, options[:conditions])
|
@@ -114,15 +126,19 @@ module ActiveRecord
|
|
114
126
|
end
|
115
127
|
|
116
128
|
def self.count(conditions = nil, joins = nil)
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
129
|
+
soql = "SELECT Id FROM #{table_name} "
|
130
|
+
add_conditions!(soql, conditions)
|
131
|
+
|
132
|
+
count_by_sql(soql)
|
121
133
|
end
|
122
134
|
|
123
135
|
def self.count_by_sql(soql)
|
124
136
|
connection.select_all(soql, "#{name} Count").length
|
125
|
-
end
|
126
|
-
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.delete(ids)
|
140
|
+
connection.delete(ids)
|
141
|
+
end
|
142
|
+
|
127
143
|
end
|
128
144
|
end
|
@@ -32,63 +32,63 @@ require File.dirname(__FILE__) + '/salesforce_active_record'
|
|
32
32
|
require File.dirname(__FILE__) + '/column_definition'
|
33
33
|
|
34
34
|
ActiveRecord::Base.class_eval do
|
35
|
-
|
35
|
+
include ActiveRecord::SalesforceRecord
|
36
36
|
end
|
37
37
|
|
38
38
|
|
39
39
|
module ActiveRecord
|
40
40
|
class Base
|
41
41
|
@@cache = {}
|
42
|
-
|
42
|
+
|
43
43
|
# Establishes a connection to the database that's used by all Active Record objects.
|
44
44
|
def self.salesforce_connection(config) # :nodoc:
|
45
45
|
puts "Using Salesforce connection!"
|
46
|
-
|
46
|
+
|
47
47
|
config = config.symbolize_keys
|
48
|
-
|
48
|
+
|
49
49
|
url = config[:url].to_s
|
50
50
|
username = config[:username].to_s
|
51
51
|
password = config[:password].to_s
|
52
52
|
|
53
53
|
connection = @@cache["#{url}.#{username}.#{password}"]
|
54
|
-
|
54
|
+
|
55
55
|
if not connection
|
56
56
|
connection = SalesforceLogin.new(url, username, password).proxy
|
57
57
|
@@cache["#{url}.#{username}.#{password}"] = connection
|
58
58
|
puts "Created new connection for [#{url}, #{username}]"
|
59
59
|
end
|
60
|
-
|
61
|
-
#puts "connected to Salesforce as #{connection.getUserInfo(nil).result['userFullName']}"
|
62
60
|
|
63
61
|
ConnectionAdapters::SalesforceAdapter.new(connection, logger, [url, username, password], config)
|
64
62
|
end
|
65
63
|
end
|
66
64
|
|
67
|
-
|
65
|
+
|
68
66
|
module ConnectionAdapters
|
69
67
|
class SalesforceError < StandardError
|
70
68
|
end
|
71
69
|
|
72
70
|
class SalesforceAdapter < AbstractAdapter
|
73
|
-
|
71
|
+
|
74
72
|
def initialize(connection, logger, connection_options, config)
|
75
73
|
super(connection, logger)
|
76
74
|
|
77
75
|
@connection_options, @config = connection_options, config
|
76
|
+
|
77
|
+
@columns_map = {}
|
78
78
|
@columns_name_map = {}
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
def adapter_name #:nodoc:
|
82
82
|
'Salesforce'
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
def supports_migrations? #:nodoc:
|
86
86
|
false
|
87
87
|
end
|
88
|
-
|
89
|
-
|
88
|
+
|
89
|
+
|
90
90
|
# QUOTING ==================================================
|
91
|
-
|
91
|
+
|
92
92
|
def quote(value, column = nil)
|
93
93
|
if value.kind_of?(String) && column && column.type == :binary
|
94
94
|
s = column.class.string_to_binary(value).unpack("H*")[0]
|
@@ -97,15 +97,15 @@ module ActiveRecord
|
|
97
97
|
super
|
98
98
|
end
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
def quote_column_name(name) #:nodoc:
|
102
102
|
"`#{name}`"
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
def quote_string(string) #:nodoc:
|
106
106
|
string
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
def quoted_true
|
110
110
|
"TRUE"
|
111
111
|
end
|
@@ -113,28 +113,28 @@ module ActiveRecord
|
|
113
113
|
def quoted_false
|
114
114
|
"FALSE"
|
115
115
|
end
|
116
|
-
|
117
|
-
|
116
|
+
|
117
|
+
|
118
118
|
# CONNECTION MANAGEMENT ====================================
|
119
|
-
|
119
|
+
|
120
120
|
def active?
|
121
121
|
true
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
def reconnect!
|
125
125
|
connect
|
126
126
|
end
|
127
|
-
|
128
|
-
|
127
|
+
|
128
|
+
|
129
129
|
# DATABASE STATEMENTS ======================================
|
130
|
-
|
130
|
+
|
131
131
|
def select_all(soql, name = nil) #:nodoc:
|
132
132
|
log(soql, name)
|
133
133
|
|
134
134
|
records = @connection.query(:queryString => soql).queryResponse.result.records
|
135
135
|
|
136
136
|
records = [ records ] unless records.is_a?(Array)
|
137
|
-
|
137
|
+
|
138
138
|
result = []
|
139
139
|
records.each do |record|
|
140
140
|
attributes = Salesforce::SObjectAttributes.new(columns_map(record[:type]), record)
|
@@ -143,46 +143,59 @@ module ActiveRecord
|
|
143
143
|
|
144
144
|
result
|
145
145
|
end
|
146
|
-
|
146
|
+
|
147
147
|
def select_one(sql, name = nil) #:nodoc:
|
148
148
|
result = select_all(sql, name)
|
149
149
|
result.nil? ? nil : result.first
|
150
150
|
end
|
151
|
-
|
151
|
+
|
152
152
|
def create(sobject, name = nil) #:nodoc:
|
153
153
|
result = @connection.create(sobject).createResponse.result
|
154
154
|
|
155
|
-
raise SalesforceError, result
|
155
|
+
raise SalesforceError, result[:errors].message unless result[:success] == "true"
|
156
156
|
|
157
|
-
|
157
|
+
result[:id]
|
158
158
|
end
|
159
159
|
|
160
160
|
def update(sobject, name = nil) #:nodoc:
|
161
161
|
result = @connection.update(sobject).updateResponse.result
|
162
|
-
|
163
|
-
raise SalesforceError, result
|
162
|
+
|
163
|
+
raise SalesforceError, result[:errors].message unless result[:success] == "true"
|
164
164
|
|
165
165
|
# @connection.affected_rows
|
166
166
|
end
|
167
|
-
|
168
|
-
alias_method :delete, :update
|
169
167
|
|
168
|
+
def delete(ids)
|
169
|
+
puts "Delete #{ids}"
|
170
|
+
|
171
|
+
|
172
|
+
result = @connection.delete(:ids => ids).deleteResponse.result
|
173
|
+
|
174
|
+
raise SalesforceError, result[:errors].message unless result[:success] == "true"
|
175
|
+
end
|
176
|
+
|
170
177
|
def columns(table_name, name = nil)
|
171
|
-
|
178
|
+
cached_columns = @columns_map[table_name]
|
179
|
+
return cached_columns if cached_columns
|
180
|
+
|
181
|
+
puts "describeSObject(#{table_name})"
|
182
|
+
|
183
|
+
cached_columns = []
|
184
|
+
@columns_map[table_name] = cached_columns
|
172
185
|
|
173
186
|
metadata = @connection.describeSObject(:sObjectType => table_name).describeSObjectResponse.result
|
174
187
|
|
175
188
|
metadata.fields.each do |field|
|
176
|
-
|
189
|
+
cached_columns << SalesforceColumn.new(field)
|
177
190
|
end
|
178
191
|
|
179
|
-
|
192
|
+
cached_columns
|
180
193
|
end
|
181
|
-
|
194
|
+
|
182
195
|
def columns_map(table_name, name = nil)
|
183
196
|
columns_map = @columns_name_map[table_name]
|
184
197
|
return columns_map if columns_map
|
185
|
-
|
198
|
+
|
186
199
|
columns_map = {}
|
187
200
|
@columns_name_map[table_name] = columns_map
|
188
201
|
|
@@ -190,23 +203,23 @@ module ActiveRecord
|
|
190
203
|
|
191
204
|
columns_map
|
192
205
|
end
|
193
|
-
|
206
|
+
|
194
207
|
private
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
end
|
207
|
-
result.free
|
208
|
-
rows
|
208
|
+
|
209
|
+
def select(sql, name = nil)
|
210
|
+
puts "select(#{sql}, (#{name}))"
|
211
|
+
@connection.query_with_result = true
|
212
|
+
result = execute(sql, name)
|
213
|
+
rows = []
|
214
|
+
if @null_values_in_each_hash
|
215
|
+
result.each_hash { |row| rows << row }
|
216
|
+
else
|
217
|
+
all_fields = result.fetch_fields.inject({}) { |fields, f| fields[f.name] = nil; fields }
|
218
|
+
result.each_hash { |row| rows << all_fields.dup.update(row) }
|
209
219
|
end
|
220
|
+
result.free
|
221
|
+
rows
|
222
|
+
end
|
210
223
|
end
|
211
224
|
end
|
212
225
|
end
|
data/test/unit/account_test.rb
CHANGED
@@ -1,17 +1,14 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '../../config/boot')
|
2
|
-
|
3
|
-
require_gem 'activesalesforce'
|
4
|
-
require 'salesforce_connection_adapter'
|
5
|
-
|
6
2
|
require File.dirname(__FILE__) + '/../test_helper'
|
7
3
|
|
8
|
-
|
4
|
+
require 'pp'
|
9
5
|
|
10
6
|
class AccountTest < Test::Unit::TestCase
|
11
7
|
def setup
|
12
8
|
ActiveRecord::Base.allow_concurrency = true
|
13
9
|
end
|
14
10
|
|
11
|
+
|
15
12
|
def test_get_account
|
16
13
|
accounts = Account.find(:all)
|
17
14
|
|
@@ -33,12 +30,37 @@ class AccountTest < Test::Unit::TestCase
|
|
33
30
|
|
34
31
|
acme.save
|
35
32
|
end
|
33
|
+
|
36
34
|
|
37
35
|
def test_create_account
|
38
36
|
dutchCo = Account.new
|
39
37
|
dutchCo.Name = "DutchCo"
|
40
38
|
dutchCo.Website = "www.dutchco.com"
|
41
39
|
dutchCo.save
|
40
|
+
|
41
|
+
dutchCo2 = Account.new(:Name => "DutchCo2", :Website => "www.dutchco2.com")
|
42
|
+
dutchCo2.save
|
43
|
+
|
44
|
+
dutchCo3 = Account.create(:Name => "DutchCo3", :Website => "www.dutchco3.com")
|
45
|
+
|
46
|
+
accounts = Account.create([
|
47
|
+
{ :Name => "DutchCo4", :Website => "www.dutchco4.com" },
|
48
|
+
{ :Name => "DutchCo5", :Website => "www.dutchco5.com" }])
|
42
49
|
end
|
43
|
-
|
50
|
+
|
51
|
+
|
52
|
+
def test_destroy_account
|
53
|
+
account = Account.create(:Name => "DutchADelete", :Website => "www.dutchcodelete.com")
|
54
|
+
account = Account.find_by_Id(account.Id)
|
55
|
+
|
56
|
+
pp account.Parent
|
57
|
+
|
58
|
+
puts "Getting CreatedBy"
|
59
|
+
createdBy = account.CreatedBy
|
60
|
+
createdBy = User.find_by_Id(account.CreatedById);
|
61
|
+
puts createdBy.Email
|
62
|
+
|
63
|
+
Account.delete(account.Id)
|
64
|
+
end
|
65
|
+
|
44
66
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: activesalesforce
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2006-01-
|
6
|
+
version: 0.0.4
|
7
|
+
date: 2006-01-22 00:00:00 -05:00
|
8
8
|
summary: ActiveSalesforce is an extension to the Rails Framework that allows for the dynamic creation and management of ActiveRecord objects through the use of Salesforce meta-data and uses a Salesforce.com organization as the backing store.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -12,7 +12,7 @@ email: dchasman@salesforce.com
|
|
12
12
|
homepage: http://rubyforge.org/projects/activesfdc/
|
13
13
|
rubyforge_project:
|
14
14
|
description:
|
15
|
-
autorequire:
|
15
|
+
autorequire: active_salesforce
|
16
16
|
default_executable:
|
17
17
|
bindir: bin
|
18
18
|
has_rdoc: true
|
@@ -31,6 +31,7 @@ files:
|
|
31
31
|
- lib/salesforce_login.rb
|
32
32
|
- lib/salesforce_active_record.rb
|
33
33
|
- lib/column_definition.rb
|
34
|
+
- lib/activesalesforce.rb
|
34
35
|
- lib/rforce.rb
|
35
36
|
- lib/sobject_attributes.rb
|
36
37
|
- lib/salesforce_connection_adapter.rb
|