{"id":26112976,"url":"https://github.com/fzingg/hyperloop-showcase","last_synced_at":"2026-02-16T09:37:41.556Z","repository":{"id":139654314,"uuid":"81452799","full_name":"fzingg/hyperloop-showcase","owner":"fzingg","description":"A simple Rails 5.0.1 app showcasing HyperReact, HyperMesh, Opal and associated technologies","archived":false,"fork":false,"pushed_at":"2017-02-23T10:36:50.000Z","size":1149,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-01-20T15:14:53.354Z","etag":null,"topics":["hyper-rails","hyperloop","isomorphic","opal","rails-application","react-components","webpack"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fzingg.png","metadata":{"files":{"readme":"README.html","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-02-09T13:26:27.000Z","updated_at":"2017-10-23T15:57:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"9fafdfc6-5c9e-4f91-980e-2da0b2170e98","html_url":"https://github.com/fzingg/hyperloop-showcase","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fzingg/hyperloop-showcase","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzingg%2Fhyperloop-showcase","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzingg%2Fhyperloop-showcase/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzingg%2Fhyperloop-showcase/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzingg%2Fhyperloop-showcase/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fzingg","download_url":"https://codeload.github.com/fzingg/hyperloop-showcase/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzingg%2Fhyperloop-showcase/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29504900,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T09:05:14.864Z","status":"ssl_error","status_checked_at":"2026-02-16T08:55:59.364Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hyper-rails","hyperloop","isomorphic","opal","rails-application","react-components","webpack"],"created_at":"2025-03-10T03:54:33.918Z","updated_at":"2026-02-16T09:37:41.549Z","avatar_url":"https://github.com/fzingg.png","language":"JavaScript","readme":"\u003c!DOCTYPE html\u003e\u003chtml\u003e\u003chead\u003e\u003cmeta charset=\"utf-8\"\u003e\u003cstyle\u003ebody {\n  width: 45em;\n  border: 1px solid #ddd;\n  outline: 1300px solid #fff;\n  margin: 16px auto;\n}\n\nbody .markdown-body\n{\n  padding: 30px;\n}\n\n@font-face {\n  font-family: fontawesome-mini;\n  src: url(data:font/woff;charset=utf-8;base64,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) format('woff');\n}\n\n@font-face {\n  font-family: octicons-anchor;\n  src: url(data:font/woff;charset=utf-8;base64,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) format('woff');\n}\n\n.markdown-body {\n  font-family: sans-serif;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n  color: #333333;\n  overflow: hidden;\n  font-family: \"Helvetica Neue\", Helvetica, \"Segoe UI\", Arial, freesans, sans-serif;\n  font-size: 16px;\n  line-height: 1.6;\n  word-wrap: break-word;\n}\n\n.markdown-body a {\n  background: transparent;\n}\n\n.markdown-body a:active,\n.markdown-body a:hover {\n  outline: 0;\n}\n\n.markdown-body b,\n.markdown-body strong {\n  font-weight: bold;\n}\n\n.markdown-body mark {\n  background: #ff0;\n  color: #000;\n  font-style: italic;\n  font-weight: bold;\n}\n\n.markdown-body sub,\n.markdown-body sup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n.markdown-body sup {\n  top: -0.5em;\n}\n.markdown-body sub {\n  bottom: -0.25em;\n}\n\n.markdown-body h1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n.markdown-body img {\n  border: 0;\n}\n\n.markdown-body hr {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n  height: 0;\n}\n\n.markdown-body pre {\n  overflow: auto;\n}\n\n.markdown-body code,\n.markdown-body kbd,\n.markdown-body pre,\n.markdown-body samp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n.markdown-body input {\n  color: inherit;\n  font: inherit;\n  margin: 0;\n}\n\n.markdown-body html input[disabled] {\n  cursor: default;\n}\n\n.markdown-body input {\n  line-height: normal;\n}\n\n.markdown-body input[type=\"checkbox\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\n\n.markdown-body table {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\n.markdown-body td,\n.markdown-body th {\n  padding: 0;\n}\n\n.markdown-body .codehilitetable {\n  border: 0;\n  border-spacing: 0;\n}\n\n.markdown-body .codehilitetable tr {\n  border: 0;\n}\n\n.markdown-body .codehilitetable pre,\n.markdown-body .codehilitetable div.codehilite {\n  margin: 0;\n}\n\n.markdown-body .linenos,\n.markdown-body .code,\n.markdown-body .codehilitetable td {\n  border: 0;\n  padding: 0;\n}\n\n.markdown-body td:not(.linenos) .linenodiv {\n  padding: 0 !important;\n}\n\n.markdown-body .code {\n  width: 100%;\n}\n\n.markdown-body .linenos div pre,\n.markdown-body .linenodiv pre,\n.markdown-body .linenodiv {\n  border: 0;\n  -webkit-border-radius: 0;\n  -moz-border-radius: 0;\n  border-radius: 0;\n  -webkit-border-top-left-radius: 3px;\n  -webkit-border-bottom-left-radius: 3px;\n  -moz-border-radius-topleft: 3px;\n  -moz-border-radius-bottomleft: 3px;\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n\n.markdown-body .code div pre,\n.markdown-body .code div {\n  border: 0;\n  -webkit-border-radius: 0;\n  -moz-border-radius: 0;\n  border-radius: 0;\n  -webkit-border-top-right-radius: 3px;\n  -webkit-border-bottom-right-radius: 3px;\n  -moz-border-radius-topright: 3px;\n  -moz-border-radius-bottomright: 3px;\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n\n.markdown-body * {\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n.markdown-body input {\n  font: 13px Helvetica, arial, freesans, clean, sans-serif, \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n  line-height: 1.4;\n}\n\n.markdown-body a {\n  color: #4183c4;\n  text-decoration: none;\n}\n\n.markdown-body a:hover,\n.markdown-body a:focus,\n.markdown-body a:active {\n  text-decoration: underline;\n}\n\n.markdown-body hr {\n  height: 0;\n  margin: 15px 0;\n  overflow: hidden;\n  background: transparent;\n  border: 0;\n  border-bottom: 1px solid #ddd;\n}\n\n.markdown-body hr:before,\n.markdown-body hr:after {\n  display: table;\n  content: \" \";\n}\n\n.markdown-body hr:after {\n  clear: both;\n}\n\n.markdown-body h1,\n.markdown-body h2,\n.markdown-body h3,\n.markdown-body h4,\n.markdown-body h5,\n.markdown-body h6 {\n  margin-top: 15px;\n  margin-bottom: 15px;\n  line-height: 1.1;\n}\n\n.markdown-body h1 {\n  font-size: 30px;\n}\n\n.markdown-body h2 {\n  font-size: 21px;\n}\n\n.markdown-body h3 {\n  font-size: 16px;\n}\n\n.markdown-body h4 {\n  font-size: 14px;\n}\n\n.markdown-body h5 {\n  font-size: 12px;\n}\n\n.markdown-body h6 {\n  font-size: 11px;\n}\n\n.markdown-body blockquote {\n  margin: 0;\n}\n\n.markdown-body ul,\n.markdown-body ol {\n  padding: 0;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body ol ol,\n.markdown-body ul ol {\n  list-style-type: lower-roman;\n}\n\n.markdown-body ul ul ol,\n.markdown-body ul ol ol,\n.markdown-body ol ul ol,\n.markdown-body ol ol ol {\n  list-style-type: lower-alpha;\n}\n\n.markdown-body dd {\n  margin-left: 0;\n}\n\n.markdown-body code,\n.markdown-body pre,\n.markdown-body samp {\n  font-family: Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n  font-size: 12px;\n}\n\n.markdown-body pre {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body kbd {\n  background-color: #e7e7e7;\n  background-image: -moz-linear-gradient(#fefefe, #e7e7e7);\n  background-image: -webkit-linear-gradient(#fefefe, #e7e7e7);\n  background-image: linear-gradient(#fefefe, #e7e7e7);\n  background-repeat: repeat-x;\n  border-radius: 2px;\n  border: 1px solid #cfcfcf;\n  color: #000;\n  padding: 3px 5px;\n  line-height: 10px;\n  font: 11px Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n  display: inline-block;\n}\n\n.markdown-body\u003e*:first-child {\n  margin-top: 0 !important;\n}\n\n.markdown-body\u003e*:last-child {\n  margin-bottom: 0 !important;\n}\n\n.markdown-body .headeranchor-link {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  display: block;\n  padding-right: 6px;\n  padding-left: 30px;\n  margin-left: -30px;\n}\n\n.markdown-body .headeranchor-link:focus {\n  outline: none;\n}\n\n.markdown-body h1,\n.markdown-body h2,\n.markdown-body h3,\n.markdown-body h4,\n.markdown-body h5,\n.markdown-body h6 {\n  position: relative;\n  margin-top: 1em;\n  margin-bottom: 16px;\n  font-weight: bold;\n  line-height: 1.4;\n}\n\n.markdown-body h1 .headeranchor,\n.markdown-body h2 .headeranchor,\n.markdown-body h3 .headeranchor,\n.markdown-body h4 .headeranchor,\n.markdown-body h5 .headeranchor,\n.markdown-body h6 .headeranchor {\n  display: none;\n  color: #000;\n  vertical-align: middle;\n}\n\n.markdown-body h1:hover .headeranchor-link,\n.markdown-body h2:hover .headeranchor-link,\n.markdown-body h3:hover .headeranchor-link,\n.markdown-body h4:hover .headeranchor-link,\n.markdown-body h5:hover .headeranchor-link,\n.markdown-body h6:hover .headeranchor-link {\n  height: 1em;\n  padding-left: 8px;\n  margin-left: -30px;\n  line-height: 1;\n  text-decoration: none;\n}\n\n.markdown-body h1:hover .headeranchor-link .headeranchor,\n.markdown-body h2:hover .headeranchor-link .headeranchor,\n.markdown-body h3:hover .headeranchor-link .headeranchor,\n.markdown-body h4:hover .headeranchor-link .headeranchor,\n.markdown-body h5:hover .headeranchor-link .headeranchor,\n.markdown-body h6:hover .headeranchor-link .headeranchor {\n  display: inline-block;\n}\n\n.markdown-body h1 {\n  padding-bottom: 0.3em;\n  font-size: 2.25em;\n  line-height: 1.2;\n  border-bottom: 1px solid #eee;\n}\n\n.markdown-body h2 {\n  padding-bottom: 0.3em;\n  font-size: 1.75em;\n  line-height: 1.225;\n  border-bottom: 1px solid #eee;\n}\n\n.markdown-body h3 {\n  font-size: 1.5em;\n  line-height: 1.43;\n}\n\n.markdown-body h4 {\n  font-size: 1.25em;\n}\n\n.markdown-body h5 {\n  font-size: 1em;\n}\n\n.markdown-body h6 {\n  font-size: 1em;\n  color: #777;\n}\n\n.markdown-body p,\n.markdown-body blockquote,\n.markdown-body ul,\n.markdown-body ol,\n.markdown-body dl,\n.markdown-body table,\n.markdown-body pre,\n.markdown-body .admonition {\n  margin-top: 0;\n  margin-bottom: 16px;\n}\n\n.markdown-body hr {\n  height: 4px;\n  padding: 0;\n  margin: 16px 0;\n  background-color: #e7e7e7;\n  border: 0 none;\n}\n\n.markdown-body ul,\n.markdown-body ol {\n  padding-left: 2em;\n}\n\n.markdown-body ul ul,\n.markdown-body ul ol,\n.markdown-body ol ol,\n.markdown-body ol ul {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body li\u003ep {\n  margin-top: 16px;\n}\n\n.markdown-body dl {\n  padding: 0;\n}\n\n.markdown-body dl dt {\n  padding: 0;\n  margin-top: 16px;\n  font-size: 1em;\n  font-style: italic;\n  font-weight: bold;\n}\n\n.markdown-body dl dd {\n  padding: 0 16px;\n  margin-bottom: 16px;\n}\n\n.markdown-body blockquote {\n  padding: 0 15px;\n  color: #777;\n  border-left: 4px solid #ddd;\n}\n\n.markdown-body blockquote\u003e:first-child {\n  margin-top: 0;\n}\n\n.markdown-body blockquote\u003e:last-child {\n  margin-bottom: 0;\n}\n\n.markdown-body table {\n  display: block;\n  width: 100%;\n  overflow: auto;\n  word-break: normal;\n  word-break: keep-all;\n}\n\n.markdown-body table th {\n  font-weight: bold;\n}\n\n.markdown-body table th,\n.markdown-body table td {\n  padding: 6px 13px;\n  border: 1px solid #ddd;\n}\n\n.markdown-body table tr {\n  background-color: #fff;\n  border-top: 1px solid #ccc;\n}\n\n.markdown-body table tr:nth-child(2n) {\n  background-color: #f8f8f8;\n}\n\n.markdown-body img {\n  max-width: 100%;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n.markdown-body code,\n.markdown-body samp {\n  padding: 0;\n  padding-top: 0.2em;\n  padding-bottom: 0.2em;\n  margin: 0;\n  font-size: 85%;\n  background-color: rgba(0,0,0,0.04);\n  border-radius: 3px;\n}\n\n.markdown-body code:before,\n.markdown-body code:after {\n  letter-spacing: -0.2em;\n  content: \"\\00a0\";\n}\n\n.markdown-body pre\u003ecode {\n  padding: 0;\n  margin: 0;\n  font-size: 100%;\n  word-break: normal;\n  white-space: pre;\n  background: transparent;\n  border: 0;\n}\n\n.markdown-body .codehilite {\n  margin-bottom: 16px;\n}\n\n.markdown-body .codehilite pre,\n.markdown-body pre {\n  padding: 16px;\n  overflow: auto;\n  font-size: 85%;\n  line-height: 1.45;\n  background-color: #f7f7f7;\n  border-radius: 3px;\n}\n\n.markdown-body .codehilite pre {\n  margin-bottom: 0;\n  word-break: normal;\n}\n\n.markdown-body pre {\n  word-wrap: normal;\n}\n\n.markdown-body pre code {\n  display: inline;\n  max-width: initial;\n  padding: 0;\n  margin: 0;\n  overflow: initial;\n  line-height: inherit;\n  word-wrap: normal;\n  background-color: transparent;\n  border: 0;\n}\n\n.markdown-body pre code:before,\n.markdown-body pre code:after {\n  content: normal;\n}\n\n/* Admonition */\n.markdown-body .admonition {\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  position: relative;\n  border-radius: 3px;\n  border: 1px solid #e0e0e0;\n  border-left: 6px solid #333;\n  padding: 10px 10px 10px 30px;\n}\n\n.markdown-body .admonition table {\n  color: #333;\n}\n\n.markdown-body .admonition p {\n  padding: 0;\n}\n\n.markdown-body .admonition-title {\n  font-weight: bold;\n  margin: 0;\n}\n\n.markdown-body .admonition\u003e.admonition-title {\n  color: #333;\n}\n\n.markdown-body .attention\u003e.admonition-title {\n  color: #a6d796;\n}\n\n.markdown-body .caution\u003e.admonition-title {\n  color: #d7a796;\n}\n\n.markdown-body .hint\u003e.admonition-title {\n  color: #96c6d7;\n}\n\n.markdown-body .danger\u003e.admonition-title {\n  color: #c25f77;\n}\n\n.markdown-body .question\u003e.admonition-title {\n  color: #96a6d7;\n}\n\n.markdown-body .note\u003e.admonition-title {\n  color: #d7c896;\n}\n\n.markdown-body .admonition:before,\n.markdown-body .attention:before,\n.markdown-body .caution:before,\n.markdown-body .hint:before,\n.markdown-body .danger:before,\n.markdown-body .question:before,\n.markdown-body .note:before {\n  font: normal normal 16px fontawesome-mini;\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  line-height: 1.5;\n  color: #333;\n  position: absolute;\n  left: 0;\n  top: 0;\n  padding-top: 10px;\n  padding-left: 10px;\n}\n\n.markdown-body .admonition:before {\n  content: \"\\f056\\00a0\";\n  color: 333;\n}\n\n.markdown-body .attention:before {\n  content: \"\\f058\\00a0\";\n  color: #a6d796;\n}\n\n.markdown-body .caution:before {\n  content: \"\\f06a\\00a0\";\n  color: #d7a796;\n}\n\n.markdown-body .hint:before {\n  content: \"\\f05a\\00a0\";\n  color: #96c6d7;\n}\n\n.markdown-body .danger:before {\n  content: \"\\f057\\00a0\";\n  color: #c25f77;\n}\n\n.markdown-body .question:before {\n  content: \"\\f059\\00a0\";\n  color: #96a6d7;\n}\n\n.markdown-body .note:before {\n  content: \"\\f040\\00a0\";\n  color: #d7c896;\n}\n\n.markdown-body .admonition::after {\n  content: normal;\n}\n\n.markdown-body .attention {\n  border-left: 6px solid #a6d796;\n}\n\n.markdown-body .caution {\n  border-left: 6px solid #d7a796;\n}\n\n.markdown-body .hint {\n  border-left: 6px solid #96c6d7;\n}\n\n.markdown-body .danger {\n  border-left: 6px solid #c25f77;\n}\n\n.markdown-body .question {\n  border-left: 6px solid #96a6d7;\n}\n\n.markdown-body .note {\n  border-left: 6px solid #d7c896;\n}\n\n.markdown-body .admonition\u003e*:first-child {\n  margin-top: 0 !important;\n}\n\n.markdown-body .admonition\u003e*:last-child {\n  margin-bottom: 0 !important;\n}\n\n/* progress bar*/\n.markdown-body .progress {\n  display: block;\n  width: 300px;\n  margin: 10px 0;\n  height: 24px;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  border-radius: 3px;\n  background-color: #ededed;\n  position: relative;\n  box-shadow: inset -1px 1px 3px rgba(0, 0, 0, .1);\n}\n\n.markdown-body .progress-label {\n  position: absolute;\n  text-align: center;\n  font-weight: bold;\n  width: 100%; margin: 0;\n  line-height: 24px;\n  color: #333;\n  text-shadow: 1px 1px 0 #fefefe, -1px -1px 0 #fefefe, -1px 1px 0 #fefefe, 1px -1px 0 #fefefe, 0 1px 0 #fefefe, 0 -1px 0 #fefefe, 1px 0 0 #fefefe, -1px 0 0 #fefefe, 1px 1px 2px #000;\n  -webkit-font-smoothing: antialiased !important;\n  white-space: nowrap;\n  overflow: hidden;\n}\n\n.markdown-body .progress-bar {\n  height: 24px;\n  float: left;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  border-radius: 3px;\n  background-color: #96c6d7;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 -1px 0 rgba(0, 0, 0, .1);\n  background-size: 30px 30px;\n  background-image: -webkit-linear-gradient(\n    135deg, rgba(255, 255, 255, .4) 27%,\n    transparent 27%,\n    transparent 52%, rgba(255, 255, 255, .4) 52%,\n    rgba(255, 255, 255, .4) 77%,\n    transparent 77%, transparent\n  );\n  background-image: -moz-linear-gradient(\n    135deg,\n    rgba(255, 255, 255, .4) 27%, transparent 27%,\n    transparent 52%, rgba(255, 255, 255, .4) 52%,\n    rgba(255, 255, 255, .4) 77%, transparent 77%,\n    transparent\n  );\n  background-image: -ms-linear-gradient(\n    135deg,\n    rgba(255, 255, 255, .4) 27%, transparent 27%,\n    transparent 52%, rgba(255, 255, 255, .4) 52%,\n    rgba(255, 255, 255, .4) 77%, transparent 77%,\n    transparent\n  );\n  background-image: -o-linear-gradient(\n    135deg,\n    rgba(255, 255, 255, .4) 27%, transparent 27%,\n    transparent 52%, rgba(255, 255, 255, .4) 52%,\n    rgba(255, 255, 255, .4) 77%, transparent 77%,\n    transparent\n  );\n  background-image: linear-gradient(\n    135deg,\n    rgba(255, 255, 255, .4) 27%, transparent 27%,\n    transparent 52%, rgba(255, 255, 255, .4) 52%,\n    rgba(255, 255, 255, .4) 77%, transparent 77%,\n    transparent\n  );\n}\n\n.markdown-body .progress-100plus .progress-bar {\n  background-color: #a6d796;\n}\n\n.markdown-body .progress-80plus .progress-bar {\n  background-color: #c6d796;\n}\n\n.markdown-body .progress-60plus .progress-bar {\n  background-color: #d7c896;\n}\n\n.markdown-body .progress-40plus .progress-bar {\n  background-color: #d7a796;\n}\n\n.markdown-body .progress-20plus .progress-bar {\n  background-color: #d796a6;\n}\n\n.markdown-body .progress-0plus .progress-bar {\n  background-color: #c25f77;\n}\n\n.markdown-body .candystripe-animate .progress-bar{\n  -webkit-animation: animate-stripes 3s linear infinite;\n  -moz-animation: animate-stripes 3s linear infinite;\n  animation: animate-stripes 3s linear infinite;\n}\n\n@-webkit-keyframes animate-stripes {\n  0% {\n    background-position: 0 0;\n  }\n\n  100% {\n    background-position: 60px 0;\n  }\n}\n\n@-moz-keyframes animate-stripes {\n  0% {\n    background-position: 0 0;\n  }\n\n  100% {\n    background-position: 60px 0;\n  }\n}\n\n@keyframes animate-stripes {\n  0% {\n    background-position: 0 0;\n  }\n\n  100% {\n    background-position: 60px 0;\n  }\n}\n\n.markdown-body .gloss .progress-bar {\n  box-shadow:\n    inset 0 4px 12px rgba(255, 255, 255, .7),\n    inset 0 -12px 0 rgba(0, 0, 0, .05);\n}\n\n/* Multimarkdown Critic Blocks */\n.markdown-body .critic_mark {\n  background: #ff0;\n}\n\n.markdown-body .critic_delete {\n  color: #c82829;\n  text-decoration: line-through;\n}\n\n.markdown-body .critic_insert {\n  color: #718c00 ;\n  text-decoration: underline;\n}\n\n.markdown-body .critic_comment {\n  color: #8e908c;\n  font-style: italic;\n}\n\n.markdown-body .headeranchor {\n  font: normal normal 16px octicons-anchor;\n  line-height: 1;\n  display: inline-block;\n  text-decoration: none;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n\n.headeranchor:before {\n  content: '\\f05c';\n}\n\n.markdown-body .task-list-item {\n  list-style-type: none;\n}\n\n.markdown-body .task-list-item+.task-list-item {\n  margin-top: 3px;\n}\n\n.markdown-body .task-list-item input {\n  margin: 0 4px 0.25em -20px;\n  vertical-align: middle;\n}\n\n/* Media */\n@media only screen and (min-width: 480px) {\n  .markdown-body {\n    font-size:14px;\n  }\n}\n\n@media only screen and (min-width: 768px) {\n  .markdown-body {\n    font-size:16px;\n  }\n}\n\n@media print {\n  .markdown-body * {\n    background: transparent !important;\n    color: black !important;\n    filter:none !important;\n    -ms-filter: none !important;\n  }\n\n  .markdown-body {\n    font-size:12pt;\n    max-width:100%;\n    outline:none;\n    border: 0;\n  }\n\n  .markdown-body a,\n  .markdown-body a:visited {\n    text-decoration: underline;\n  }\n\n  .markdown-body .headeranchor-link {\n    display: none;\n  }\n\n  .markdown-body a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n\n  .markdown-body abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n\n  .markdown-body .ir a:after,\n  .markdown-body a[href^=\"javascript:\"]:after,\n  .markdown-body a[href^=\"#\"]:after {\n    content: \"\";\n  }\n\n  .markdown-body pre {\n    white-space: pre;\n    white-space: pre-wrap;\n    word-wrap: break-word;\n  }\n\n  .markdown-body pre,\n  .markdown-body blockquote {\n    border: 1px solid #999;\n    padding-right: 1em;\n    page-break-inside: avoid;\n  }\n\n  .markdown-body .progress,\n  .markdown-body .progress-bar {\n    -moz-box-shadow: none;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n  }\n\n  .markdown-body .progress {\n    border: 1px solid #ddd;\n  }\n\n  .markdown-body .progress-bar {\n    height: 22px;\n    border-right: 1px solid #ddd;\n  }\n\n  .markdown-body tr,\n  .markdown-body img {\n    page-break-inside: avoid;\n  }\n\n  .markdown-body img {\n    max-width: 100% !important;\n  }\n\n  .markdown-body p,\n  .markdown-body h2,\n  .markdown-body h3 {\n    orphans: 3;\n    widows: 3;\n  }\n\n  .markdown-body h2,\n  .markdown-body h3 {\n    page-break-after: avoid;\n  }\n}\n\u003c/style\u003e\u003ctitle\u003eREADME\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003carticle class=\"markdown-body\"\u003e\u003ch1 id=\"hyperloop-showcase\"\u003e\u003ca name=\"user-content-hyperloop-showcase\" href=\"#hyperloop-showcase\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eHyperLoop Showcase\u003c/h1\u003e\n\u003cp\u003eThis is a simple Rails application showcasing \u003cstrong\u003eHyperReact\u003c/strong\u003e (wrapper for the React.js library for creating user interfaces), Opal, NPM, Webpack, React Bootstrap, \u003cstrong\u003eHyperMesh\u003c/strong\u003e (gives your \u003cstrong\u003eHyperReact\u003c/strong\u003e components CRUD access to your server side ActiveRecord models and implements push notifications)  and other associated technologies. \u003c/p\u003e\n\u003cp\u003eThis Showcase application will mix native React and \u003cstrong\u003eHyperReact\u003c/strong\u003e components, be styled by Bootstrap CSS (using ReactBootstrap), display a video (using a native React component) and use \u003cstrong\u003eHyperMesh\u003c/strong\u003e to handle data for an Events feed app.\u003c/p\u003e\n\u003cp\u003eThe Showcase application will look like this:\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Screen\" src=\"/home/fcooker/rails/hyperloop-showcase/public/screen.png\" /\u003e\u003c/p\u003e\n\u003ch3 id=\"technologies-highlighted-in-this-showcase-application\"\u003e\u003ca name=\"user-content-technologies-highlighted-in-this-showcase-application\" href=\"#technologies-highlighted-in-this-showcase-application\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eTechnologies highlighted in this Showcase application\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eFor the backend we are using \u003ca href=\"http://rubyonrails.org/\"\u003eRails 5.0.1\u003c/a\u003e with \u003ca href=\"https://www.ruby-lang.org/en/news/2016/04/26/ruby-2-3-1-released/\"\u003eRuby 2.3.1\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.npmjs.com/\"\u003eNPM\u003c/a\u003e and \u003ca href=\"https://webpack.github.io/\"\u003eWebpack\u003c/a\u003e to manage front end assets\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ruby-hyperloop/hyper-rails\"\u003eHypeRails\u003c/a\u003e to install \u003ca href=\"https://github.com/ruby-hyperloop/hyper-react\"\u003eHyperReact\u003c/a\u003e and Opal in Rails 4.x or 5.x\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ruby-hyperloop/hyper-react\"\u003eHyperReact\u003c/a\u003e to use \u003ca href=\"https://facebook.github.io/react/\"\u003eReact\u003c/a\u003e with Rails and to write reactive UI components with Ruby\u0026rsquo;s elegance\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://react-bootstrap.github.io/\"\u003eReact Bootstrap\u003c/a\u003e to show how to use native React components in \u003ca href=\"https://github.com/ruby-hyperloop/hyper-react\"\u003eHyperReact\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ruby-hyperloop/hyper-mesh\"\u003eHyperMesh\u003c/a\u003e between Rails models and the front end and to magically push \u003cbr /\u003e\n  changed data between all connected clients\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/fkchang/opal-hot-reloader\"\u003eHyperReact Hot-Reloader and Opal IRB\u003c/a\u003e for programmer joy and hot-loading with developing\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"introduction\"\u003e\u003ca name=\"user-content-introduction\" href=\"#introduction\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eIntroduction\u003c/h2\u003e\n\u003ch3 id=\"introductions-to-hyperreact\"\u003e\u003ca name=\"user-content-introductions-to-hyperreact\" href=\"#introductions-to-hyperreact\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eIntroductions to \u003cstrong\u003eHyperReact\u003c/strong\u003e\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://slides.com/mitchvanduyn/deck-1-3#/\"\u003eAn overview of HyperReact (formerly Reactrb) by Mitch VanDuyn\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.slideshare.net/fkchang/reactrb-all-the-power-of-reactjs-with-all-the-joy-of-ruby\"\u003ePower of React-js with the joy of Ruby by Forrest Chang\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"hyperreact-help-and-questions\"\u003e\u003ca name=\"user-content-hyperreact-help-and-questions\" href=\"#hyperreact-help-and-questions\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eHyperReact Help and Questions\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://gitter.im/reactrb/chat\"\u003eGitter.im\u003c/a\u003e for general questions, discussion, and interactive help.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://stackoverflow.com/questions/tagged/reactrb\"\u003eStack Overflow\u003c/a\u003e tag \u003ccode\u003ereactrb\u003c/code\u003e for specific problems.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ruby-hyperloop/hyper-react/issues\"\u003eGithub Issues\u003c/a\u003e for bugs, feature enhancements, etc.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#further-reading\"\u003eFurther reading\u003c/a\u003e at the end of this tutorial\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"using-npm-and-webpack-alongside-rails\"\u003e\u003ca name=\"user-content-using-npm-and-webpack-alongside-rails\" href=\"#using-npm-and-webpack-alongside-rails\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eUsing NPM and Webpack alongside Rails\u003c/h3\u003e\n\u003cp\u003eRuby libraries are distributed as gems, and are managed in your Rails app using the Gemfile and bundler.\u003c/p\u003e\n\u003cp\u003eIn the Javascript world things are still evolving but I have found that the easiest way to manage Javascript libraries is using NPM (Node Package Manager) and Webpack.  Pretty much every front end library is packaged with NPM these days so it is easy to get help and most things just work.\u003c/p\u003e\n\u003cp\u003eHappily NPM, Webpack, Rails, and \u003cstrong\u003eHyperReact\u003c/strong\u003e can all play together very nicely.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.npmjs.com/\"\u003eNPM\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.npmjs.com/package/webpack\"\u003eWebpack\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis tutorial requires that Ruby, Rails, NPM and Webpack are installed. Please see their websites for installation instructions.\u003c/p\u003e\n\u003ch2 id=\"setup\"\u003e\u003ca name=\"user-content-setup\" href=\"#setup\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eSetup\u003c/h2\u003e\n\u003ch3 id=\"step-1-creating-a-new-rails-application\"\u003e\u003ca name=\"user-content-step-1-creating-a-new-rails-application\" href=\"#step-1-creating-a-new-rails-application\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eStep 1: Creating a new Rails application\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e    rails new hyperloop-showcase\n    cd hyperloop-showcase\n    bundle install\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eUpdate your Database config file for accessing your Database properly : \u003ccode\u003econfig/database.yml\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eThen execute \u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    rails db:create\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eYou should have a empty Rails application\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    bundle exec rails s\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eAnd in your browser\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    http://localhost:3000/\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eYou should be seeing the Rails Welcome aboard page. Great, Rails is now installed. Lets get started with the interesting stuff.\u003c/p\u003e\n\u003ch3 id=\"step-2-adding-hyperreact-and-hypermesh\"\u003e\u003ca name=\"user-content-step-2-adding-hyperreact-and-hypermesh\" href=\"#step-2-adding-hyperreact-and-hypermesh\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eStep 2: Adding HyperReact and HyperMesh\u003c/h3\u003e\n\u003cp\u003eThere are 2 ways do achieve that :\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUsing \u003cstrong\u003eHyperLoop\u003c/strong\u003e installation generator\u003cbr /\u003e\nOR\u003c/li\u003e\n\u003cli\u003eManually.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIn this tutorial we advise you to follow the manual way, so you can see what\u0026rsquo;s happen and you can be sure to have all gems versions identical to those used in this tutorial.\u003c/p\u003e\n\u003cp\u003eif you want to see the automatic way for the future you can go to the official \u003cstrong\u003eHyperLoop web page\u003c/strong\u003e : \u003ca href=\"http://ruby-hyperloop.io/installation/#with-rails\"\u003eHyperLoop installation with Rails\u003c/a\u003e\u003c/p\u003e\n\u003ch4 id=\"manual-installation-of-hyperreact-and-hypermesh\"\u003e\u003ca name=\"user-content-manual-installation-of-hyperreact-and-hypermesh\" href=\"#manual-installation-of-hyperreact-and-hypermesh\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eManual installation of HyperReact and HyperMesh\u003c/h4\u003e\n\u003ch5 id=\"step-21-add-the-gems\"\u003e\u003ca name=\"user-content-step-21-add-the-gems\" href=\"#step-21-add-the-gems\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eStep 2.1: Add the gems\u003c/h5\u003e\n\u003cp\u003ein your \u003ccode\u003eGemfile\u003c/code\u003e\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003e    gem 'react-rails', '1.4.2'\n    gem 'hyper-rails', '0.4.1'\n    gem 'opal-rails', '0.9.1'\n    gem 'opal-browser', '0.2.0'\n    gem 'hyper-react', '0.11.0'\n    gem 'hyper-mesh', '0.5.3'\n    gem 'hyper-router', '2.4.0'\n    gem 'therubyracer', platforms: :ruby\n\u003c/code\u003e\u003c/pre\u003e\u003cbr /\u003e\nThen run\u003cbr /\u003e\n\u003cpre\u003e\u003ccode\u003ebundle update\n\u003c/code\u003e\u003c/pre\u003e\u003c/p\u003e\n\u003ch3 id=\"step-3-webpack-for-managing-front-end-assets\"\u003e\u003ca name=\"user-content-step-3-webpack-for-managing-front-end-assets\" href=\"#step-3-webpack-for-managing-front-end-assets\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eStep 3: Webpack for managing front-end assets\u003c/h3\u003e\n\u003cp\u003eThere are three parts to this step:  \u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSetting up NPM (node package manager) for the project\u003c/li\u003e\n\u003cli\u003eSetting up Webpack\u003c/li\u003e\n\u003cli\u003eUpdating the rails asset pipeline to use the bundles generated by Webpack\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is just a matter of adding 4 boiler plate files, and updating two of your rails files.\u003c/p\u003e\n\u003cp\u003eFirst add a package.json file to your root directory (same place as your Gemfile) like this:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// package.json\n{\n    \"name\": \"reactrb-showcase\",\n    \"version\": \"0.0.1\",\n    \"dependencies\": {\n        \"bootstrap\": \"^3.3.6\",\n        \"react\": \"^0.14.2\",      \n        \"react-dom\": \"^0.14.2\",\n        \"react-bootstrap\": \"^0.29.5\",\n        \"webpack\": \"^1.13.1\"\n    },\n        \"devDependencies\": {\n    }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eNotice how similar this is to your Gemfile.\u003c/p\u003e\n\u003cp\u003eNow run \u003ccode\u003enpm install\u003c/code\u003e which will make sure you have all these packages.\u003c/p\u003e\n\u003cp\u003eSo that we can run Webpack from the command line do a \u003ccode\u003enpm install webpack -g\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eNow that we have Webpack, we need to add 3 boiler plate files to configure it.  As you add more javascript packages you will be updating these files.  Again this is similar to updating your Gemfile when you add new gems to a project.\u003c/p\u003e\n\u003cp\u003eAdd webpack.config.js to the root of your project:\u003c/p\u003e\n\u003cp\u003e\u003cpre\u003e\u003ccode class=\"javascript\"\u003evar path = require(\u0026quot;path\u0026quot;);\n\nmodule.exports = {\n    context: __dirname,\n    entry: {\n      client_only:  \u0026quot;./webpack/client_only.js\u0026quot;,\n      client_and_server: \u0026quot;./webpack/client_and_server.js\u0026quot;\n    },\n    output: {\n      path: path.join(__dirname, 'app', 'assets',   'javascripts', 'webpack'),\n      filename: \u0026quot;[name].js\u0026quot;,\n      publicPath: \u0026quot;/webpack/\u0026quot;\n    },\n    module: {\n      loaders: [\n        // add any loaders here\n      ]\n    },\n    resolve: {\n      root: path.join(__dirname, '..', 'webpack')\n    },\n};\n\u003c/code\u003e\u003c/pre\u003e\u003cbr /\u003e\nand create a folder called \u003ccode\u003ewebpack\u003c/code\u003e and add the following two files:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"javascript\"\u003e// webpack/client_only.js\n// any packages that depend specifically on the DOM go here\n// for example the webpack css loader generates code that will break prerendering\nconsole.log('client_only.js loaded');\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cpre\u003e\u003ccode class=\"javascript\"\u003e// webpack/client_and_server.js\n// all other packages that you can run on both server (prerendering) and client go here\n// most well behaved packages can be required here\nReactDOM = require('react-dom')\nReact = require('react')\nconsole.log('client_and_server.js loaded')\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eNow run \u003ccode\u003ewebpack\u003c/code\u003e from the command line.  This will grab all necessary dependencies and package them up into the \u003ccode\u003eclient_and_server.js\u003c/code\u003e and \u003ccode\u003eclient_only.js\u003c/code\u003e bundles.  If you look in the \u003ccode\u003eapp/assets/javascripts/webpack\u003c/code\u003e directory you should see the two files there.\u003c/p\u003e\n\u003cp\u003eFinally we need to require these two bundles into our rails asset pipeline.\u003c/p\u003e\n\u003cp\u003eEdit \u003ccode\u003eapp/assets/javascript/application.js\u003c/code\u003e and add\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"javascript\"\u003e//= require 'webpack/client_only'\n\u003c/code\u003e\u003c/pre\u003e\u003cbr /\u003e\njust \u003cem\u003eabove\u003c/em\u003e the line that reads \u003ccode\u003eOpal.load('components');\u003c/code\u003e.  This will pull in any webpack assets that can only run on the client.\u003c/p\u003e\n\u003cp\u003eThen edit \u003ccode\u003eapp/views/components.rb\u003c/code\u003e and replace the \u003ccode\u003erequire 'react'\u003c/code\u003e line with\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003erequire 'webpack/client_and_server.js'\n\u003c/code\u003e\u003c/pre\u003e\u003c/p\u003e\n\u003cp\u003eIn otherwords instead of pulling in react from the react-rails gem, we are going to pull in react \u003cem\u003eand\u003c/em\u003e any other javascript packages we want from our webpack bundle.\u003c/p\u003e\n\u003cp\u003eReactrb can automatically access our components loaded by Webpack, but we have to opt in to this behavior.  Edit \u003ccode\u003eapp/views/components.rb\u003c/code\u003e and add\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003erequire 'reactrb/auto-import'\n\u003c/code\u003e\u003c/pre\u003e\u003c/p\u003e\n\u003cp\u003eimmediately after \u003ccode\u003erequire 'reactrb'\u003c/code\u003e (which is right near the top of the file.)  Auto-import will now search the javascript name space, and import into ruby any components that are referenced by your Reactrb components.\u003c/p\u003e\n\u003cp\u003eNow run \u003ccode\u003ebundle exec rails s\u003c/code\u003e and refresh the browser.  Look at the console and you should see something like this:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003eclient_and_server.js loaded\nclient_only.js loaded\nclient_and_server.js loaded\n************************ React Prerendering Context Initialized Show ***********************\n************************ React Browser Context Initialized ****************************\nReactive record prerendered data being loaded: [Object]\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eCongratulations you are setup and ready to begin adding javascript packages to your application.\u003c/p\u003e\n\u003ch2 id=\"working-with-native-react-components\"\u003e\u003ca name=\"user-content-working-with-native-react-components\" href=\"#working-with-native-react-components\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eWorking with native React components\u003c/h2\u003e\n\u003cp\u003eIt is time to reap some of the rewards from all the hard work above. We have everything setup so we can easily add front end components and work with them in Reactrb. Lets jump in and add a native React component that plays a video.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/CookPete/rplayr\"\u003eWe are going to use Pete Cook\u0026rsquo;s React rplayr\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eFirst let\u0026rsquo;s install the component via NPM:\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003enpm install react-player --save\n\u003c/code\u003e\u003c/pre\u003e\u003c/p\u003e\n\u003cp\u003eNext we need to \u003ccode\u003erequire\u003c/code\u003e it in \u003ccode\u003ewebpack/client_and_server.js\u003c/code\u003e\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"javascript\"\u003eReactPlayer = require('react-player')\n\u003c/code\u003e\u003c/pre\u003e\u003c/p\u003e\n\u003cp\u003eNext run webpack so it can be bundled\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003ewebpack\n\u003c/code\u003e\u003c/pre\u003e\u003c/p\u003e\n\u003cp\u003eAnd then finally let\u0026rsquo;s add it to our Show component:\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003edef render\n  div do\n    ReactPlayer(url:  'https://www.youtube.com/embed/FzCsDVfPQqk',\n      playing: true\n    )\n  end\nend\n\u003c/code\u003e\u003c/pre\u003e\u003c/p\u003e\n\u003cp\u003eRefresh your browser and you should have a video. How simple was that!\u003c/p\u003e\n\u003ch2 id=\"working-with-react-bootstrap\"\u003e\u003ca name=\"user-content-working-with-react-bootstrap\" href=\"#working-with-react-bootstrap\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eWorking with React Bootstrap\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://react-bootstrap.github.io/\"\u003eWe will be using React Bootstrap which is a native React library\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eThe main purpose for React Bootstrap is that it abstracts away verbose HTML \u0026amp; CSS code into React components which makes it a lot cleaner for React JSX developers. One of the very lovely things about Reactrb is that we already work in beautiful Ruby. To emphasise this point, consider the following:\u003c/p\u003e\n\u003cp\u003eSample 1 - In HTML (without React Bootstrap):\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;button id=\"something-btn\" type=\"button\" class=\"btn btn-success btn-sm\"\u0026gt;\n  Something\n\u0026lt;/button\u0026gt;\n$('#something-btn').click(someCallback);\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eSample 2 - In JSX (with React Bootstrap components):\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;Button bsStyle=\"success\" bsSize=\"small\" onClick={someCallback}\u0026gt;\n  Something\n\u0026lt;/Button\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eSample 3 - In Reactrb (without React Bootstrap):\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ebutton.btn_success.btn_sm {'Something'}.on(:click) do\n    someMethod\nend\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eSample 4 - In Reactrb (with React Bootstrap):\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eBs.Button(bsStyle: 'success' bsSize: \"small\") {'Something'}.on(:click) do\n    someMethod\nend\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eAs you can see, sample 3 \u0026amp; 4 are not that different and as a Reactrb developer, I actually prefer sample 3. If I were a JavaScript or JSX developer I would completely understand the advantage of abstracting Bootstrap CSS into React Components so I don\u0026rsquo;t have to work directly with CSS and JavaScript but this is not the case with Reactrb as CSS classes are added to HTML elements with simple dot notation:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003espan.pull_right {}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003ecompiles to (note the conversion from _ to -)\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class='pull-right'\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eSo I hear you ask: why if I prefer the non-React Bootstrap syntax why am worrying about React Bootstrap? For one very simple reason: components like Navbar and Modal that requires \u003ccode\u003ebootstrap.js\u003c/code\u003e will not work with React on it\u0026rsquo;s own so without the React Bootstrap project you would need to implement all that functionality yourself. The React Bootstrap project has re-implemented all this functionality as React components.\u003c/p\u003e\n\u003cp\u003eLets implement a Navbar in this project using React Bootstrap in Reactrb. First, we need to install Bootstrap and React Bootstrap:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003enpm install bootstrap react-bootstrap --save\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eNote: The \u003ccode\u003e--save\u003c/code\u003e option will update the package.json file.\u003c/p\u003e\n\u003cp\u003eAnd then we need to \u003ccode\u003erequire\u003c/code\u003e it in \u003ccode\u003ewebpack/client_and_server.js\u003c/code\u003e by adding this line:\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"javascript\"\u003eReactBootstrap = require('react-bootstrap')\n\u003c/code\u003e\u003c/pre\u003e\u003cbr /\u003e\nRun the \u003ccode\u003ewebpack\u003c/code\u003e command again, and restart your rails server.\u003c/p\u003e\n\u003cp\u003eIf you refresh your browser now and open the JavaScript console we will be able to interact with React Bootstrap by typing:\u003c/p\u003e\n\u003cp\u003eIn the JavaScript console type: \u003ccode\u003eReactBootstrap\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eand you will see the ReactBootstrap object with all its components like Accordion, Alert, Badge, Breadcrumb, etc. This is great news, React Bootstrap is installed and ready to use. Accessing the JavaScript object in this way is a really great way to see what you have to work with. Sometimes the documentation of a component is not as accurate as actually seeing what you have in the component itself.\u003c/p\u003e\n\u003cp\u003eTo make sure everything is working lets add a \u003cem\u003eButton\u003c/em\u003e to our our Show component like this:\u003c/p\u003e\n\u003cp\u003e\u003cpre\u003e\u003ccode class=\"ruby\"\u003emodule Components\n  module Home\n    class Show \u0026lt; React::Component::Base\n      def render\n        ReactBootstrap::Button(bsStyle: 'success', bsSize: \u0026quot;small\u0026quot;) do\n          'Success'\n        end.on(:click) do\n          alert('you clicked me!')\n        end\n      end\n    end\n  end\nend\n\u003c/code\u003e\u003c/pre\u003e\u003cbr /\u003e\nNotice that we reference \u003ccode\u003eReactBoostrap\u003c/code\u003e in ruby using the same identifer that was in the require statement in our \u003ccode\u003eclient_and_server.js\u003c/code\u003e webpack bundle.  The first time Reactrb hits the \u003ccode\u003eReactBootstrap\u003c/code\u003e constant it will not be defined. This triggers a search of the javascript name space for something that looks either like a component or library of components.  It then defines the appropriate module or component class wrapper in ruby.\u003c/p\u003e\n\u003cp\u003eVisit your page and if all is well you will see a clickable button.  However it will not have any styles.  This is because ReactBootstrap does not automatically depend on any particular style sheet, so we will have to supply one.  An easy way to do this is to just copy the css file from the bootstrap repo, and stuff it our rails assets directory, however with a little upfront work we can setup webpack to do it all for us.\u003c/p\u003e\n\u003cp\u003eFirst lets add four webpack \u003cem\u003eloaders\u003c/em\u003e using npm:\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003enpm install css-loader file-loader style-loader url-loader --save-dev\n\u003c/code\u003e\u003c/pre\u003e\u003cbr /\u003e\nNotice we use \u003ccode\u003e--save-dev\u003c/code\u003e instead of just \u003ccode\u003e--save\u003c/code\u003e as these packages are only used in the development process.\u003c/p\u003e\n\u003cp\u003eNow edit your \u003ccode\u003ewebpack.config.js\u003c/code\u003e file, and update the loaders section so it looks like this:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"javascript\"\u003evar path = require(\u0026quot;path\u0026quot;);\n\nmodule.exports = {\n...\n    module: {\n      loaders: [\n        { test: /\\.css$/,\n          loader: \u0026quot;style-loader!css-loader\u0026quot;\n        },\n        { test: /\\.(woff|woff2)(\\?v=\\d+\\.\\d+\\.\\d+)?$/,\n          loader: 'url?limit=10000\u0026amp;mimetype=application/font-woff'\n        },\n        { test: /\\.ttf(\\?v=\\d+\\.\\d+\\.\\d+)?$/,\n          loader: 'url?limit=10000\u0026amp;mimetype=application/octet-stream'\n        },\n        { test: /\\.eot(\\?v=\\d+\\.\\d+\\.\\d+)?$/,\n          loader: 'file'\n        },\n        { test: /\\.svg(\\?v=\\d+\\.\\d+\\.\\d+)?$/,\n          loader: 'url?limit=10000\u0026amp;mimetype=image/svg+xml'\n        }\n      ]\n    },\n...\n};\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eWe have set webpack up so that when a css file is required it uses the style loader to process the file.  Because the bootstrap css file will require font face files, we also have 4 font loaders.  All this will package up everything when we require any css file.\u003c/p\u003e\n\u003cp\u003eNow we are ready to require CSS files, and have webpack build a complete bundle including the css and any fonts referenced.\u003c/p\u003e\n\u003cp\u003eTo bundle in the bootstrap css file add this line to \u003ccode\u003ewebpack/client_only.js\u003c/code\u003e\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"javascript\"\u003erequire('bootstrap/dist/css/bootstrap.css');\n\u003c/code\u003e\u003c/pre\u003e\u003c/p\u003e\n\u003cp\u003eAnd install the bootstrap package\u003cbr /\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003enpm install bootstrap --save\n\u003c/code\u003e\u003c/pre\u003e\u003c/p\u003e\n\u003cp\u003eNow run \u003ccode\u003ewebpack\u003c/code\u003e to update our bundles, and restart your server.  Now our button is properly styled you should be rewarded with a nice Bootstrap styled green Success Button.\u003c/p\u003e\n\u003cp\u003eNow that everything is loaded, lets update our component to use a few more of the Bootstrap components.  Update your Show component so that it looks like this:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003emodule Components\n  module Home\n    class Show \u0026lt; React::Component::Base\n\n      def say_hello(i)\n        alert \u0026quot;Hello from number #{i}\u0026quot;\n      end\n\n      def render\n        div do\n          ReactBootstrap::Navbar(bsStyle: :inverse) do\n            ReactBootstrap::Nav() do\n              ReactBootstrap::NavbarBrand() do\n                a(href: '#') { 'Reactrb Showcase' }\n              end\n              ReactBootstrap::NavDropdown(\n                eventKey: 1,\n                title: 'Things',\n                id: :drop_down\n              ) do\n                (1..5).each do |n|\n                  ReactBootstrap::MenuItem(href: '#',\n                    key: n,\n                    eventKey: \u0026quot;1.#{n}\u0026quot;\n                  ) do\n                    \u0026quot;Number #{n}\u0026quot;\n                  end.on(:click) { say_hello(n) }\n                end\n              end\n            end\n          end\n          div.container do\n            ReactPlayer(url: 'https://www.youtube.com/embed/FzCsDVfPQqk',\n              playing: true\n            )\n          end\n        end\n      end\n    end\n  end\nend\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eA few things to notice in the code above:\u003c/p\u003e\n\u003cp\u003eWe add React Bootstrap components simply by \u003ccode\u003eReactBootstrap::Name\u003c/code\u003e where \u003ccode\u003eName\u003c/code\u003e is the JavaScriot component you want to render. All the components are documented in the React Bootstrap \u003ca href=\"https://react-bootstrap.github.io/components.html\"\u003edocumentation\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eSee with \u003ccode\u003ediv.container\u003c/code\u003e we are mixing in CSS style which will compile into \u003ccode\u003e\u0026lt;div class='container'\u0026gt;\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eAlso notice how I have added an \u003ccode\u003e.on(:click)\u003c/code\u003e event handler to the \u003ccode\u003eMenuItem\u003c/code\u003e component while setting \u003ccode\u003ehref: '#'\u003c/code\u003e as this will allow us to handle the event instead of navigating to a new page.\u003c/p\u003e\n\u003cp\u003eSo far we have a very basic application which is looking OK and showing a video. Time to do something a little more interesting. How about if we add Post and Comment functionality which will let us explore Reactive Record!\u003c/p\u003e\n\u003ch2 id=\"using-reactrb-reactive-record\"\u003e\u003ca name=\"user-content-using-reactrb-reactive-record\" href=\"#using-reactrb-reactive-record\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eUsing Reactrb Reactive Record\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/reactrb/reactive-record\"\u003eWe will be using the Reactive Record gem\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eReactive Record compiles your Active Record models so they are accessible to the front-end and implements an API based on your models and their associations. Lazy loads just the data that is needed to render a component and is fully integrated with Reactrb and paired with Synchromesh to push database changes to all connected clients. ReactiveRecord and Synchromesh give you Relay + GraphQL like functionality with a fraction of the effort and complexity (the original idea for Reactive Record is credited to \u003ca href=\"https://github.com/voltrb/volt\"\u003eVolt\u003c/a\u003e and not Relay).\u003c/p\u003e\n\u003ch3 id=\"installing-reactive-record\"\u003e\u003ca name=\"user-content-installing-reactive-record\" href=\"#installing-reactive-record\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eInstalling Reactive Record\u003c/h3\u003e\n\u003cp\u003eInstalling Reactive Record is straight forward.\u003c/p\u003e\n\u003cp\u003eFirst add this line to your application\u0026rsquo;s Gemfile:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003egem 'reactive-record'\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eAnd then execute:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ bundle install\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eFinally you need to add a line to your \u003ccode\u003eroutes.rb\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003emount ReactiveRecord::Engine =\u0026gt; '/rr'\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch3 id=\"creating-the-models\"\u003e\u003ca name=\"user-content-creating-the-models\" href=\"#creating-the-models\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eCreating the models\u003c/h3\u003e\n\u003cp\u003eWe are going to need a few models to work with so let\u0026rsquo;s go ahead and create those now.\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003erails g model Post\nrails g model Comment post:references\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eAnd then before you run the migrations, lets flesh them out a little so they look like this:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003e# db/migrate/..create_posts.rb\nclass CreatePosts \u0026lt; ActiveRecord::Migration\n  def change\n    create_table :posts do |t|\n      t.string :body\n      t.timestamps null: false\n    end\n  end\nend\n\n# db/migrate/..create_comments.rb\nclass CreateComments \u0026lt; ActiveRecord::Migration\n  def change\n    create_table :comments do |t|\n      t.references :post, index: true, foreign_key: true\n      t.string :body\n      t.timestamps null: false\n    end\n  end\nend\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eNow would be a good time to run the migrations:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003erake db:migrate\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch3 id=\"making-your-models-accessible-to-reactive-record\"\u003e\u003ca name=\"user-content-making-your-models-accessible-to-reactive-record\" href=\"#making-your-models-accessible-to-reactive-record\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eMaking your models accessible to Reactive Record\u003c/h3\u003e\n\u003cp\u003eReactive Record needs to \u0026lsquo;see\u0026rsquo; your models as a representation of them get compiled into JavaScript along with your Reactrb components so they are accessible in your client side code.\u003c/p\u003e\n\u003cp\u003eThe convention (though this is choice and you can change this if you prefer) is to create a \u003ccode\u003epublic\u003c/code\u003e folder under \u003ccode\u003emodels\u003c/code\u003e and then provide a linkage file which will \u003ccode\u003erequire_tree\u003c/code\u003e your models when compiling \u003ccode\u003ecomponents.rb\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eCreate a new folder:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003emodels/public\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eThen move \u003ccode\u003epost.rb\u003c/code\u003e and \u003ccode\u003ecomment.rb\u003c/code\u003e to \u003ccode\u003emodels/public\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003e$ mv app/models/post.rb app/models/public\n$ mv app/models/comment.rb app/models/public\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eNext create \u003ccode\u003e_react_public_models.rb\u003c/code\u003e in your models folder:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003e# models/_react_public_models.rb\nrequire_tree './public'\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eFinally add a line to your \u003ccode\u003eviews/components.rb\u003c/code\u003e file:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003e# views/components.rb\n...\nrequire '_react_public_models'\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch3 id=\"model-associations\"\u003e\u003ca name=\"user-content-model-associations\" href=\"#model-associations\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eModel Associations\u003c/h3\u003e\n\u003cp\u003eReactive Record is particular about both sides of an association being specified. If you forget to do this you will see warnings to this effect.\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003e# models/public/post.rb\nclass Post \u0026lt; ActiveRecord::Base\n  has_many :comments\nend\n\n# models/public/comment.rb\nclass Comment \u0026lt; ActiveRecord::Base\n  belongs_to :post\nend\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch3 id=\"accessing-your-models-in-reactrb-components\"\u003e\u003ca name=\"user-content-accessing-your-models-in-reactrb-components\" href=\"#accessing-your-models-in-reactrb-components\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eAccessing your models in Reactrb components\u003c/h3\u003e\n\u003cp\u003eTo get started, lets create a new component which will display a list of Posts and Comments under the video:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003e# views/components/show.rb\n...\ndiv.container do\n  ReactPlayer(url: 'https://www.youtube.com/embed/FzCsDVfPQqk', playing: true)\n  br # line break\n  PostsList()\nend\n...\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eNote that to place a Reactrb component you either need to include ( ) or { }, so \u003ccode\u003ePostsList()\u003c/code\u003e or \u003ccode\u003ePostsList { }\u003c/code\u003e would be valid but just \u003ccode\u003ePostsList\u003c/code\u003e would not.\u003c/p\u003e\n\u003cp\u003eNext lets create the \u003ccode\u003ePostsList\u003c/code\u003e component:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003emodule Components\n  module Home\n    class PostsList \u0026lt; React::Component::Base\n      define_state :new_post, \u0026quot;\u0026quot;\n\n      before_mount do\n        # note that this will lazy load posts\n        # and only the fields that are needed will be requested\n        @posts = Post.all\n      end\n\n      def render\n        div do\n          new_post\n          ul.list_unstyled do\n            @posts.reverse.each do |post|\n              PostListItem(post: post)\n              CommentsList(comments: post.comments)\n            end\n          end\n        end\n      end\n\n      def new_post\n        ReactBootstrap::FormGroup() do\n          ReactBootstrap::FormControl(\n            value: state.new_post,\n            type: :text,\n          ).on(:change) { |e|\n            state.new_post! e.target.value\n          }\n        end\n        ReactBootstrap::Button(bsStyle: :primary) do\n          \u0026quot;Post\u0026quot;\n        end.on(:click) { save_new_post }\n      end\n\n      def save_new_post\n        post = Post.new(body: state.new_post)\n        post.save do |result|\n          # note that save is a promise so this code will only run after the save\n          # yet react will move onto the code after this (before the save happens)\n          alert \u0026quot;unable to save\u0026quot; unless result == true\n        end\n        state.new_post! \u0026quot;\u0026quot;\n      end\n    end\n\n    class PostListItem \u0026lt; React::Component::Base\n      param :post\n\n      def render\n        li do\n          # note how you access post.body just like with Active Record\n          h4 { params.post.body }\n        end\n      end\n\n    end\n  end\nend\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eThings to note in the code above:\u003c/p\u003e\n\u003cp\u003eSee how we fetch the Reactive Record Post collection in \u003ccode\u003ebefore_mount\u003c/code\u003e. Setting this here instead of in \u003ccode\u003eafter_mount\u003c/code\u003e means that we do not need to worry about \u003ccode\u003e@posts\u003c/code\u003e being \u003ccode\u003enil\u003c/code\u003e as the collection will always contain at least one entry with the actual records being lazy loaded when needed.\u003c/p\u003e\n\u003cp\u003eNote how we are binding the state variable \u003ccode\u003enew_post\u003c/code\u003e to the \u003ccode\u003eFormControl\u003c/code\u003e and then setting its value based on the value being passed to the \u003ccode\u003e.on(:change)\u003c/code\u003e block. This is a standard React pattern.\u003c/p\u003e\n\u003cp\u003eAlso see how we are saving the new post where Reactive Record\u0026rsquo;s save returns a promise which means that the block after save is only evaluated when it returns yet React would have moved on to the rest of the code.\u003c/p\u003e\n\u003cp\u003eFinally note that there is no code which checks to see if there are new posts yet when you run this, the list of posts remains magically up-to-date.\u003c/p\u003e\n\u003cp\u003eWelcome to the wonderful of Reactive Record and React!\u003c/p\u003e\n\u003ch2 id=\"synchromesh\"\u003e\u003ca name=\"user-content-synchromesh\" href=\"#synchromesh\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eSynchromesh\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/reactrb/synchromesh\"\u003eWe will be using the Synchromesh gem\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eReactive Record is the data layer between one client and its server and Synchromesh uses push notifications to push changed records to all connected Reactive Record clients.\u003c/p\u003e\n\u003cp\u003eSynchromesh is incredibly simple to setup. Add this line to your Gemfile:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003egem 'synchromesh', git: \u0026quot;https://github.com/reactrb/synchromesh.git\u0026quot;\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eAnd then execute:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003e$ bundle install\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eNext add this line to your \u003ccode\u003ecomponents.rb\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003erequire 'synchromesh'\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eFinally, you need to add an initialiser \u003ccode\u003econfig/initializers/synchromesh.rb\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003e# config/initializers/synchromesh.rb\nSynchromesh.configuration do |config|\n  # this is the initialiser for polling, see the synchromesh\n  # documentation for using pusher.com\n  config.transport = :simple_poller\n  config.channel_prefix = \u0026quot;synchromesh\u0026quot;\n  config.opts = {\n    seconds_between_poll: 1.second,\n    seconds_polled_data_will_be_retained: 1.hour\n  }\nend\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eRestart your server, open two browser windows and be amazed to see any new posts added to one session magically appearing in the other!\u003c/p\u003e\n\u003cp\u003eTodo:\u003cbr /\u003e\n+ Reactrb Router\u003c/p\u003e\n\u003ch2 id=\"reactrb-hot-reloader-and-opal-irb\"\u003e\u003ca name=\"user-content-reactrb-hot-reloader-and-opal-irb\" href=\"#reactrb-hot-reloader-and-opal-irb\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eReactrb Hot-reloader and Opal IRB\u003c/h2\u003e\n\u003cp\u003eBefore we go any further, let\u0026rsquo;s install too fantastic tools written by Forrest Chang:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/fkchang/opal-hot-reloader\"\u003eOpal Hot Reloader\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/fkchang/opal-console\"\u003eOpal Console\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eOpal Hot Loader is for pure programmer joy (not having to reload the page to compile your source) and the Opal console is incredibly useful to test how Ruby code compiles to JavaScript.\u003c/p\u003e\n\u003cp\u003eWe are also going to add the Foreman gem to run our Rails server and the Hot Loader service for us.\u003c/p\u003e\n\u003cp\u003eAdd the following lines to your \u003ccode\u003egemfile\u003c/code\u003e and run \u003ccode\u003ebundle\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003egem 'opal_hot_reloader', git: 'https://github.com/fkchang/opal-hot-reloader.git'\ngem 'foreman'\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003ebundle install\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eModify your \u003ccode\u003ecomponents.rb\u003c/code\u003e, adding the following lines inside the if statement so they only run on the client and not as part of the server pre-rendering process:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby\"\u003erequire 'opal_hot_reloader'\nOpalHotReloader.listen(25222, true)\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eThen modify your \u003ccode\u003eprocfile\u003c/code\u003e so that the Hot Loader service will start whenever you start your server:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"text\"\u003erails: bundle exec rails server\nhotloader: opal-hot-reloader -p 25222 -d app/views/components\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eTo start both servers:\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eforeman start\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eRefresh your browser for the last time and try modifying your \u003ccode\u003eshow.rb\u003c/code\u003e component and you should see your changes appearing magically in your browser as you save. Pure joy.  \u003c/p\u003e\n\u003ch2 id=\"further-reading\"\u003e\u003ca name=\"user-content-further-reading\" href=\"#further-reading\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eFurther reading\u003c/h2\u003e\n\u003ch3 id=\"other-reactrb-tutorials-and-examples\"\u003e\u003ca name=\"user-content-other-reactrb-tutorials-and-examples\" href=\"#other-reactrb-tutorials-and-examples\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eOther Reactrb tutorials and examples\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/loicboutet/reactrb_tutorial\"\u003eGetting started with Reactrb and Rails\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/reactrb/reactrb.github.io/blob/master/docs/tutorial.md\"\u003eChatRB Demo App\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/loicboutet/reactivetodo\"\u003eReactive Record sample ToDo app\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/reactrb/reactrb.github.io/wiki/Sending-data-from-deeply-nested-components\"\u003eFlux pattern in Reactrb\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/fkchang/getting-started-reactrb-webpack\"\u003eGetting with Reactrb, React Bootstrap and Webpack\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"other-reactrb-resources\"\u003e\u003ca name=\"user-content-other-reactrb-resources\" href=\"#other-reactrb-resources\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eOther Reactrb resources\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://reactrb.org/\"\u003eReactrb website\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/reactrb/reactrb\"\u003eReactrb GitHub site\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"reactrb-is-powered-by-react\"\u003e\u003ca name=\"user-content-reactrb-is-powered-by-react\" href=\"#reactrb-is-powered-by-react\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eReactrb is powered by React\u003c/h3\u003e\n\u003cp\u003eReactrb and friends are in most cases simple DSL Ruby wrappers to the underlying native JavaScript libraries and React Components. It is really important to have a solid grip on how these technologies work to complement your understanding of Reactrb. Most searches for help on Google will take you to examples written in JSX or ES6 JavaScript but you will learn over time to transalte this to Reactrb equivalents. To make headway with Reactrb you do need a solid understanding of the underlying philosophy of React and its component based architecture. The \u0026lsquo;Thinking in React\u0026rsquo; tutorial below is an excellent place to start. (Make sure you see the Flux pattern in Reactrb above for an example of how to communicate between grandparent and child components).   \u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://facebook.github.io/react/docs/thinking-in-react.html\"\u003eThinking in React\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://facebook.github.io/react/docs/getting-started.html\"\u003eReact\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/reactjs/react-router\"\u003eReact Router\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://react-bootstrap.github.io/\"\u003eReact Bootstrap\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"opal-under-the-covers\"\u003e\u003ca name=\"user-content-opal-under-the-covers\" href=\"#opal-under-the-covers\" class=\"headeranchor-link\" aria-hidden=\"true\"\u003e\u003cspan class=\"headeranchor\"\u003e\u003c/span\u003e\u003c/a\u003eOpal under the covers\u003c/h3\u003e\n\u003cp\u003eReactrb is a DSL wrapper of React which uses Opal to compile Ruby code to ES5 native JavaScript. If you have not used Opal before then you should at a minimum read the excellent guides as they will teach you enough to get you started with Reactrb.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://opalrb.org/\"\u003eOpal\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://opalrb.org/docs/guides/v0.9.2/index.html\"\u003eOpal Guides\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=vhIrrlcWphU\"\u003eTo see the full power of Opal in action watch this video\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/article\u003e\u003c/body\u003e\u003c/html\u003e","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffzingg%2Fhyperloop-showcase","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffzingg%2Fhyperloop-showcase","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffzingg%2Fhyperloop-showcase/lists"}