{"id":48337,"date":"2013-02-28T13:32:15","date_gmt":"2013-02-28T10:32:15","guid":{"rendered":"https:\/\/www.altoros.com\/blog\/?p=48337"},"modified":"2021-09-20T21:06:57","modified_gmt":"2021-09-20T18:06:57","slug":"websocket-rails-gem","status":"publish","type":"post","link":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/","title":{"rendered":"WebSocket for a Ruby-on-Rails App"},"content":{"rendered":"<p>I\u2019d like to look at a relatively new project on GitHub called <a href=\"https:\/\/github.com\/websocket-rails\/websocket-rails\" rel=\"noopener noreferrer\" target=\"_blank\">websocket-rails<\/a> built on top of <a href=\"http:\/\/faye.jcoglan.com\" rel=\"noopener noreferrer\" target=\"_blank\">Faye<\/a> (it&#8217;s a Ruby version), <a href=\"https:\/\/github.com\/eventmachine\/eventmachine\">EventMachine<\/a>, and <a href=\"https:\/\/www.altoros.com\/research-papers\/redis-as-a-service-performance-benchmark-redis-cloud-elasticache-openredis-redisgreen-and-redis-to-go\/\">Redis<\/a> for data storage. In short, the <code style=\"color: black; background-color: #e6e6e6;\">websocket-rails<\/code> gem is a Ruby-on-Rails implementation for the <a href=\"http:\/\/www.websocket.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">WebSocket<\/a> protocol with a number of fallbacks, including an implementation of Flash sockets. It provides a very cool tool for building client-side apps. After all, \u201cWebSocket represents the next evolutionary step in web communication compared to Comet and Ajax.\u201d<\/p>\n<p>&nbsp;<\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-transparent ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#Installation\" >Installation<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#Routes\" >Routes<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#Controllers\" >Controllers<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#The_client_dispatcher_code\" >The client dispatcher code<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#Even_more_functionality\" >Even more functionality<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#Conclusion\" >Conclusion<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#Further_reading\" >Further reading<\/a><\/li><\/ul><\/nav><\/div>\n<h3><span class=\"ez-toc-section\" id=\"Installation\"><\/span>Installation<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>If your app is running on any server supporting threads, such as Thin or Puma, you can dive right into using WebSocket by adding <code style=\"color: black; background-color: #e6e6e6;\">gem 'websocket-rails'<\/code> to your Gemfile. Otherwise, there is an option of using <a href=\"https:\/\/github.com\/websocket-rails\/websocket-rails\/wiki\/Standalone-Server-Mode\">a standalone WebSocket server<\/a>.<\/p>\n<p>The gem comes with a simple <b>get started<\/b> generator. Run <code style=\"color: black; background-color: #e6e6e6;\">rails g websocket_rails:install<\/code>. It will create an <code style=\"color: black; background-color: #e6e6e6;\">events.rb<\/code> initializer, as well as require JavaScript in your <code style=\"color: black; background-color: #e6e6e6;\">application.js<\/code>.<\/p>\n<p>To see the gem in development, the official installation instructions advise to enable the <code style=\"color: black; background-color: #e6e6e6;\">config.threadsafe!<\/code> configuration in <code style=\"color: black; background-color: #e6e6e6;\">development.rb<\/code> (naturally, it is absolutely necessary for production). Unfortunately, this option prevents the app from reloading the code while the page refreshes.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Routes\"><\/span>Routes<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>A WebSocket analog for routes in this gem is called <code style=\"color: black; background-color: #e6e6e6;\">events<\/code>. A generator creates the <code style=\"color: black; background-color: #e6e6e6;\">events.rb<\/code> file heavily reminding <code style=\"color: black; background-color: #e6e6e6;\">routes.rb<\/code>. Its generated version is sparingly commented, and the syntax is quite simple, with <code style=\"color: black; background-color: #e6e6e6;\">subscribe<\/code> as an analog for <code style=\"color: black; background-color: #e6e6e6;\">match<\/code>.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nWebsocketRails::EventMap.describe do\r\n  namespace :chat_messages do\r\n    subscribe :create, to: Sockets::ChatMessagesController, with_method: :create\r\n  end\r\nend\r\n<\/pre>\n<p>It doesn\u2019t have any more complex helpers, such as <code style=\"color: black; background-color: #e6e6e6;\">resources<\/code>, yet. By default, WebSocket controllers don\u2019t enforce REST. So, the <code style=\"color: black; background-color: #e6e6e6;\">create<\/code> method name appearing later in this article makes me stick to \u201cmy comfort zone\u201d conventions. Whether to stick to the show-create-update-destroy scheme is still an open question.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Controllers\"><\/span>Controllers<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><code style=\"color: black; background-color: #e6e6e6;\">websocket-rails<\/code> provides an API that may seem familiar to any Ruby-on-Rails developer. The API features a tree of controllers inherited from a common source and routes-ish events. <a href=\"https:\/\/github.com\/jimsynz\/faye-rails\" rel=\"noopener noreferrer\" target=\"_blank\">faye-rails<\/a>, which is a different take on Faye, clutters <code style=\"color: black; background-color: #e6e6e6;\">routes.rb<\/code> and requires more configuration. Let\u2019s look at a simple sockets controller.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nclass Sockets::ChatMessagesController &amp;lt; WebsocketRails::BaseController\r\n\r\n  def initialize_session\r\n    @message_sent = 0\r\n  end\r\n\r\n  def create\r\n    if can? :create, ChatMessage\r\n      chat_message = ChatMessage.create(event.data) do |message| \r\n        message.user = current_user\r\n      end\r\n      if chat_message\r\n        @messages_sent += 1\r\n        trigger_success( message: 'Message created' )\r\n        broadcast_message :created, chat_message,\r\n             namespace: :chat_messages\r\n      else\r\n        trigger_failure( message: chat_message.errors.full_messages.join(' ') )\r\n      end\r\n    else\r\n     trigger_failure( message: 'Unauthorized' )\r\n    end\r\n  end\r\n\r\nend\r\n<\/pre>\n<p>First thing we can see above is the fact that WebSocket controllers are inherited from <code style=\"color: black; background-color: #e6e6e6;\">WebsocketRails::BaseController<\/code>. What differs this controller from the rest of the application is the fact that its instance is created once on the server start, and any WebSocket request is redirected to this very instance. It means that instance variables, such as <code style=\"color: black; background-color: #e6e6e6;\">@messages_sent<\/code>, are shared across requests.<\/p>\n<p>This controller, in fact, is not related to <code style=\"color: black; background-color: #e6e6e6;\">ActionController<\/code>, so it doesn\u2019t provide any Ruby-on-Rails controllers&#8217; goodness (redirects, responders, and callbacks) we are accustomed to rely on. Where does <code style=\"color: black; background-color: #e6e6e6;\">can?<\/code> come from then? <code style=\"color: black; background-color: #e6e6e6;\">websocket-rails<\/code> uses <code style=\"color: black; background-color: #e6e6e6;\">method_missing<\/code> to delegate undefined instance methods to <code style=\"color: black; background-color: #e6e6e6;\">DelegationController<\/code> inherited from <code style=\"color: black; background-color: #e6e6e6;\">ApplicationController<\/code>. In other words, WebSocket controllers have access to any controller instance helper methods. Adopting any class-enchancing logic, for example, <code style=\"color: black; background-color: #e6e6e6;\">load_and_authorize_resource<\/code> from the same <a href=\"https:\/\/github.com\/ryanb\/cancan\" rel=\"noopener noreferrer\" target=\"_blank\">CanCan<\/a> gem can be troublesome, though. That prevents us from just plainly reusing the existing controller code. Minor inconvinience at worst, or a problem to solve.<\/p>\n<p>The gem also features a number of responders. A couple of them return action status to a request initializer (<code style=\"color: black; background-color: #e6e6e6;\">trigger_success<\/code>, and <code style=\"color: black; background-color: #e6e6e6;\">trigger_failure<\/code>, as well as <code style=\"color: black; background-color: #e6e6e6;\">flash[:status]<\/code> analogs). A couple more methods initialize events in client JavaScript. <code style=\"color: black; background-color: #e6e6e6;\">send_message<\/code> affects one client, a requester by default. <code style=\"color: black; background-color: #e6e6e6;\">broadcast_message<\/code> affects a range of connected clients, all of them by default.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"The_client_dispatcher_code\"><\/span>The client dispatcher code<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Any rich internet application typically features much more client-side code than the server code. <code style=\"color: black; background-color: #e6e6e6;\">websocket-rails<\/code> applications don\u2019t make an exception, but at least they try. First, we need to open a WebSocket connection from JavaScript.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndispatcher = new WebSocketRails('localhost:3000\/websockets');\r\n<\/pre>\n<p>The gem takes care of mounting the route, and it is the default path on a local server. Note that the request protocol is not specified, it is resolved depending on which one is best supported by the browser. The request sent this way creates an instance of the <code style=\"color: black; background-color: #e6e6e6;\">WebsocketRails::ConnectionManager<\/code> server side, transporting browser cookies and storing them (so, all the requests through that connection use the same <code style=\"color: black; background-color: #e6e6e6;\">session_id<\/code>). <code style=\"color: black; background-color: #e6e6e6;\">ConnectionManagers<\/code> also persist in memory, silently taking care of all the hard work until the server is stopped, or the client closes a connection.<\/p>\n<p>All we need to do now is trigger events as shown below.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n...\r\nfailure_callback = function(message) { \r\n\tconsole.log(message); \r\n}\r\ndispatcher.trigger('chat_messages.create', new_message_object,\r\n\tsuccess_callback, failure_callback);\r\n<\/pre>\n<p>Then, we receive the events.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndispatcher.bind('chat_messages.created', insertNewMessageSomewhere);\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Even_more_functionality\"><\/span>Even more functionality<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Broadcasting events to all clients can be expensive in resources, insecure, etc. Intuition tells, checking user abilities to create each chat message is an overkill, as well. For this purpose, <code style=\"color: black; background-color: #e6e6e6;\">websocket-rails<\/code> implements the <a href=\"https:\/\/github.com\/websocket-rails\/websocket-rails\/wiki\/Working-with-Channels\">Channel<\/a> mechanism. Channels feature their own authorization mechanism. So, you can create and destroy these mechanisms in runtime, while subscribing clients to them in JavaScript. This allows, for example, to narrow message broadcasting to channels. Additionally, there exists a possibility to broadcast to specific channels from any place in the rest of the app (<code style=\"color: black; background-color: #e6e6e6;\">ApplicationController<\/code> descendants, model callbacks, or delayed processess).<\/p>\n<p>Another interesting documented feature is <a href=\"https:\/\/github.com\/websocket-rails\/websocket-rails\/wiki\/Using-the-DataStore\" rel=\"noopener noreferrer\" target=\"_blank\">DataStore<\/a>. <code style=\"color: black; background-color: #e6e6e6;\">WebsocketRails::BaseController<\/code> instance variables persist between different user requests. So, how to store a data specific for each user\/connection? For the purpose, the <code style=\"color: black; background-color: #e6e6e6;\">data_store<\/code> helper is used. A minor feature, but the same helper can be used to aggregate data from all open connections.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>After all, it is a library built on an unstable, \u2018not-quite-yet-specified-standards\u2019 technology. Nevertheless, it is relatively easy to start using the gem in Ruby-on-Rails. It wraps low-level tinkering with EventMachine, maintaining connections on both sides\u2014server and client. It goes out of its way to be as much compatible with the rest of the application as possible (one can wish for more, though). It even adds some helpers of its own. It is supposedly easy to teach the gem to maintain synchronization between server instances. Last but not the least, it is already thoroughly tested with <a href=\"https:\/\/github.com\/rspec\/rspec-rails\" rel=\"noopener noreferrer\" target=\"_blank\">RSpec<\/a> and <a href=\"https:\/\/jasmine.github.io\/\" rel=\"noopener noreferrer\" target=\"_blank\">Jasmine<\/a>.<\/p>\n<p><code style=\"color: black; background-color: #e6e6e6;\">websocket-rails<\/code> doesn\u2019t have an extensive set of plugins, or documented best practices, or recipes. It must be quite buggy, too. However, I believe that (provided no better analog appears) it will evolve very fast. It just means that we have an excellent opportunity to influence how these best practices will look like.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Further_reading\"><\/span>Further reading<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<ul>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/commonjs-for-rails\/\">CommonJS for Ruby on Rails<\/a><\/li>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/email-on-rails\/\">E-mails in Ruby on Rails<\/a><\/li>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/running-capybara-tests-for-ruby-applications-in-remote-browsers\/\">Running Capybara Tests for Ruby Apps in Remote Browsers<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Easy to get started websocket gem for rich Rails application.<\/p>\n","protected":false},"author":119,"featured_media":58284,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":"","_links_to":"","_links_to_target":""},"categories":[214],"tags":[1000,895],"class_list":["post-48337","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-github","tag-research-and-development"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>WebSocket for a Ruby-on-Rails App | Altoros<\/title>\n<meta name=\"description\" content=\"Supported by code samples, this blog post explores how to quickly start with the websocket-rails gem in a Ruby-on-Rails app.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"WebSocket for a Ruby-on-Rails App | Altoros\" \/>\n<meta property=\"og:description\" content=\"Easy to get started websocket gem for rich Rails application.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/\" \/>\n<meta property=\"og:site_name\" content=\"Altoros\" \/>\n<meta property=\"article:published_time\" content=\"2013-02-28T10:32:15+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-09-20T18:06:57+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/02\/websocket-ruby-on-rails.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"576\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Dmitry Savitski\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dmitry Savitski\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/\"},\"author\":{\"name\":\"Dmitry Savitski\",\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/#\\\/schema\\\/person\\\/a787fe0020308b728e68ad4a4ff571ca\"},\"headline\":\"WebSocket for a Ruby-on-Rails App\",\"datePublished\":\"2013-02-28T10:32:15+00:00\",\"dateModified\":\"2021-09-20T18:06:57+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/\"},\"wordCount\":1128,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/wp-content\\\/uploads\\\/2013\\\/02\\\/websocket-ruby-on-rails.png\",\"keywords\":[\"GitHub\",\"Research and Development\"],\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/\",\"url\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/\",\"name\":\"WebSocket for a Ruby-on-Rails App | Altoros\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/wp-content\\\/uploads\\\/2013\\\/02\\\/websocket-ruby-on-rails.png\",\"datePublished\":\"2013-02-28T10:32:15+00:00\",\"dateModified\":\"2021-09-20T18:06:57+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/#\\\/schema\\\/person\\\/a787fe0020308b728e68ad4a4ff571ca\"},\"description\":\"Easy to get started websocket gem for rich Rails application.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/wp-content\\\/uploads\\\/2013\\\/02\\\/websocket-ruby-on-rails.png\",\"contentUrl\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/wp-content\\\/uploads\\\/2013\\\/02\\\/websocket-ruby-on-rails.png\",\"width\":1024,\"height\":576},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/websocket-rails-gem\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"WebSocket for a Ruby-on-Rails App\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/\",\"name\":\"Altoros\",\"description\":\"Insight\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/#\\\/schema\\\/person\\\/a787fe0020308b728e68ad4a4ff571ca\",\"name\":\"Dmitry Savitski\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/07\\\/dmitry-savitski-96x96.jpeg\",\"url\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/07\\\/dmitry-savitski-96x96.jpeg\",\"contentUrl\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/07\\\/dmitry-savitski-96x96.jpeg\",\"caption\":\"Dmitry Savitski\"},\"description\":\"Dmitry Savitski is a software engineer at Altoros. He specializes in web development using Ruby and JavaScript as his primary tools. Dmitry has a keen interest in the 12-factor application approach and the ways in which different Cloud Foundry implementations\u2014including Predix\u2014support this methodology.\",\"url\":\"https:\\\/\\\/www.altoros.com\\\/blog\\\/author\\\/dmitry-savitski\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"WebSocket for a Ruby-on-Rails App | Altoros","description":"Supported by code samples, this blog post explores how to quickly start with the websocket-rails gem in a Ruby-on-Rails app.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/","og_locale":"en_US","og_type":"article","og_title":"WebSocket for a Ruby-on-Rails App | Altoros","og_description":"Easy to get started websocket gem for rich Rails application.","og_url":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/","og_site_name":"Altoros","article_published_time":"2013-02-28T10:32:15+00:00","article_modified_time":"2021-09-20T18:06:57+00:00","og_image":[{"width":1024,"height":576,"url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/02\/websocket-ruby-on-rails.png","type":"image\/png"}],"author":"Dmitry Savitski","twitter_misc":{"Written by":"Dmitry Savitski","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#article","isPartOf":{"@id":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/"},"author":{"name":"Dmitry Savitski","@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/a787fe0020308b728e68ad4a4ff571ca"},"headline":"WebSocket for a Ruby-on-Rails App","datePublished":"2013-02-28T10:32:15+00:00","dateModified":"2021-09-20T18:06:57+00:00","mainEntityOfPage":{"@id":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/"},"wordCount":1128,"commentCount":0,"image":{"@id":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#primaryimage"},"thumbnailUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/02\/websocket-ruby-on-rails.png","keywords":["GitHub","Research and Development"],"articleSection":["Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/","url":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/","name":"WebSocket for a Ruby-on-Rails App | Altoros","isPartOf":{"@id":"https:\/\/www.altoros.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#primaryimage"},"image":{"@id":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#primaryimage"},"thumbnailUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/02\/websocket-ruby-on-rails.png","datePublished":"2013-02-28T10:32:15+00:00","dateModified":"2021-09-20T18:06:57+00:00","author":{"@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/a787fe0020308b728e68ad4a4ff571ca"},"description":"Easy to get started websocket gem for rich Rails application.","breadcrumb":{"@id":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#primaryimage","url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/02\/websocket-ruby-on-rails.png","contentUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/02\/websocket-ruby-on-rails.png","width":1024,"height":576},{"@type":"BreadcrumbList","@id":"https:\/\/www.altoros.com\/blog\/websocket-rails-gem\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.altoros.com\/blog\/"},{"@type":"ListItem","position":2,"name":"WebSocket for a Ruby-on-Rails App"}]},{"@type":"WebSite","@id":"https:\/\/www.altoros.com\/blog\/#website","url":"https:\/\/www.altoros.com\/blog\/","name":"Altoros","description":"Insight","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.altoros.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/a787fe0020308b728e68ad4a4ff571ca","name":"Dmitry Savitski","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/07\/dmitry-savitski-96x96.jpeg","url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/07\/dmitry-savitski-96x96.jpeg","contentUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/07\/dmitry-savitski-96x96.jpeg","caption":"Dmitry Savitski"},"description":"Dmitry Savitski is a software engineer at Altoros. He specializes in web development using Ruby and JavaScript as his primary tools. Dmitry has a keen interest in the 12-factor application approach and the ways in which different Cloud Foundry implementations\u2014including Predix\u2014support this methodology.","url":"https:\/\/www.altoros.com\/blog\/author\/dmitry-savitski\/"}]}},"_links":{"self":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/48337","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/users\/119"}],"replies":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/comments?post=48337"}],"version-history":[{"count":15,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/48337\/revisions"}],"predecessor-version":[{"id":63581,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/48337\/revisions\/63581"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/media\/58284"}],"wp:attachment":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/media?parent=48337"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/categories?post=48337"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/tags?post=48337"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}