Skip to content

Commit

Permalink
Feature/rails 7 and adding features (#3)
Browse files Browse the repository at this point in the history
* Add support for Rails 7. Update dependencies and namespacing for Faraday errors. Bump version file. Remove codeclimate dependency.

* Add ActiveModel::Type where they can be inferred from salesforce when generating model files.

* Add namespace command line option. Call `classify` on class name to remove underscores. Remove unneeded monkey patch and call `underscore` from ActiveSupport.

* Set the `table_name` in the model generator.

* Add `has_one` association and a ProjectionBuilder for it.

* Move towards using the `attributes` from ActiveModel rather than custom ones.

* Add get/set via `[]` and `[]=` just like in ActiveRecord.

* Sort the attributes by `:name` so they are easier to read after running the model generator.

* Add a couple more delegators.

* Exclude vendor and spec directories from SimpleCov configuration.

* Update CHANGELOG for new release.
  • Loading branch information
asedge authored Feb 3, 2023
1 parent ba81ef4 commit b3cab9f
Show file tree
Hide file tree
Showing 20 changed files with 290 additions and 94 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

## Not released

## 0.9.0

* Add support for Rails 7 and update Restforce dependency to newer version. (https://github.com/Beyond-Finance/active_force/pull/3)
* Add `has_one` association. (https://github.com/Beyond-Finance/active_force/pull/3)
* Model generator enhancements (https://github.com/Beyond-Finance/active_force/pull/3):
* automatically add types to fields
* sort fields alphabetically
* add `table_name` to class
* add optional namespace parameter so generated models can be namespaced
* Add get/set via `[]` and `[]=` for `SObject` attributes. (https://github.com/Beyond-Finance/active_force/pull/3)

## 0.7.1

* Allow sfdc_client to be set. ([#92][])
Expand Down
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
source 'https://rubygems.org'

# Specify your gem's dependencies in active_force.gemspec
gem "codeclimate-test-reporter", group: :test, require: nil
gemspec
24 changes: 19 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
A ruby gem to interact with [SalesForce][1] as if it were Active Record. It
uses [Restforce][2] to interact with the API, so it is fast and stable.

### Heroku Fork
### Beyond Finance Fork

This version is forked from the work done by
https://github.com/ionia-corporation/active_force with upgrades for Rails 5, as
https://github.com/heroku/active_force which was in turn forked from
https://github.com/ionia-corporation/active_force.
It includes upgrades for Rails 7, as
well as additional functionality.

## Installation

Add this line to your application's `Gemfile`:

gem 'active_force', github: "heroku/active_force"
gem 'active_force', github: "Beyond-Finance/active_force"

And then execute:

Expand Down Expand Up @@ -100,6 +102,10 @@ Altenative you can try the generator. (requires setting up the connection)

rails generate active_force_model Medication__c

The model generator also supports an optional namespace which will add a namespace to the generated model

rails generate active_force_model Medication__c SomeNamespace

### Associations

#### Has Many
Expand All @@ -123,6 +129,14 @@ class Account < ActiveForce::SObject
end
```

#### Has One

```ruby
class Car < ActiveForce::SObject
has_one :engine, model: CarEngine
end
```

#### Belongs to

```ruby
Expand Down Expand Up @@ -169,12 +183,12 @@ class Account < ActiveForce::SObject
def self.decorate account_records
# Perform other API call once for all account_records ids
other_things = OtherAPI.find_things_with_ids(account_records.map{ |a| a["Id"] } )
account_records.map do |a|
account_records.map do |a|
# Find other_thing that corresponds to the current account_record
other_thing_for_account = other_things.detect{ |o| o["Id"] == a["Id"]}

# make updates to each record
a.merge_in_other_stuff(other_thing_for_account)
a.merge_in_other_stuff(other_thing_for_account)
end # the mapped array will be returned
end
end
Expand Down
7 changes: 3 additions & 4 deletions active_force.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = '>= 1.9.3'

spec.add_dependency 'activemodel', '~> 5.2'
spec.add_dependency 'activesupport', '~> 5.2'
spec.add_dependency 'restforce', '~> 2.5'
spec.add_development_dependency 'bundler', '~> 1.16'
spec.add_dependency 'activemodel', '~> 7.0'
spec.add_dependency 'activesupport', '~> 7.0'
spec.add_dependency 'restforce', '>= 5'
spec.add_development_dependency 'rake', '>= 0'
spec.add_development_dependency 'rspec', '>= 0'
spec.add_development_dependency 'pry', '>= 0'
Expand Down
2 changes: 1 addition & 1 deletion lib/active_force/active_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class ActiveQuery < Query
attr_reader :sobject

def_delegators :sobject, :sfdc_client, :build, :table_name, :mappings
def_delegators :to_a, :each, :map, :inspect
def_delegators :to_a, :each, :map, :inspect, :pluck, :each_with_object

def initialize sobject
@sobject = sobject
Expand Down
5 changes: 5 additions & 0 deletions lib/active_force/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'active_force/association/eager_load_projection_builder'
require 'active_force/association/relation_model_builder'
require 'active_force/association/has_many_association'
require 'active_force/association/has_one_association'
require 'active_force/association/belongs_to_association'

module ActiveForce
Expand All @@ -21,6 +22,10 @@ def has_many relation_name, options = {}
associations[relation_name] = HasManyAssociation.new(self, relation_name, options)
end

def has_one relation_name, options = {}
associations[relation_name] = HasOneAssociation.new(self, relation_name, options)
end

def belongs_to relation_name, options = {}
associations[relation_name] = BelongsToAssociation.new(self, relation_name, options)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/active_force/association/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def foreign_key
end

def relationship_name
options[:relationship_name] || relation_model.table_name
options[:relationship_name] || relation_model.to_s.constantize.table_name
end

###
Expand Down
8 changes: 8 additions & 0 deletions lib/active_force/association/eager_load_projection_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ def projections
end
end

class HasOneAssociationProjectionBuilder < AbstractProjectionBuilder
def projections
query = Query.new association.sfdc_association_field
query.fields association.relation_model.fields
["(#{query.to_s})"]
end
end

class BelongsToAssociationProjectionBuilder < AbstractProjectionBuilder
def projections
association.relation_model.fields.map do |field|
Expand Down
29 changes: 29 additions & 0 deletions lib/active_force/association/has_one_association.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module ActiveForce
module Association
class HasOneAssociation < Association
private

def default_foreign_key
infer_foreign_key_from_model @parent
end

def define_relation_method
association = self
_method = @relation_name
@parent.send :define_method, _method do
association_cache.fetch(_method) do
association_cache[_method] = association.relation_model.to_s.constantize.find_by(association.foreign_key => self.id)
end
end

@parent.send :define_method, "#{_method}=" do |other|
value_to_set = other.nil? ? nil : self.id
# Do we change the object that was passed in or do we modify the already associated object?
obj_to_change = value_to_set ? other : self.send(association.relation_name)
obj_to_change.send "#{ association.foreign_key }=", value_to_set
association_cache[_method] = other
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/active_force/association/relation_model_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def call

class BuildFromNilClass < AbstractBuildFrom
def call
association.is_a?(BelongsToAssociation) ? nil : []
association.is_a?(HasManyAssociation) ? [] : nil
end
end

Expand Down
30 changes: 0 additions & 30 deletions lib/active_force/attributable.rb

This file was deleted.

34 changes: 16 additions & 18 deletions lib/active_force/sobject.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
require 'active_model'
require 'active_force/active_query'
require 'active_force/attributable'
require 'active_force/association'
require 'active_force/mapping'
require 'yaml'
Expand All @@ -12,11 +11,12 @@ module ActiveForce
class RecordInvalid < StandardError;end

class SObject
include ActiveModel::API
include ActiveModel::AttributeMethods
include ActiveModel::Attributes
include ActiveModel::Model
include ActiveModel::Dirty
extend ActiveModel::Callbacks
include ActiveForce::Attributable
extend ActiveForce::Association

define_model_callbacks :build, :create, :update, :save, :destroy
Expand Down Expand Up @@ -82,7 +82,7 @@ def update_attributes! attributes = {}

def update_attributes attributes = {}
update_attributes! attributes
rescue Faraday::Error::ClientError, RecordInvalid => error
rescue Faraday::ClientError, RecordInvalid => error
handle_save_error error
end

Expand All @@ -101,7 +101,7 @@ def create!

def create
create!
rescue Faraday::Error::ClientError, RecordInvalid => error
rescue Faraday::ClientError, RecordInvalid => error
handle_save_error error
self
end
Expand Down Expand Up @@ -132,7 +132,7 @@ def save!

def save
save!
rescue Faraday::Error::ClientError, RecordInvalid => error
rescue Faraday::ClientError, RecordInvalid => error
handle_save_error error
end

Expand All @@ -146,25 +146,15 @@ def persisted?

def self.field field_name, args = {}
mapping.field field_name, args
cast_type = args.fetch(:as, :string)
attribute field_name, cast_type
define_attribute_methods field_name
define_attribute_reader field_name
define_attribute_writer field_name, args
end

def modified_attributes
attributes.select{ |attr, key| changed.include? attr.to_s }
end

def self.attribute_names
mapping.mappings.keys.map(&:to_s)
end

def attributes
mappings.keys.each_with_object(Hash.new) do |field, hsh|
hsh[field.to_s] = self.send(field)
end
end

def reload
association_cache.clear
reloaded = self.class.find(id)
Expand All @@ -187,6 +177,14 @@ def write_value key, value
send "#{field}=", value if field && respond_to?(field)
end

def [](name)
send(name.to_sym)
end

def []=(name,value)
send("#{name.to_sym}=", value)
end

private

def validate!
Expand All @@ -209,7 +207,7 @@ def association_cache
def logger_output action, exception, params = {}
logger = Logger.new(STDOUT)
logger.info("[SFDC] [#{self.class.model_name}] [#{self.class.table_name}] Error while #{ action }, params: #{params}, error: #{exception.inspect}")
errors[:base] << exception.message
errors.add(:base, exception.message)
false
end

Expand Down
2 changes: 1 addition & 1 deletion lib/active_force/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module ActiveForce
VERSION = "0.8.3"
VERSION = "0.9.0"
end
Loading

0 comments on commit b3cab9f

Please sign in to comment.