activesalesforce 0.2.6 → 0.2.7

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/lib/asf_adapter.rb CHANGED
@@ -44,18 +44,25 @@ module ActiveRecord
44
44
 
45
45
  # Establishes a connection to the database that's used by all Active Record objects.
46
46
  def self.activesalesforce_connection(config) # :nodoc:
47
- puts "Using ActiveSalesforce connection!"
47
+ puts "\nUsing ActiveSalesforce connection\n"
48
48
 
49
49
  url = config[:url]
50
50
  sid = config[:sid]
51
+ binding = config[:binding] if config[:binding]
51
52
 
53
+ if binding
54
+ puts " via provided binding #{binding}\n"
55
+ #pp binding
56
+ end
57
+
52
58
  if sid
53
- connection = @@cache["sid=#{sid}"]
54
- unless connection
59
+ binding = @@cache["sid=#{sid}"] unless binding
60
+
61
+ unless binding
55
62
  puts "Establishing new connection for [sid='#{sid}']"
56
63
 
57
- connection = RForce::Binding.new(url, sid)
58
- @@cache["sid=#{sid}"] = connection
64
+ binding = RForce::Binding.new(url, sid)
65
+ @@cache["sid=#{sid}"] = binding
59
66
 
60
67
  puts "Created new connection for [sid='#{sid}']"
61
68
  end
@@ -71,19 +78,20 @@ module ActiveRecord
71
78
  username = config[:username]
72
79
  password = config[:password]
73
80
 
74
- connection = @@cache["#{url}.#{username}.#{password}"]
75
- unless connection
81
+ binding = @@cache["#{url}.#{username}.#{password}"] unless binding
82
+
83
+ unless binding
76
84
  puts "Establishing new connection for ['#{url}', '#{username}']"
77
85
 
78
- connection = RForce::Binding.new(url)
79
- connection.login(username, password).result
86
+ binding = RForce::Binding.new(url, sid)
87
+ binding.login(username, password).result
80
88
 
81
- @@cache["#{url}.#{username}.#{password}"] = connection
89
+ @@cache["#{url}.#{username}.#{password}"] = binding
82
90
 
83
91
  puts "Created new connection for ['#{url}', '#{username}']"
84
92
  end
85
93
 
86
- ConnectionAdapters::SalesforceAdapter.new(connection, logger, [url, username, password], config)
94
+ ConnectionAdapters::SalesforceAdapter.new(binding, logger, [url, username, password, sid], config)
87
95
  end
88
96
  end
89
97
  end
@@ -98,7 +106,7 @@ module ActiveRecord
98
106
 
99
107
  @fault = fault
100
108
 
101
- logger.debug("\nSalesforceError:\n message='#{message}'\n fault='#{fault}'\n\n")
109
+ logger.debug("\nSalesforceError:\n message='#{message}'\n fault='#{fault}'\n\n") if logger
102
110
  end
103
111
  end
104
112
 
@@ -290,8 +298,8 @@ module ActiveRecord
290
298
  values = values.scan(/(((NULL))|((TRUE))|((FALSE))|'(([^']|'')*)'),*/mi)
291
299
 
292
300
  values.map! { |v| v[7] }
293
-
294
- fields = get_fields(columns, names, values)
301
+
302
+ fields = get_fields(columns, names, values, :createable)
295
303
 
296
304
  sobject = create_sobject(entity_name, nil, fields)
297
305
 
@@ -314,7 +322,7 @@ module ActiveRecord
314
322
  values = match.scan(/=\s*(((NULL))|((TRUE))|((FALSE))|'(([^']|'')*)'),*/mi)
315
323
  values.map! { |v| v[7] }
316
324
 
317
- fields = get_fields(columns, names, values)
325
+ fields = get_fields(columns, names, values, :updateable)
318
326
 
319
327
  id = sql.match(/WHERE\s+id\s*=\s*'(\w+)'/i)[1]
320
328
 
@@ -341,13 +349,11 @@ module ActiveRecord
341
349
  ids_element = []
342
350
  ids.each { |id| ids_element << :ids << id }
343
351
 
