HyperMesh gives your HyperReact components CRUD access to your server side ActiveRecord models, using the standard ActiveRecord API. In addition HyperMesh implements push notifications (via a number of possible technologies) so changes to records on the server are dynamically pushed to all authorised clients.
Its Isomorphic Ruby in action.
In other words one browser creates, updates, or destroys a model, and the changes are persisted in active record models and then broadcast to all other authorised clients.
- HyperMesh is built on top of HyperReact.
- HyperReact is a Ruby DSL (Domain Specific Language) to build React.js UI components in Ruby. As data changes on the client (either from user interactions or external events) HyperReact re-draws whatever parts of the display is needed.
- HyperMesh provides a flux dispatcher and data store backed by Rails Active Record models.
You access your model data in your HyperReact components just like you would on the server or in an ERB or HAML view file. - If an optional push transport is connected HyperMesh broadcasts any changes made to your ActiveRecord models as they are persisted on the server.
For example consider a simple model called Dictionary
which might be part of Wiktionary type app.
class Dictionary < ActiveRecord::Base
# attributes
# word: string
# definition: text
# pronunciation: string
scope :defined, -> { 'definition IS NOT NULL AND pronunciation IS NOT NULL' }
end
Here is a very simple HyperReact component that shows a random word from the dictionary:
class WordOfTheDay < React::Component::Base
def pick_entry!
# pick a random word and assign the selected record to entry
@entry = Dictionary.defined.all[rand(Dictionary.defined.count)]
force_update! # redraw our component when the word changes
# Notice that we use standard ActiveRecord constructs to select our
# random entry value
end
# pick an initial entry before we mount our component...
before_mount :pick_entry
# Again in our render block we use the standard ActiveRecord API, such
# as the 'defined' scope, and the 'word', 'pronunciation', and
# 'definition' attribute getters.
render(DIV) do
DIV { "total definitions: #{Dictionary.defined.count}" }
DIV do
DIV { @entry.word }
DIV { @entry.pronunciation }
DIV { @entry.definition }
BUTTON { 'pick another' }.on(:click) { pick_entry! }
end
end
For more complete examples with push updates checkout any of the apps in the examples
directory, or build your own in 5 minutes following one of the quickstart guides:
The easiest way to install is to use the hyper-rails
gem.
- Add
gem 'hyper-rails'
to your RailsGemfile
development section. - Install the Gem:
bundle install
- Run the generator:
bundle exec rails g hyperloop:install --hyper-mesh
(or use--all
to install all hyperloop gems) - Update the bundle:
bundle update
You will find a public
folder has been added to the app/models
folder. To access a model on the client, move it into the public directory. If you are on Rails 5, you will also need to move the application_record.rb
into the public directory.
You will also find an app/policies
folder with a simple access policy suited for development. Policies are how you will provide detailed access control to to your public models. More details here.
Once you have run the hyperloop installer you can move models to the app/models/public
directory and they will be accessible on both the server and client.
To have changes to your models on the server broadcast to authorized clients, add a HyperMesh initializer file and specify a transport. For example to setup a simple polled transport add this file:
# config/initializers/hyper_mesh.rb
HyperMesh.configuration do |config|
config.transport = :simple_poller
end
After restarting, and reloading your browsers you will see changes broadcast to the clients. You can also play with this by firing up a rails console, and creating, changing or destroying models at the console.
For setting up the other possible transports following one of these guides:
The above guides will work in most cases, but for complete details on configuration settings go here
HyperMesh uses a large subset of the ActiveRecord API modified only when necessary to accommodate the asynchronous nature of the client. You can access your ActiveRecord models just like you would in models, controllers, or in ERB or HAML view templates.
See this guide for details.
Warning currently the attributes
method is supported, but please do not use it as some details of the semantics will be changing in an upcoming release. Instead of foo.attributes[:xyz]
use foo.send('xyz')
for now.
By default scopes will be recalculated on the server. For simple scopes that do not use joins or includes no additional action needs to be taken to make scopes work with HyperMesh. For scopes that do use joins, or if you want to offload the scoping computation from the server to the client read more here.
Each application defines a number of channels and authorization policies for those channels and the data sent over the channels.
Policies are defined with Policy classes. These are similar and compatible with Pundit but you do not need to use the pundit gem (but can if you want.)
For complete details see Authorization Policies
-
No policy class:
If you don't define a policy file, nothing will happen because nothing will get connected.
By default HyperMesh will look for aApplicationPolicy
class. -
Wrong version of pusher-fake (pusher-fake/base vs. pusher-fake/rspec)
See the Pusher-Fake gem repo for details. -
Forgetting to add
require pusher
in application.js file
this results in an error like this:
Exception raised while rendering #<TopLevelRailsComponent:0x53e>
ReferenceError: Pusher is not defined
To resolve make sure you require 'pusher'
in your application.js file if using pusher. DO NOT require pusher from your components manifest as this will cause prerendering to fail.
-
No create/update/destroy policies
You must explicitly allow changes to the models to be made by the client. If you don't you will see 500 responses from the server when you try to update. To open all access do this in your application policy:allow_change(to: :all, on: [:create, :update, :destroy]) { true }
-
Cannot connect to real pusher account:
If you are trying to use a real pusher account (not pusher-fake) but see errors like this
pusher.self.js?body=1:62 WebSocket connection to
'wss://127.0.0.1/app/PUSHER_API_KEY?protocol=7&client=js&version=3.0.0&flash=false'
failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
Check to see if you are including the pusher-fake gem.
HyperMesh will always try to use pusher-fake if it sees the gem included. Remove it and you should be good to go. See issue #5 for more details.
-
Cannot connect with ActionCable. Make sure that
config.action_cable.allowed_request_origins
includes the url you use for development (including the port) and that you are usingPuma
. -
Attributes are not being converted from strings, or do not have their default values
Eager loading is probably turned off. HyperMesh needs to eager loadmodels/public
so it can find all the column information for all public models. -
When starting rails you get a message on the rails console
couldn't find file 'browser'
Hyper-React v0.10.0 removed the dependency on opal-browser. You will have to add the 'opal-browser' gem to your Gemfile. -
On page load you get a message yacking about super class mismatch for
DummyValue
You are still have the oldreactive-record
gem in your Gemfile, remove it from your gemfile and your components.rb manifest. -
On page load you get a message yacking about no method
session
fornil
You are still referencing the old reactive-ruby or reactrb gems either directly or indirectly though a gem like reactrb-router. Replace any gems likereactrb-router
withhyper-router
. You can also just removereactrb
, ashyper-react
will be included by thehyper-mesh
gem.
Sometimes you need to figure out what connections are available, or what attributes are readable etc.
Its usually all to do with your policies, but perhaps you just need a little investigation.
You can bring up a console within the controller context by browsing localhost:3000/rr/console
Note: change rr
to wherever you are mounting HyperMesh in your routes file.
Note: in rails 4, you will need to add the gem 'web-console' to your development section
Within the context you have access to session.id
and current acting_user
which you will need, plus some helper methods to reduce typing
-
Getting auto connection channels:
channels(session_id = session.id, user = acting_user)
e.g.channels
returns all channels connecting to this session and user
providing nil as the acting_user will test if connections can be made without there being a logged in user. -
Can a specific class connection be made:
can_connect?(channel, user = acting_user)
e.g.can_connect? Todo
returns true if current acting_user can connect to the Todo class
You can also provide the class name as a string. -
Can a specific instance connection be made:
can_connect?(channel, user = acting_user)
e.g.can_connect? Todo.first
returns true if current acting_user can connect to the first Todo model.
You can also provide the instance in the form 'Todo-123' -
What attributes are accessible for a model instance:
viewable_attributes(instance, user = acting_user)
-
Can the attribute be viewed:
view_permitted?(instance, attribute, user = acting_user)
-
Can a model be created/updated/destroyed:
create_permitted?(instance, user = acting_user)
e.g.create_permitted?(Todo.new, nil)
can anybody save a new todo?
e.g.destroy_permitted?(Todo.last)
can the acting_user destroy the last Todo
You can of course simulate server side changes to your models through this console like any other console. For example
Todo.new.save
will broadcast the changes to the Todo model to any authorized channels.
HyperMesh is the merger of reactive-record
and synchromesh
gems. As such a lot of the internal names are still using either ReactiveRecord or Synchromesh module names.
The original ReactiveRecord
specs were written in opal-rspec. These are being migrated to
use server rspec with isomorphic helpers. There are about 170 of the original tests left and to run these you
- cd to
reactive_record_spec/test_app
- do a bundle install/update as needed,
rake db:reset db:test:prepare
,- start the server:
bundle exec rails s
, - then visit
localhost:3000/spec-opal
.
If you want to help PLEASE consider spending an hour and migrate a spec file to the new format. You can
find examples by looking in the spec/reactive_record/
directory and matching to the original file in
reactive_record_test_app/spec_dont_run/moved_to_main_spec_dir
The remaining tests are run in the more traditional bundle exec rake
or
bundle exec rspec spec
You can run the specs in firefox by adding DRIVER=ff
(best for debugging.) You can add SHOW_LOGS=true
if running in poltergeist (the default) to see what is going on, but ff is a lot better for debug.
Bug reports and pull requests are welcome on GitHub at /~https://github.com/reactive-ruby/HyperMesh. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.