Skip to content
This repository has been archived by the owner on May 25, 2018. It is now read-only.

Commit

Permalink
Add section to the README documentating running the rails environment…
Browse files Browse the repository at this point in the history
… without starting a server, also using the Redis engine, for good measure. #1. #23.
  • Loading branch information
jimsynz committed Jan 9, 2013
1 parent 7263922 commit 3b10e29
Showing 1 changed file with 84 additions and 54 deletions.
138 changes: 84 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,58 +6,70 @@ faye-rails is a Ruby gem which handles embedding Faye's rack-based server into t

Due to the limitations of most Rack-based web servers available Faye can only be run on Thin, however if you are using thin, then you can add as many Faye servers as you want to the Rails router like so:

App::Application.routes.draw do
faye_server '/faye', :timeout => 25
end
```ruby
App::Application.routes.draw do
faye_server '/faye', :timeout => 25
end
```

You can also pass a block to `faye_server` which will be executed in the context of the Faye server, thus you can call any methods on `Faye::RackAdapter` from within the block:

App::Application.routes.draw do
faye_server '/faye', :timeout => 25 do
class MockExtension
def incoming(message, callback)
callback.call(message)
end
end
add_extension(MockExtension.new)
```ruby
App::Application.routes.draw do
faye_server '/faye', :timeout => 25 do
class MockExtension
def incoming(message, callback)
callback.call(message)
end
end
add_extension(MockExtension.new)
end
end
```

If you really want to, you can ask Faye to start it's own listening Thin server on an arbitrary port:

App::Application.routes.draw do
faye_server '/faye', :timeout => 25 do
listen(9292)
end
end
```ruby
App::Application.routes.draw do
faye_server '/faye', :timeout => 25 do
listen(9292)
end
end
```

You can also do some rudimentary routing using the map method:

App::Application.routes.draw do
faye_server '/faye', :timeout => 25 do
map '/widgets/**' => WidgetsController
map :default => :block
end
end
```ruby
App::Application.routes.draw do
faye_server '/faye', :timeout => 25 do
map '/widgets/**' => WidgetsController
map :default => :block
end
end
```

You can find more details on the #map method in the [rdoc](http://rubydoc.info/github/jamesotron/faye-rails/master/FayeRails/RackAdapter)

# Controller

faye-rails includes a controller for handling the binding between model events and channels with it's own DSL for managing channel-based events.

class WidgetController < FayeRails::Controller
end
```ruby
class WidgetController < FayeRails::Controller
end
```

## Model observers

You can subscribe to changes in models using the controller's observer DSL:

class WidgetController < FayeRails::Controller
observe Widget, :after_create do |new_widget|
WidgetController.publish('/widgets', new_widget.attributes)
end
end
```ruby
class WidgetController < FayeRails::Controller
observe Widget, :after_create do |new_widget|
WidgetController.publish('/widgets', new_widget.attributes)
end
end
```

The available callbacks are derived from the ActiveRecord callback stack. See [ActiveRecord::Callbacks](http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html) for more information regarding the callback queue.

Expand All @@ -71,46 +83,64 @@ The controller DSL elegantly wraps channel-based aspects of the Faye API so that

You can make use of Faye's [monitoring API](http://faye.jcoglan.com/ruby/monitoring.html) by adding calls to `monitor` within the channel block. You are able to monitor `:subscribe`, `:unsubscribe` and `:publish` events. Blocks are executed within the context of a `FayeRails::Controller::Monitor` instance which will give you access to `#client_id`, `#channel` and `#data` (`#data` only having a value on `:publish` events).

class WidgetController < FayeRails::Controller
channel '/widgets' do
monitor :subscribe do
puts "Client #{client_id} subscribed to #{channel}."
end
monitor :unsubscribe do
puts "Client #{client_id} unsubscribed from #{channel}."
end
monitor :publish do
puts "Client #{client_id} published #{data.inspect} to #{channel}."
end
end
```ruby
class WidgetController < FayeRails::Controller
channel '/widgets' do
monitor :subscribe do
puts "Client #{client_id} subscribed to #{channel}."
end
monitor :unsubscribe do
puts "Client #{client_id} unsubscribed from #{channel}."
end
monitor :publish do
puts "Client #{client_id} published #{data.inspect} to #{channel}."
end
end
end
```

### Filtering

You can quickly and easily filter incoming and outgoing messages for your specific channel using the controller's filter API, which wraps Faye's [extensions API](http://faye.jcoglan.com/ruby/extensions.html) in a concise and channel-specific way.

class WidgetController < FayeRails::Controller
channel '/widgets' do
filter :in do
puts "Inbound message #{message}."
pass
end
end
```ruby
class WidgetController < FayeRails::Controller
channel '/widgets' do
filter :in do
puts "Inbound message #{message}."
pass
end
end
end
```

You can add filters for `:in`, `:out` and `:any`, which will allow you to filter messages entering the server, exiting the server or both. The block passed to the `filter` is executed in the context of a `FayeRails::Filter::DSL` instance, which gives you access to the `#message` method, which contains the entire message payload from the client (including meta information you wouldn't see other ways). You also have access to the `#pass`, `#modify`, `#block` and `#drop` methods which are sugar around Faye's callback system - which is accessible via the `#callback` method if you want to do it that way. Check out the [FayeRails::Filter::DSL rdoc](http://rubydoc.info/github/jamesotron/faye-rails/master/FayeRails/Filter/DSL) for more information. Please note that all filters must call `callback.call` either via the sugar methods or directly to ensure that requests are not lost (not to mention potential memory leaks).

### Subscribing

You can easily subscribe to a channel using the 'subscribe' method inside your channel block, like so:

class WidgetController < FayeRails::Controller
channel '/widgets' do
subscribe do
puts "Received on channel #{channel}: #{message.inspect}"
end
end
```ruby
class WidgetController < FayeRails::Controller
channel '/widgets' do
subscribe do
puts "Received on channel #{channel}: #{message.inspect}"
end
end
end
```

# Non-server environments

Often you'll find yourself running the Rails environment without the server running - eg when doing background job processing, or running the console. If you have any actions which use Faye then you'll need to make sure that you have the EventMachine reactor running. The easiest solution to this is to create an initialiser in `config/initializers` which calls `Faye.ensure_reactor_running!`. For workers in production you probably also want to make sure that you are using the Redis engine for Faye to ensure that multiple server instances see the same data.

```ruby
App::Application.routes.draw do
faye_server '/faye', timeout: 25, engine: {type: Faye::Redis, host: 'localhost'} do
map '/announce/**' => SomeController
end
end
```

# Thanks.

Expand Down

1 comment on commit 3b10e29

@deemytch
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear (for me) where to put such code App::Application.routes.draw do, also I get error NoMethodError: undefined method 'faye_server' for #<ActionDispatch::Routing::Mapper:0x0000000465d9a8>

I try to put that in config/initializers/faye.rb, config/application.rb outside and inside the module and then in class Application

Dmenu::Application.routes.draw do
  faye_server '/quick', :timeout => 25, engine: {type: Faye::Redis, host: Rails.configuration.redis_host } do
      map '/registerapp/**' => ManageTabletsController
      map :default => :block
  end
end

Please sign in to comment.