LoginSignup
3
6

More than 5 years have passed since last update.

Rails5(ActionCable)とReact-railsで簡易チャットアプリを作ってみる

Last updated at Posted at 2016-11-11

はじめに

Rails5とActionCableとreact-railsを使って簡易チャットアプリを作りました。
それぞれ写経したものを組み合わせた感じです 
突っ込みどころ満載だと思いますが、ご容赦下さい

実行環境

  • Ruby 2.3.0
  • Rails 5.0.0.beta3
  • react-rails 1.6.2
  • redis 3.2.2

参考記事

準備

  • Rubyのバージョンを確認(2.2.1以上になっているか)

アプリケーションの作成

# bundle install は一旦スキップで
rails new rails5-app --skip-bundle

Gemを追加

# react-rails
gem 'react-rails'

# redisのコメントアウトを外す
gem 'redis', '~> 3.0'

bundle install

bundle install --path vendor/bundle

migrate(特にDBを使用する予定はありませんが・・・)

# rails5からコマンドがrakeからrailsに変わっているので注意
bundle exec rails db:craete
bundle exec rails db:migrate

react-railsをインストール

bundle exec rails g react:install

コントローラを作成

# showアクションを持つroomコントローラ
bundle exec rails g controller room show

チャンネルを作成

# speakアクションを持つroomチャンネルを作成
bundle exec rails g channel room speak

コンポーネントを作成

bundle exec rails g react:component CommentBox

サーバ側の実装

チャンネルの実装

app/channels/room_channel.rb
class RoomChannel < ApplicationCable::Channel
  # おまじない(調査中です)
  def subscribed
    stream_from "room_channel"
  end

  # 省略

  # クライアントから来たspeakをハンドリング
  def speak(data)
    ActionCable.server.broadcast 'room_channel', comment: data['comment']
  end
end

ルーティングを設定

config/route.rb
Rails.application.routes.draw do
  root 'rooms#show'

  # コメントアウトを外す
  mount ActionCable.server => '/cable'
end

クライアント側の実装

ActionCableを有効に

app/assets/javascripts/cable.coffee
# コメントアウトを外す
@App ||= {}
App.cable = ActionCable.createConsumer()

Railsのviewに追記

app/views/rooms/show.html.erb
<%= react_component('CommentBox')%>

コンポーネントの実装(長いので分けます)

app/assets/javascripts/components/comment_box.js.jsx
var CommentBox = React.createClass({
  getInitialState: function() {
    return {comments: []};
  },
  componentDidMount: function() {
    this.setupRoomChat();
  },
  updateCommentList: function(comment) {
    comment.id = new Date().getTime();
    this.setState({ comments: this.state.comments.concat([comment]) });
  },
  setupRoomChat: function() {
    App.room = App.cable.subscriptions.create("RoomChannel", {
      connected: function() {},
      disconnected: function() {},
      received: function(data) {
        // サーバからメッセージを受信
        this.updateCommentList(data.comment);
      },
      // ここが1番謎です(解明中)
      updateCommentList: this.updateCommentList.bind(this),
      speak: function(comment) {
        return this.perform('speak', {
          comment: comment
        });
      }
    });
  },
  handleCommentSubmit: function(comment) {
    // サーバにメッセージを飛ばす
    App.room.speak(comment);
  },
  render: function() {
    return (
      <div className="commentBox">
        <h1>Chat Room</h1>
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
        <CommentList comments={this.state.comments} />
      </div>
    );
  }
});
app/assets/javascripts/components/comment_box.js.jsx
// ...省略
var CommentForm = React.createClass({
  onClick: function(e) {
    e.preventDefault();
    var text = ReactDOM.findDOMNode(this.refs.text).value.trim();
    if (!text) {
      return;
    }
    this.props.onCommentSubmit({text: text});
    ReactDOM.findDOMNode(this.refs.text).value = '';
    return;
  },
  render: function() {
    return (
      <div className="commentForm">
        <div>
          <input type="text" placeholder="Say something..." ref="text" />
        </div>
        <div>
          <button type="button" onClick={this.onClick}>Post</button>
        </div>
      </div>
    );
  }
});

app/assets/javascripts/components/comment_box.js.jsx
// ...省略
var CommentList = React.createClass({
  render: function() {
    var commentNodes = this.props.comments.map(function (comment) {
      return (
        <Comment key={comment.id}>
          {comment.text}
        </Comment>
      );
    });
    return (
      <div className="commentList">
        {commentNodes}
      </div>
    );
  }
});

var Comment = React.createClass({
  render: function() {
    return (
      <div className="comment">
        {this.props.children}
      </div>
    );
  }
});

実行

bundle exec rails s

確認

ブラウザからlocalhost:3000にアクセス
2窓で上手くチャット出来ますでしょうか

最後に

ReactのRの字もわからないのでFluxも何を使っていません。
怪しい箇所が何ヶ所もあるので何かあれば教えて頂けると幸いです

github

一応ここにあります。
https://github.com/TekkaMK/rails5-react-chat

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6