344
- pp ids_element
345
-
346
352
  check_result(get_result(@connection.delete(ids_element), :delete))
347
353
  end
348
354
 
349
355
 
350
- def get_fields(columns, names, values)
356
+ def get_fields(columns, names, values, access_check)
351
357
  fields = {}
352
358
  names.each_with_index do | name, n |
353
359
  value = values[n]
@@ -359,7 +365,8 @@ module ActiveRecord
359
365
 
360
366
  value.gsub!(/''/, "'") if value.is_a? String
361
367
 
362
- fields[column.api_name] = value unless column.readonly or value.empty?
368
+ include_field = ((not value.empty?) and column.send(access_check))
369
+ fields[column.api_name] = value if include_field
363
370
  end
364
371
  end
365
372
 
@@ -404,15 +411,18 @@ module ActiveRecord
404
411
  custom = true
405
412
  end
406
413
 
407
- metadata.fields.each do |field|
414
+ metadata[:fields].each do |field|
408
415
  column = SalesforceColumn.new(field)
409
416
  cached_columns << column
410
417
 
411
418
  cached_relationships << SalesforceRelationship.new(field, column) if field[:type] =~ /reference/i
412
419
  end
413
420
 
414
- if metadata.childRelationships
415
- metadata.childRelationships.each do |relationship|
421
+ relationships = metadata[:childRelationships]
422
+ if relationships
423
+ relationships = [ relationships ] unless relationships.is_a? Array
424
+
425
+ relationships.each do |relationship|
416
426
  if relationship[:cascadeDelete] == "true"
417
427
  r = SalesforceRelationship.new(relationship)
418
428
  cached_relationships << r
@@ -443,28 +453,40 @@ module ActiveRecord
443
453
  referenceName = relationship.name
444
454
  unless self.respond_to? referenceName.to_sym or relationship.reference_to == "Profile"
445
455
  reference_to = relationship.reference_to
456
+ one_to_many = relationship.one_to_many
457
+ foreign_key = relationship.foreign_key
458
+
459
+ # DCHASMAN TODO Figure out how to handle polymorphic refs (e.g. Note.parent can refer to
460
+ # Account, Contact, Opportunity, Contract, Asset, Product2, <CustomObject1> ... <CustomObject(n)>
461
+ if reference_to.is_a? Array
462
+ puts " Skipping unsupported polymophic one-to-#{one_to_many ? 'many' : 'one' } relationship '#{referenceName}' from #{entity_name} to [#{relationship.reference_to.join(', ')}] using #{foreign_key}"
463
+ next
464
+ end
465
+
466
+ # Handle references to custom objects
467
+ if reference_to.match(/__c$/)
468
+ reference_to.chop!.chop!.chop!
469
+ reference_to.capitalize!
470
+ end
446
471
 
447
472
  begin
448
- reference_to.constantize
473
+ referenced_klass = reference_to.constantize
449
474
  rescue NameError => e
450
475
  # Automatically create a least a stub for the referenced entity
476
+ puts " Creating ActiveRecord stub for the referenced entity '#{reference_to}'"
477
+
451
478
  referenced_klass = klass.class_eval("::#{reference_to} = Class.new(ActiveRecord::Base)")
452
- referenced_klass.connection = klass.connection
453
- #configure_active_record(get_entity_def(reference_to))
454
479
 
455
- puts "Created ActiveRecord stub for the referenced entity '#{reference_to}'"
480
+ # configure_active_record(get_entity_def(reference_to))
456
481
  end
457
-
458
- one_to_many = relationship.one_to_many
459
- foreign_key = relationship.foreign_key
460
-
482
+
461
483
  if one_to_many
462
484
  klass.has_many referenceName.to_sym, :class_name => reference_to, :foreign_key => foreign_key, :dependent => false
463
485
  else
464
486
  klass.belongs_to referenceName.to_sym, :class_name => reference_to, :foreign_key => foreign_key, :dependent => false
465
487
  end
466
488
 
467
- puts "Created one-to-#{one_to_many ? 'many' : 'one' } relationship '#{referenceName}' from #{entity_name} to #{relationship.reference_to} using #{foreign_key}"
489
+ puts " Created one-to-#{one_to_many ? 'many' : 'one' } relationship '#{referenceName}' from #{entity_name} to #{relationship.reference_to} using #{foreign_key}"
468
490
 
