├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── app ├── assets │ ├── images │ │ └── .keep │ ├── javascripts │ │ ├── application.js │ │ ├── comments.js.jsx │ │ └── pages.js.coffee │ └── stylesheets │ │ ├── application.css.scss │ │ ├── comments.css.scss │ │ ├── pages.css.scss │ │ └── scaffolds.css.scss ├── controllers │ ├── application_controller.rb │ ├── comments_controller.rb │ ├── concerns │ │ └── .keep │ └── pages_controller.rb ├── helpers │ ├── application_helper.rb │ ├── comments_helper.rb │ └── pages_helper.rb ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── comment.rb │ └── concerns │ │ └── .keep └── views │ ├── comments │ ├── _form.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── index.json.jbuilder │ ├── new.html.erb │ ├── show.html.erb │ └── show.json.jbuilder │ ├── layouts │ └── application.html.erb │ └── pages │ └── index.html.erb ├── bin ├── bundle ├── rails ├── rake ├── setup └── spring ├── config.ru ├── config ├── application.rb ├── boot.rb ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── cookies_serializer.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── session_store.rb │ └── wrap_parameters.rb ├── locales │ └── en.yml ├── routes.rb └── secrets.yml ├── db ├── migrate │ └── 20140823052830_create_comments.rb ├── schema.rb └── seeds.rb ├── lib ├── assets │ └── .keep └── tasks │ └── .keep ├── log └── .keep ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico └── robots.txt ├── test ├── controllers │ ├── .keep │ ├── comments_controller_test.rb │ └── pages_controller_test.rb ├── fixtures │ ├── .keep │ └── comments.yml ├── helpers │ └── .keep ├── integration │ └── .keep ├── mailers │ └── .keep ├── models │ ├── .keep │ └── comment_test.rb └── test_helper.rb └── vendor └── assets ├── javascripts └── .keep └── stylesheets └── .keep /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-journal 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/*.log 16 | /tmp 17 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | 4 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 5 | gem 'rails', '4.2.0.beta1' 6 | # Use sqlite3 as the database for Active Record 7 | gem 'sqlite3', group: :development 8 | gem 'pg', group: :production 9 | 10 | gem 'rails_12factor' 11 | 12 | # Use SCSS for stylesheets 13 | gem 'sass-rails', '~> 5.0.0.beta1' 14 | # Use Uglifier as compressor for JavaScript assets 15 | gem 'uglifier', '>= 1.3.0' 16 | # Use CoffeeScript for .js.coffee assets and views 17 | gem 'coffee-rails', '~> 4.0.0' 18 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes 19 | # gem 'therubyracer', platforms: :ruby 20 | 21 | # Use jquery as the JavaScript library 22 | gem 'jquery-rails' 23 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks 24 | gem 'turbolinks' 25 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 26 | gem 'jbuilder', '~> 2.0' 27 | # bundle exec rake doc:rails generates the API under doc/api. 28 | gem 'sdoc', '~> 0.4.0', group: :doc 29 | 30 | # Use ActiveModel has_secure_password 31 | # gem 'bcrypt', '~> 3.1.7' 32 | 33 | # Use Rails Html Sanitizer for HTML sanitization 34 | gem 'rails-html-sanitizer', '~> 1.0' 35 | 36 | # Use Unicorn as the app server 37 | # gem 'unicorn' 38 | 39 | # Use Capistrano for deployment 40 | # gem 'capistrano-rails', group: :development 41 | 42 | group :development, :test do 43 | # Call 'debugger' anywhere in the code to stop execution and get a debugger console 44 | gem 'byebug' 45 | 46 | # Access an IRB console on exceptions page and /console in development 47 | gem 'web-console', '~> 2.0.0.beta2' 48 | 49 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 50 | gem 'spring' 51 | end 52 | 53 | gem 'react-rails', github: 'reactjs/react-rails', branch: 'master' 54 | 55 | gem 'showdown-rails' 56 | 57 | gem 'bootstrap-sass' 58 | gem 'autoprefixer-rails' 59 | 60 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: git://github.com/reactjs/react-rails.git 3 | revision: b4051e111aa8ec3e68b8924e1f13598f18b475c6 4 | branch: master 5 | specs: 6 | react-rails (1.0.0.pre) 7 | connection_pool 8 | execjs 9 | rails (>= 3.1) 10 | react-source (= 0.11.1) 11 | 12 | GEM 13 | remote: https://rubygems.org/ 14 | specs: 15 | actionmailer (4.2.0.beta1) 16 | actionpack (= 4.2.0.beta1) 17 | actionview (= 4.2.0.beta1) 18 | mail (~> 2.5, >= 2.5.4) 19 | rails-dom-testing (~> 1.0, >= 1.0.2) 20 | actionpack (4.2.0.beta1) 21 | actionview (= 4.2.0.beta1) 22 | activesupport (= 4.2.0.beta1) 23 | rack (~> 1.6.0.beta) 24 | rack-test (~> 0.6.2) 25 | rails-deprecated_sanitizer (~> 1.0, >= 1.0.2) 26 | rails-dom-testing (~> 1.0, >= 1.0.2) 27 | actionview (4.2.0.beta1) 28 | activesupport (= 4.2.0.beta1) 29 | builder (~> 3.1) 30 | erubis (~> 2.7.0) 31 | rails-deprecated_sanitizer (~> 1.0, >= 1.0.2) 32 | rails-dom-testing (~> 1.0, >= 1.0.2) 33 | activejob (4.2.0.beta1) 34 | globalid (>= 0.2.3) 35 | activemodel (4.2.0.beta1) 36 | activesupport (= 4.2.0.beta1) 37 | builder (~> 3.1) 38 | activerecord (4.2.0.beta1) 39 | activemodel (= 4.2.0.beta1) 40 | activesupport (= 4.2.0.beta1) 41 | arel (>= 6.0.0.beta1, < 6.1) 42 | activesupport (4.2.0.beta1) 43 | i18n (>= 0.7.0.beta1, < 0.8) 44 | json (~> 1.7, >= 1.7.7) 45 | minitest (~> 5.1) 46 | thread_safe (~> 0.1) 47 | tzinfo (~> 1.1) 48 | arel (6.0.0.beta1) 49 | autoprefixer-rails (3.0.0.20140821) 50 | execjs 51 | binding_of_caller (0.7.3.pre1) 52 | debug_inspector (>= 0.0.1) 53 | bootstrap-sass (3.2.0.1) 54 | sass (~> 3.2) 55 | builder (3.2.2) 56 | byebug (3.2.0) 57 | columnize (~> 0.8) 58 | debugger-linecache (~> 1.2) 59 | coffee-rails (4.0.1) 60 | coffee-script (>= 2.2.0) 61 | railties (>= 4.0.0, < 5.0) 62 | coffee-script (2.3.0) 63 | coffee-script-source 64 | execjs 65 | coffee-script-source (1.7.1) 66 | columnize (0.8.9) 67 | connection_pool (2.0.0) 68 | debug_inspector (0.0.2) 69 | debugger-linecache (1.2.0) 70 | erubis (2.7.0) 71 | execjs (2.2.1) 72 | globalid (0.2.3) 73 | activesupport (>= 4.1.0) 74 | hike (1.2.3) 75 | i18n (0.7.0.beta1) 76 | jbuilder (2.1.3) 77 | activesupport (>= 3.0.0, < 5) 78 | multi_json (~> 1.2) 79 | jquery-rails (3.1.1) 80 | railties (>= 3.0, < 5.0) 81 | thor (>= 0.14, < 2.0) 82 | json (1.8.1) 83 | loofah (2.0.1) 84 | nokogiri (>= 1.5.9) 85 | mail (2.6.1) 86 | mime-types (>= 1.16, < 3) 87 | mime-types (2.3) 88 | mini_portile (0.6.0) 89 | minitest (5.4.0) 90 | multi_json (1.10.1) 91 | nokogiri (1.6.3.1) 92 | mini_portile (= 0.6.0) 93 | pg (0.17.1) 94 | rack (1.6.0.beta) 95 | rack-test (0.6.2) 96 | rack (>= 1.0) 97 | rails (4.2.0.beta1) 98 | actionmailer (= 4.2.0.beta1) 99 | actionpack (= 4.2.0.beta1) 100 | actionview (= 4.2.0.beta1) 101 | activejob (= 4.2.0.beta1) 102 | activemodel (= 4.2.0.beta1) 103 | activerecord (= 4.2.0.beta1) 104 | activesupport (= 4.2.0.beta1) 105 | bundler (>= 1.3.0, < 2.0) 106 | railties (= 4.2.0.beta1) 107 | sprockets-rails (~> 3.0.0.beta1) 108 | rails-deprecated_sanitizer (1.0.2) 109 | activesupport (>= 4.2.0.alpha) 110 | rails-dom-testing (1.0.2) 111 | activesupport 112 | nokogiri (~> 1.6.0) 113 | rails-deprecated_sanitizer (>= 1.0.1) 114 | rails-html-sanitizer (1.0.0) 115 | loofah (~> 2.0) 116 | rails_12factor (0.0.2) 117 | rails_serve_static_assets 118 | rails_stdout_logging 119 | rails_serve_static_assets (0.0.2) 120 | rails_stdout_logging (0.0.3) 121 | railties (4.2.0.beta1) 122 | actionpack (= 4.2.0.beta1) 123 | activesupport (= 4.2.0.beta1) 124 | rake (>= 0.8.7) 125 | thor (>= 0.18.1, < 2.0) 126 | rake (10.3.2) 127 | rdoc (4.1.1) 128 | json (~> 1.4) 129 | react-source (0.11.1) 130 | sass (3.4.1) 131 | sass-rails (5.0.0.beta1) 132 | railties (>= 4.0.0, < 5.0) 133 | sass (~> 3.2) 134 | sprockets (~> 2.12) 135 | sprockets-rails (>= 2.0, < 4.0) 136 | sdoc (0.4.1) 137 | json (~> 1.7, >= 1.7.7) 138 | rdoc (~> 4.0) 139 | showdown-rails (0.0.4) 140 | actionpack (>= 3.1) 141 | railties (>= 3.1) 142 | spring (1.1.3) 143 | sprockets (2.12.1) 144 | hike (~> 1.2) 145 | multi_json (~> 1.0) 146 | rack (~> 1.0) 147 | tilt (~> 1.1, != 1.3.0) 148 | sprockets-rails (3.0.0.beta1) 149 | actionpack (>= 4.0) 150 | activesupport (>= 4.0) 151 | sprockets (~> 2.8) 152 | sqlite3 (1.3.9) 153 | thor (0.19.1) 154 | thread_safe (0.3.4) 155 | tilt (1.4.1) 156 | turbolinks (2.3.0) 157 | coffee-rails 158 | tzinfo (1.2.2) 159 | thread_safe (~> 0.1) 160 | uglifier (2.5.3) 161 | execjs (>= 0.3.0) 162 | json (>= 1.8.0) 163 | web-console (2.0.0.beta3) 164 | activemodel (~> 4.0) 165 | binding_of_caller (= 0.7.3.pre1) 166 | railties (~> 4.0) 167 | sprockets-rails (>= 2.0, < 4.0) 168 | 169 | PLATFORMS 170 | ruby 171 | 172 | DEPENDENCIES 173 | autoprefixer-rails 174 | bootstrap-sass 175 | byebug 176 | coffee-rails (~> 4.0.0) 177 | jbuilder (~> 2.0) 178 | jquery-rails 179 | pg 180 | rails (= 4.2.0.beta1) 181 | rails-html-sanitizer (~> 1.0) 182 | rails_12factor 183 | react-rails! 184 | sass-rails (~> 5.0.0.beta1) 185 | sdoc (~> 0.4.0) 186 | showdown-rails 187 | spring 188 | sqlite3 189 | turbolinks 190 | uglifier (>= 1.3.0) 191 | web-console (~> 2.0.0.beta2) 192 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is an example of using the react-rails gem to integrate Rails with React. 2 | 3 | Detailed instructions can be found here: http://www.railsonmaui.com/blog/2014/09/29/react-on-rails-4-dot-2-simple-tutorial/ 4 | 5 | The author, Justin Gordon, developed an alternative technique to the gem, described here: 6 | http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/ 7 | 8 | Please see this git repo: https://github.com/justin808/react-webpack-rails-tutorial 9 | 10 | If you'd like to improve this example, I'm happy to take pull requests! 11 | 12 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justin808/react-rails-tutorial/7a0844407ab424159d8487080aa1e67a73eb4fdb/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require turbolinks 16 | //= require bootstrap-sprockets 17 | //= require showdown 18 | //= require react 19 | //= require_tree . 20 | -------------------------------------------------------------------------------- /app/assets/javascripts/comments.js.jsx: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 3 | var converter = new Showdown.converter(); 4 | 5 | var Comment = React.createClass({ 6 | render: function() { 7 | var rawMarkup = converter.makeHtml(this.props.children.toString()); 8 | return ( 9 |
10 |
11 |

12 | {this.props.author} 13 |

14 |
15 |
16 | 17 |
18 |
19 | ); 20 | } 21 | }); 22 | 23 | var CommentBox = React.createClass({ 24 | loadCommentsFromServer: function() { 25 | $.ajax({ 26 | url: this.props.url, 27 | dataType: 'json', 28 | success: function(data) { 29 | this.setState({data: data}); 30 | }.bind(this), 31 | error: function(xhr, status, err) { 32 | console.error(this.props.url, status, err.toString()); 33 | }.bind(this) 34 | }); 35 | }, 36 | handleCommentSubmit: function(comment) { 37 | var comments = this.state.data; 38 | comments.push(comment); 39 | this.setState({data: comments}, function() { 40 | // `setState` accepts a callback. To avoid (improbable) race condition, 41 | // `we'll send the ajax request right after we optimistically set the new 42 | // `state. 43 | $.ajax({ 44 | url: this.props.url, 45 | dataType: 'json', 46 | type: 'POST', 47 | data: { comment: comment }, 48 | success: function(data) { 49 | }.bind(this), 50 | error: function(xhr, status, err) { 51 | comments.pop(); 52 | this.setState({data: comments}); 53 | console.error(this.props.url, status, err.toString()); 54 | }.bind(this) 55 | }); 56 | }); 57 | }, 58 | getInitialState: function() { 59 | return {data: []}; 60 | }, 61 | componentDidMount: function() { 62 | this.loadCommentsFromServer(); 63 | setInterval(this.loadCommentsFromServer, this.props.pollInterval); 64 | }, 65 | render: function() { 66 | return ( 67 |
68 |

Comments

69 | 70 | 71 |
72 | ); 73 | } 74 | }); 75 | 76 | var CommentList = React.createClass({ 77 | render: function() { 78 | var commentNodes = this.props.data.map(function(comment, index) { 79 | return ( 80 | // `key` is a React-specific concept and is not mandatory for the 81 | // purpose of this tutorial. if you're curious, see more here: 82 | // http://facebook.github.io/react/docs/multiple-components.html#dynamic-children 83 | 84 | {comment.text} 85 | 86 | ); 87 | }); 88 | return ( 89 |
90 | {commentNodes} 91 |
92 | ); 93 | } 94 | }); 95 | 96 | var CommentForm = React.createClass({ 97 | handleSubmit: function(e) { 98 | e.preventDefault(); 99 | var author = this.refs.author.getDOMNode().value.trim(); 100 | var text = this.refs.text.getDOMNode().value.trim(); 101 | if (!text || !author) { 102 | return; 103 | } 104 | this.props.onCommentSubmit({author: author, text: text}); 105 | this.refs.author.getDOMNode().value = ''; 106 | this.refs.text.getDOMNode().value = ''; 107 | return; 108 | }, 109 | render: function() { 110 | return ( 111 |
112 |
Add a Note
113 |
114 |
115 |
116 | 117 | 118 |
119 |
120 | 121 |