This gem is being developed as part of an internal proyect. It's constantly changing and is not ready for production usage. Use at your own risk!!
This gem provides realtime sync of Model data between a Rails 5 app and its web clients. It was inspired in meteor's ddp and minimongo for data syncing and client side storage. It uses new Rails 5 Action Cable to communicate with the server and sync collections in realtime.
Check the sample todo app that uses this gem with VueJS for rendering. Will try to upload more examples shortly.
On server-side, create a new channel (rails g cahnnel Test
) or modify existing one including ActionCableNotifications::Streams
module.
class TestChannel < ApplicationCable::Channel
include ActionCableNotifications::Channel
def subscribed
# Config streaming for Customer model with default options
stream_notifications_for Customer
# Can have more than one ActiveRecord model streaming per channel
stream_notifications_for Invoice,
model_options: {
scope: {
limit: 5,
order: :id,
select: [:id, :customer_id, :seller_id, :amount]
}
}
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
Method stream_notifications_for
receives the following parameters:
stream_notifications_for(model, options = {}, &block)
- model: (ActiveRecord model) - Specifies the model to be used for data fetching and event binding.
- options: (Hash) - Options to be used for configuracion. Default options are:
{
publication: model.model_name.collection, # Name of the pubsub stream
params: params, # Params sent when client subscribes
cache: false, # Turn off server-side cache of client-side data
model_options: {
actions: [:create, :update, :destroy], # Model callbacks to attach to
scope: :all # Default collection scope. Can be an ,Array or Hash
track_scope_changes: true # During model updates, checks if the changes affect scope inclusion of the resulting record
}
}
On client-side, you will need to create a subscription to the channel and then you can instantiate a Store and one or more Collections to keep the data synced with the server. You can register more than one store per application and more than one collection per store.
App.testChannel = App.cable.subscriptions.create("TestChannel", {
connected: function() {
return console.log("Connected")
},
disconnected: function() {
return console.log("Disconnected")
}
}
// Create a store
store = App.cableNotifications.registerStore('storeName')
// Create the collections and sync them with the server using testChannel
customersCollection = store.registerCollection('customers', App.testChannel)
invoicesCollection = store.registerCollection('invoices', App.testChannel)
That's it! Now you have customers and invoices collections available in your clients. Data will be available as an array in customersCollection.data and invoicesCollection.data objects.
Stores are groups of collections. They hold a list of available collections and its options for syncing with the server using channels subscriptions. They expose the following methods:
Called to register a new collection into the store. collectionName must be unique in the store. channelSubscription specifies which channel to use to sync with the server. Multiple collections can share the same channel for syncing. If no channel is specified, the collection will work standalone. You can always turn on syncing for a collection later using syncToChannel method.
By default, collectionName is used on the server side to identify the table on the DB. If you are using a different tablename, you can specify it in the tableName parameter.
Example:
customersCollection = store.registerCollection('customers', App.testChannel)
Used to sync a standalone collection with the server using a channel.
store.syncToChannel(App.testChannel, customersCollection)
Collections is where data is stored on clients. Collections can be standalone or synced with the server using channel subcriptions.
The registered collection object expose some methods to give easy access to data stored on clients. It uses lodash for data manipulation, so you can check its documentation for details on parameters.
Retrieves data from the server. You can specify a hash of parameters to send to server.
invoicesCollection.fetch({limit: 10, where: 'amount>100'})
Filter data already present in the client and return all records that met the field values specified in selector parameter. You can specify a hash of options or a callback function.
invoices = invoicesCollection.where({customer_id: 14})
Same as filter but returns only the first record found.
invoice = invoicesCollection.find({customer_id: 14})
Create a new record having the specified field values and sync it with the server.
invoice = invoicesCollection.create({customer_id: 14, seller_id: 5, amount: 100})
Updates an existing record identified by selector with the specified field values and sync it with the server.
invoice = invoicesCollection.update({id: 55},{seller_id: 6, amount: 150})
If an existing record cannot be found for updating, a new record is created with the specified fields.
invoice = invoicesCollection.upsert({id: 55},{seller_id: 6, amount: 150})
Destroys an existing record identified by selector and sync it with the server.
invoicesCollection.destroy({id: 55})
Received data will have the following format:
{
collection: 'users',
msg: 'upsert_many',
data: [
{
id: 1,
username: 'username 1',
color: 'red'
},
{
id: 2,
username: 'username 2',
color: 'green'
]
}
{
collection: 'users',
msg: 'create',
id: 3,
data: {
id: 3,
username: 'username 3'
color: 'blue'
}
}
Update event will only transmit changed fields for the model.
{
collection: 'users',
msg: 'update',
id: 2,
data: {
color: 'light blue'
}
}
{
collection: 'users',
msg: 'destroy',
id: 2
}
Add this line to your application's Gemfile:
gem 'action_cable_notifications'
And then execute:
$ bundle
Or install it yourself as:
$ gem install action_cable_notifications
Contributions are welcome. We will be happy to receive issues, comments and pull-request to make this gem better.
The gem is available as open source under the terms of the MIT License.