Project | Gem Release |
---|---|
Gem name | pliable |
License | MIT |
Version | |
Continuous Integration | |
Test Coverage | |
Grade | |
Dependencies | |
Homepage | http://mfpiccolo.github.io/pliable |
Documentation | http://rdoc.info/github/mfpiccolo/pliable/frames |
Issues | https://github.com/mfpiccolo/pliable/issues |
Pliable makes integrating a Rails project with Schemaless data not so painful.
Rolling your own integration with an external service where the schema can change from moment to moment can be tough. Pliable makes it a bit easier by giving you a familiar place to store this data (models backed by postgres) and familiar ways of interacting with it (Active Record objects, complete with associations).
Add this line to your application's Gemfile:
gem "pliable"
And then execute:
$ bundle
Or install it yourself as:
$ gem install pliable
Pliable allows you to save individual records from external schemaless databases into your postgres backed rails apps. We store all of the data in a plies table. The Ply model contains logic that allows you to inherit from Ply and then act as if these iherited models are normal Active Record models.
Here is the Ply model your generator created by running rails g pliable:models
:
class Ply < Pliable::Ply
# Define methods here that you want all you Ply backed models to have.
end
Now you can create a model that is backed by Ply.
class Foo < Ply
# This is redundant if it is the same name as the class but required for now.
ply_name "Foo"
# Define methods that you only want Foo to have.
end
Now lets make another Ply Backed Model.
class Bar < Ply
ply_name "Bar"
end
Now you should be able to treat these like any other Active Record object with the added bonus of a few features. You can assign any json data to the data attribute.
foo = Foo.create(data: {"some" => "json", "other" => "data"})
The nice part is now these json keys are methods.
foo.some => "json"
Another nicety is associations. You can associate a Ply inhereted class to another using parent and child relationships and the PlyRelations model
foo = Foo.create
bar = Bar.create
PlyRealation.create(parent_id: foo.id, parent_type: foo.class.name, child_id: bar, child_type: bar.class.name)
foo.bars => <#<ActiveRecord::AssociationRelation [#<Pliable::Ply id: 2 otype: "Bar" ...>
To use the generator run:
$ rails g pliable:model
This will set up pliable.rb initializer, create the migration and run it and add a Ply model and specs.
In the initializer, specify any aditional logic you need to prepare the ply_name for pluralization.
Pliable.configure do |config|
# Add logic to this bloc to change the names given by external services so we can pluralize.
# For instance if you ply names need to gsub __c of the end do:
config.added_scrubber {|name| name.gsub('__c', '') }
end
An example of a salesforce integration:
Here is your Ply model:
# Notice it inherits from Pliable::Ply
class Ply < Pliable::Ply
# Define methods here that you want all of your Ply inherited models to have
def anything_you_like
puts "I can play disco all night"
end
end
This is an example salesforce Invoice model:
# Notice it inherits from your apps Ply
class Invoice < Ply
# If you dont put this you will get all Ply records.
# This is the name that you have put into the otype attribute.
# In this example I just used the exact salesforce api name.
# This is also why we need the configuration to strip off "__c"
# for pluralization.
ply_name "Invoice__c"
# Add Invoice specific methods here
def what_dosnt_gather_moss?
puts "A rolling stone!"
end
end
Here is an example associated salesforce model:
class LineItem < Ply
ply_name "Line_Item__c"
# You guessed it. LineItem specific methods here.
def best_pliable_quote
puts "Facts are stubborn, but statistics are more pliable. - Mark Twain"
end
end
A service object for pulling salesforce data into your app:
class SalesforceSynch
attr_reader :user, :client
def initialize(user)
@user = user
end
def call
set_clients # Connect to your Salesforce data (i.e. databsedotcom or restforce)
create_plys_from_salesforce_records # Create records in your PG database using Ply model
create_ply_relations # Dynamically create associations based on the data recieved
end
def self.call
new.call
end
def set_clients
#Fake service object that sets up a client to connect to databasedotcom
@client = ConnectToDatabasedotcom.call(user.salesforce_credentials)
end
def create_plys_from_salesforce_records
records = []
# User has_many :plies in this example (i.e. user.plies)
client.get_the_records_you_want.each do |record|
object = user.plies.find_or_create_by(oid: record.Id)
object.update_attributes(
# The data attribute is a json column. This is where you store all shcemaless data.
data: record.attributes,
# Whatever the service calls the object (i.e. "Invoice__c" for salesforce)
otype: record.salesforce_api_name,
# Use last_checked and last_modified to know when you need to update a record
last_checked: Time.zone.now
)
end
end
# Dynamically deduce if there is a relationship with any of the plies that have been imported.
# In the case of saleforce the id of related object is stored by using the name of that
# object as a key. (ie "Invoice__c" => "long_uiniq_id"). In this app users choose a few models
# that they want to bring over (i.e user.model_names).
user.plies.each do |ply|
related_model_names = ply.instance_variables.map {|e| e.to_s.gsub("@", "") } & user.model_names
related_model_names.each do |name|
child = Ply.find_by_oid(ply.send(name.to_sym))
unless PlyRelation.where(parent_id: record.id, child_id: child.id).present?
ply.children.new(
parent_id: ply.id,
parent_type: ply.otype,
child_id: ply.id,
child_type: ply.otype
).save # #create does not work yet. Sorry
end
end
end
end
end
Now with this setup you can run something like this
SalesforceSynch.call(@user) # Awesome. You just imported all your salesforce data.
invoice = Invoice.first => #<Invoice id: 1, user_id: 1, oid: "randomnumber", otype: "Invoice__c",
# data: {"Id"=>"a00i000000BbWLvAAN", "OwnerId"=>"005i0000002NdyWAAS", "Owner"=>nil...}...>
invoice.line_items => #<ActiveRecord::AssociationRelation [#<Pliable::Ply id: 2 ...>
invoice.line_items.first.invoices.find(invoice.id) === invoice => true
invoice.SalesForceCustomAttribute__c => # Whatever it is in salesforce.
Invoice.all => #<ActiveRecord::Relation [#<Invoice id: 136, user_id: 1...>
LineItem.first => #<LineItem id: 145, user_id: 1...>
Invoice.find_by_oid("random_oid_number") => #<Invoice id: 132, user_id: 1, oid: "rand...">
# All the normal active-recordy goodness
Support this project and others by mfpiccolo via gittip.
Copyright (c) 2013 Mike Piccolo
See LICENSE.txt for details.
- Fork it ( http://github.com//pliable/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request