469
491
  end
470
492
  end
@@ -38,7 +38,7 @@ module ActiveRecord
38
38
  class SalesforceColumn < Column
39
39
  include StringHelper
40
40
 
41
- attr_reader :api_name, :custom, :label, :readonly, :reference_to
41
+ attr_reader :api_name, :custom, :label, :createable, :updateable, :reference_to
42
42
 
43
43
  def initialize(field)
44
44
  @api_name = field[:name]
@@ -51,7 +51,8 @@ module ActiveRecord
51
51
  @text = [:string, :text].include? @type
52
52
  @number = [:float, :integer].include? @type
53
53
 
54
- @readonly = (field[:updateable] != "true" or field[:createable] != "true")
54
+ @createable = field[:createable] == "true"
55
+ @updateable = field[:updateable] == "true"
55
56
 
56
57
  if field[:type] =~ /reference/i
57
58
  @reference_to = field[:referenceTo]
@@ -0,0 +1,76 @@
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 'yaml'
25
+ require File.dirname(__FILE__) + '/rforce'
26
+
27
+
28
+ class MockBinding < RForce::Binding
29
+ attr_reader :recorded_responses
30
+
31
+ #Connect to the server securely.
32
+ def initialize(url, sid, recording)
33
+ @recording = recording
34
+ @recorded_responses = {}
35
+
36
+ super(url, sid) if @recording
37
+ end
38
+
39
+
40
+ def save(f)
41
+ YAML.dump(@recorded_responses, f)
42
+ end
43
+
44
+
45
+ def load(f)
46
+ @recorded_responses = YAML.load(f)
47
+ end
48
+
49
+
50
+ #Call a method on the remote server. Arguments can be
51
+ #a hash or (if order is important) an array of alternating
52
+ #keys and values.
53
+ def call_remote(method, args)
54
+ # Star-out any passwords
55
+ safe_args = args.inject([]) {|memo, v| memo << (memo.last == :password ? "*" * v.length : v) }
56
+ key = "#{method}(#{safe_args.join(':')})"
57
+
58
+ if @recording
59
+ response = super(method, args)
60
+ @recorded_responses[key] = response
61
+ else
62
+ response = @recorded_responses[key]
63
+
64
+ unless response
65
+ @recorded_responses.each do |request, reponse|
66
+ #pp request
67
+ end
68
+
69
+ raise "Unable to find matching response for recorded request '#{key}'"
70
+ end
71
+ end
72
+
73
+ response
74
+ end
75
+
76
+ end
@@ -45,12 +45,28 @@ module ActiveRecord
45
45
  if source[:childSObject]
46
46
  relationship = source
47
47
 
48
- @api_name = relationship[:relationshipName] ? relationship[:relationshipName] : relationship[:field].chop.chop
49
- @one_to_many = relationship[:relationshipName] != nil
48
+ if relationship[:relationshipName]
49
+ @api_name = relationship[:relationshipName]
50
+ @one_to_many = true
51
+ @label = @api_name
52
+ @name = column_nameize(@api_name)
53
+ @custom = false
54
+ else
55
+ @api_name = relationship[:field]
56
+ @one_to_many = relationship[:cascadeDelete] == "true"
57
+ @label = relationship[:childSObject].pluralize
58
+ @custom = relationship[:childSObject].match(/__c$/)
59
+
60
+ name = relationship[:childSObject]
61
+ name.chop!.chop!.chop! if custom
62
+
63
+ @name = column_nameize(name.pluralize)
64
+ end
65
+
50
66
  @reference_to = relationship[:childSObject]
51
- @label = @name
67
+
52
68
  @foreign_key = column_nameize(relationship[:field])
53
- @custom = false
69
+ @foreign_key.chop!.chop! << "id__c" if @foreign_key.match(/__c$/)
54
70
  else
55
71
  field = source
56
72
 
@@ -60,15 +76,12 @@ module ActiveRecord
60
76
  @api_name = @api_name.chop.chop unless @custom
