Skip to content

Commit 9632e9f

Browse files
committedNov 28, 2015
React app displaying messages.
1 parent a93877a commit 9632e9f

File tree

11 files changed

+163
-54
lines changed

11 files changed

+163
-54
lines changed
 

‎Gemfile

+8
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ gem 'sdoc', '~> 0.4.0', group: :doc
3535
# Slack Bot
3636
gem 'slack-ruby-bot'
3737

38+
# HAML
39+
gem 'haml-rails'
40+
41+
# React
42+
gem 'react-rails'
43+
gem 'sprockets-coffee-react'
44+
gem 'js-routes'
45+
3846
group :development, :test do
3947
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
4048
gem 'byebug'

‎Gemfile.lock

+42
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,24 @@ GEM
3838
tzinfo (~> 1.1)
3939
addressable (2.3.8)
4040
arel (6.0.3)
41+
babel-source (5.8.34)
42+
babel-transpiler (0.7.0)
43+
babel-source (>= 4.0, < 6)
44+
execjs (~> 2.0)
4145
binding_of_caller (0.7.2)
4246
debug_inspector (>= 0.0.1)
4347
builder (3.2.2)
4448
byebug (8.2.1)
4549
coffee-rails (4.1.0)
4650
coffee-script (>= 2.2.0)
4751
railties (>= 4.0.0, < 5.0)
52+
coffee-react (3.0.1)
53+
execjs
4854
coffee-script (2.4.1)
4955
coffee-script-source
5056
execjs
5157
coffee-script-source (1.10.0)
58+
connection_pool (2.2.0)
5259
debug_inspector (0.0.2)
5360
diff-lcs (1.2.5)
5461
erubis (2.7.0)
@@ -72,7 +79,20 @@ GEM
7279
launchy (~> 2.4)
7380
globalid (0.3.6)
7481
activesupport (>= 4.1.0)
82+
haml (4.0.7)
83+
tilt
84+
haml-rails (0.9.0)
85+
actionpack (>= 4.0.1)
86+
activesupport (>= 4.0.1)
87+
haml (>= 4.0.6, < 5.0)
88+
html2haml (>= 1.0.1)
89+
railties (>= 4.0.1)
7590
hashie (3.4.3)
91+
html2haml (2.0.0)
92+
erubis (~> 2.7.0)
93+
haml (~> 4.0.0)
94+
nokogiri (~> 1.6.0)
95+
ruby_parser (~> 3.5)
7696
i18n (0.7.0)
7797
jbuilder (2.3.2)
7898
activesupport (>= 3.0.0, < 5)
@@ -81,6 +101,9 @@ GEM
81101
rails-dom-testing (~> 1.0)
82102
railties (>= 4.2.0)
83103
thor (>= 0.14, < 2.0)
104+
js-routes (1.1.2)
105+
railties (>= 3.2)
106+
sprockets-rails
84107
json (1.8.3)
85108
launchy (2.4.3)
86109
addressable (~> 2.3)
@@ -125,6 +148,13 @@ GEM
125148
thor (>= 0.18.1, < 2.0)
126149
rake (10.4.2)
127150
rdoc (4.2.0)
151+
react-rails (1.5.0)
152+
babel-transpiler (>= 0.7.0)
153+
coffee-script-source (~> 1.8)
154+
connection_pool
155+
execjs
156+
rails (>= 3.2)
157+
tilt
128158
rspec-core (3.4.1)
129159
rspec-support (~> 3.4.0)
130160
rspec-expectations (3.4.0)
@@ -142,6 +172,8 @@ GEM
142172
rspec-mocks (~> 3.4.0)
143173
rspec-support (~> 3.4.0)
144174
rspec-support (3.4.1)
175+
ruby_parser (3.7.2)
176+
sexp_processor (~> 4.1)
145177
sass (3.4.19)
146178
sass-rails (5.0.4)
147179
railties (>= 4.0.0, < 5.0)
@@ -152,6 +184,7 @@ GEM
152184
sdoc (0.4.1)
153185
json (~> 1.7, >= 1.7.7)
154186
rdoc (~> 4.0)
187+
sexp_processor (4.6.0)
155188
slack-ruby-bot (0.4.5)
156189
activesupport
157190
giphy (~> 2.0.2)
@@ -167,6 +200,11 @@ GEM
167200
spring (1.4.4)
168201
sprockets (3.4.1)
169202
rack (> 1, < 3)
203+
sprockets-coffee-react (3.0.1)
204+
coffee-react (>= 3.0.1)
205+
coffee-script
206+
sprockets
207+
tilt
170208
sprockets-rails (2.3.3)
171209
actionpack (>= 3.0)
172210
activesupport (>= 3.0)
@@ -197,14 +235,18 @@ PLATFORMS
197235
DEPENDENCIES
198236
byebug
199237
coffee-rails (~> 4.1.0)
238+
haml-rails
200239
jbuilder (~> 2.0)
201240
jquery-rails
241+
js-routes
202242
rails (= 4.2.4)
243+
react-rails
203244
rspec-rails
204245
sass-rails (~> 5.0)
205246
sdoc (~> 0.4.0)
206247
slack-ruby-bot
207248
spring
249+
sprockets-coffee-react
208250
sqlite3
209251
turbolinks
210252
uglifier (>= 1.3.0)

‎app/assets/javascripts/application.js