61
77
 
62
78
  @label = field[:label]
63
- @readonly = (field[:updateable] != "true" or field[:createable] != "true")
64
79
  @reference_to = field[:referenceTo]
65
80
  @one_to_many = false
66
81
 
67
82
  @foreign_key = column.name
83
+ @name = column_nameize(@api_name)
68
84
  end
69
-
70
- @name = column_nameize(@api_name)
71
-
72
85
  end
73
86
  end
74
87
 
data/lib/rforce.rb CHANGED
@@ -150,7 +150,7 @@ module RForce
150
150
 
151
151
 
152
152
  #Connect to the server securely.
153
- def initialize(url, sid = nil)
153
+ def initialize(url, sid)
154
154
  init_server(url)
155
155
 
156
156
  @session_id = sid
@@ -184,10 +184,10 @@ module RForce
184
184
 
185
185
  raise "Incorrect user name / password [#{response.fault}]" unless response.loginResponse
186
186
 
187
- result = response.loginResponse.result
188
- @session_id = result.sessionId
187
+ result = response[:loginResponse][:result]
188
+ @session_id = result[:sessionId]
189
189
 
190
- init_server(result.serverUrl)
190
+ init_server(result[:serverUrl])
191
191
 
192
192
  response
193
193
  end
@@ -0,0 +1,99 @@
1
+ require 'rubygems'
2
+
3
+ #require_gem 'activesalesforce', '>= 0.2.6'
4
+ require 'activesalesforce'
5
+
6
+ require 'recorded_test_case'
7
+ require 'pp'
8
+
9
+
10
+ class Contact < ActiveRecord::Base
11
+ end
12
+
13
+
14
+
15
+ module Asf
16
+ module UnitTests
17
+
18
+ class BasicTest < Test::Unit::TestCase
19
+ include RecordedTestCase
20
+
21
+ attr_reader :contact
22
+
23
+ def initialize(test_method_name)
24
+ super(test_method_name)
25
+
26
+ #force_recording :test_get_created_by_from_contact
27
+ end
28
+
29
+ def setup
30
+ puts "\nStarting test '#{self.class.name.gsub('::', '')}.#{method_name}'"
31
+
32
+ super
33
+
34
+ @contact = Contact.new
35
+ contact.first_name = 'DutchTestFirstName'
36
+ contact.last_name = 'DutchTestLastName'
37
+ contact.home_phone = '555-555-1212'
38
+ contact.save
39
+
40
+ contact.reload
41
+ end
42
+
43
+ def teardown
44
+ contact.destroy if contact
45
+
46
+ super
47
+ end
48
+
49
+ def test_count_contacts
50
+ assert_equal 27, Contact.count
51
+ end
52
+
53
+ def test_create_a_contact
54
+ contact.id
55
+ end
56
+
57
+ def test_save_a_contact
58
+ contact.id
59
+ end
60
+
61
+ def test_find_a_contact
62
+ c = Contact.find(contact.id)
63
+ assert_equal contact.id, c.id
64
+ end
65
+
66
+ def test_find_a_contact_by_id
67
+ c = Contact.find_by_id(contact.id)
68
+ assert_equal contact.id, c.id
69
+ end
70
+
71
+ def test_find_a_contact_by_first_name
72
+ c = Contact.find_by_first_name('DutchTestFirstName')
73
+ assert_equal contact.id, c.id
74
+ end
75
+
76
+ def test_read_all_content_columns
77
+ Contact.content_columns.each { |column| contact.send(column.name) }
78
+ end
79
+
80
+ def test_get_created_by_from_contact
81
+ user = contact.created_by
82
+ assert_equal contact.created_by_id, user.id
83
+ end
84
+
85
+ def test_add_notes_to_contact
86
+ n1 = Note.new(:title => "My Title", :body => "My Body")
87
+ n2 = Note.new(:title => "My Title 2", :body => "My Body 2")
88
+
89
+ contact.notes << n1
90
+ contact.notes << n2
91
+
92
+ n1.save
93
+ n2.save
94
+ end
95
+
96
+ end
97
+
98
+ end
99
+ end