+3
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,7 @@
1313
//= require jquery
1414
//= require jquery_ujs
1515
//= require turbolinks
16+
//= require react
17+
//= require react_ujs
18+
//= require js-routes
1619
//= require_tree .
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# @cjsx React.DOM
2+
3+
@Message = React.createClass
4+
displayName: 'Message'
5+
render: ->
6+
# let's use this add-on to set the main div's class names
7+
cx = React.addons.classSet
8+
9+
# here we use the calculated classes
10+
<div className="message">
11+
{@props.data.id}: {@props.data.message?.text}
12+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# @cjsx React.DOM
2+
3+
@MessagesSection = React.createClass
4+
# Display name used for debugging
5+
displayName: 'MessagesSection'
6+
7+
# Invoked before the component is mounted and provides the initial
8+
# state for the render method.
9+
getInitialState: ->
10+
# We'll change it to true once we fetch data
11+
didFetchData: false
12+
# The messages JSON array used to display the messages in the view
13+
messages: []
14+
15+
# Invoked right after the component renders
16+
componentDidMount: ->
17+
# Lets fetch all the messages...
18+
@_fetchMessages()
19+
setInterval(@_fetchMessages, 1000);
20+
21+
# AJAX call to our MessagesController
22+
_fetchMessages: ()->
23+
$.ajax
24+
url: Routes.messages_path()
25+
.done @_fetchDataDone
26+
.fail @_fetchDataFail
27+
28+
# If the AJAX call is successful...
29+
_fetchDataDone: (data, textStatus, jqXHR) ->
30+
# We change the state of the component. This will cause the component and
31+
# it's children to render again
32+
@setState
33+
didFetchData: true
34+
messages: data
35+
36+
# If errors in AJAX call...
37+
_fetchDataFail: (xhr, status, err) =>
38+
console.error @props.url, status, err.toString()
39+
40+
# How the component is going to be rendered to the user depending on it's
41+
# props and state...
42+
render: ->
43+
# The collection of Message components we are going to display
44+
# using the messages stored in the component's state
45+
messagesNode = @state.messages.map (message) ->
46+
# Message component with a data property containing all the JSON
47+
# attributes we are going to use to display it to the user
48+
<Message key={message.id} data={message}/>
49+
50+
# HTML displayed if no messages found in it's state
51+
noDataNode =
52+
<div className="warning">
53+
<h4>No messages found...</h4>
54+
</div>
55+
56+
# Here starts the render result
57+
<div>
58+
<div className="messages-wrapper">
59+
{
60+
# If there are messages render the messages...
61+
if @state.messages.length > 0
62+
messagesNode
63+
# If has fetched data and no messages found, render the
64+
# warning message instead
65+
else if @state.didFetchData
66+
noDataNode
67+
}
68+
</div>
69+
</div>

‎app/controllers/home_controller.rb

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class HomeController < ApplicationController
2+
def index
3+
end
4+
end
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class MessagesController < ApplicationController
2+
def index
3+
data = (1..10).map do |i|
4+
{ id: i, message: Rails.cache.read(i) }
5+
end
6+
render json: data
7+
end
8+
end

‎app/views/home/index.html.haml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
%section
2+
%header
3+
%h1 Tattletale
4+
5+
= react_component 'MessagesSection', {}, :div

‎bot/say.rb

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
class Say < SlackRubyBot::Commands::Base
2+
@id = 0
3+
4+
def self.next_id
5+
@id = @id % 10 + 1
6+
end
7+
28
command 'say' do |client, data, match|
9+
Rails.cache.write next_id, { text: match['expression'] }
310
send_message client, data.channel, match['expression']
411
end
512
end

‎config/application.rb

+3
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,8 @@ class Application < Rails::Application
3131

3232
# Do not swallow errors in after_commit/after_rollback callbacks.
3333
config.active_record.raise_in_transactional_callbacks = true
34+
35+
# React config
36+
config.react.addons = true
3437
end
3538
end

‎config/routes.rb

+2-54
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,4 @@
11
Rails.application.routes.draw do
2-
# The priority is based upon order of creation: first created -> highest priority.
3-
# See how all your routes lay out with "rake routes".
4-
5-
# You can have the root of your site routed with "root"
6-
# root 'welcome#index'
7-
8-
# Example of regular route:
9-
# get 'products/:id' => 'catalog#view'
10-
11-
# Example of named route that can be invoked with purchase_url(id: product.id)
12-
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
13-
14-
# Example resource route (maps HTTP verbs to controller actions automatically):
15-
# resources :products
16-
17-
# Example resource route with options:
18-
# resources :products do
19-
# member do
20-
# get 'short'
21-
# post 'toggle'
22-
# end
23-
#
24-
# collection do
25-
# get 'sold'
26-
# end
27-
# end
28-
29-
# Example resource route with sub-resources:
30-
# resources :products do
31-
# resources :comments, :sales
32-
# resource :seller
33-
# end
34-
35-
# Example resource route with more complex sub-resources:
36-
# resources :products do
37-
# resources :comments
38-
# resources :sales do
39-
# get 'recent', on: :collection
40-
# end
41-
# end
42-
43-
# Example resource route with concerns:
44-
# concern :toggleable do
45-
# post 'toggle'
46-
# end
47-
# resources :posts, concerns: :toggleable
48-
# resources :photos, concerns: :toggleable
49-
50-
# Example resource route within a namespace:
51-
# namespace :admin do
52-
# # Directs /admin/products/* to Admin::ProductsController
53-
# # (app/controllers/admin/products_controller.rb)
54-
# resources :products
55-
# end
2+
root 'home#index'
3+
resources :messages, only: :index
564
end

0 commit comments

Comments
 (0)