amazon-chime-sdk-rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +87 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +47 -0
  5. data/.yardopts +6 -0
  6. data/CHANGELOG.md +3 -0
  7. data/Gemfile +25 -0
  8. data/LICENSE +21 -0
  9. data/README.md +1109 -0
  10. data/Rakefile +20 -0
  11. data/amazon-chime-sdk-rails.gemspec +29 -0
  12. data/gemfiles/Gemfile.rails-5.0 +25 -0
  13. data/gemfiles/Gemfile.rails-5.1 +25 -0
  14. data/gemfiles/Gemfile.rails-5.2 +25 -0
  15. data/gemfiles/Gemfile.rails-6.0 +25 -0
  16. data/lib/amazon-chime-sdk-rails.rb +37 -0
  17. data/lib/chime_sdk/config.rb +90 -0
  18. data/lib/chime_sdk/controller/attendees.rb +128 -0
  19. data/lib/chime_sdk/controller/common.rb +202 -0
  20. data/lib/chime_sdk/controller/meetings.rb +192 -0
  21. data/lib/chime_sdk/meeting_coordinator.rb +184 -0
  22. data/lib/chime_sdk/version.rb +4 -0
  23. data/lib/generators/chime_sdk/controllers_generator.rb +104 -0
  24. data/lib/generators/chime_sdk/install_generator.rb +27 -0
  25. data/lib/generators/chime_sdk/js_generator.rb +67 -0
  26. data/lib/generators/chime_sdk/views_generator.rb +43 -0
  27. data/lib/generators/templates/chime_sdk.rb +28 -0
  28. data/lib/generators/templates/controllers/README +35 -0
  29. data/lib/generators/templates/controllers/meeting_attendees_controller.rb +106 -0
  30. data/lib/generators/templates/controllers/meetings_controller.rb +146 -0
  31. data/lib/generators/templates/views/meetings/index.html.erb +27 -0
  32. data/lib/generators/templates/views/meetings/show.html.erb +136 -0
  33. data/spec/factories/rooms.rb +5 -0
  34. data/spec/factories/users.rb +8 -0
  35. data/spec/generators/controllers_generator_spec.rb +113 -0
  36. data/spec/generators/install_generator_spec.rb +24 -0
  37. data/spec/generators/js_generator_spec.rb +26 -0
  38. data/spec/generators/views_generator_spec.rb +46 -0
  39. data/spec/rails_app/Rakefile +15 -0
  40. data/spec/rails_app/app/assets/config/manifest.js +2 -0
  41. data/spec/rails_app/app/assets/images/.keep +0 -0
  42. data/spec/rails_app/app/assets/javascripts/.keep +0 -0
  43. data/spec/rails_app/app/assets/stylesheets/application.css +15 -0
  44. data/spec/rails_app/app/assets/stylesheets/scaffolds.scss +65 -0
  45. data/spec/rails_app/app/controllers/api/meeting_attendees_controller.rb +3 -0
  46. data/spec/rails_app/app/controllers/api/meetings_controller.rb +3 -0
  47. data/spec/rails_app/app/controllers/api/rooms_controller.rb +3 -0
  48. data/spec/rails_app/app/controllers/application_controller.rb +11 -0
  49. data/spec/rails_app/app/controllers/entries_controller.rb +47 -0
  50. data/spec/rails_app/app/controllers/meeting_attendees_controller.rb +121 -0
  51. data/spec/rails_app/app/controllers/meetings_controller.rb +162 -0
  52. data/spec/rails_app/app/controllers/rooms_controller.rb +76 -0
  53. data/spec/rails_app/app/controllers/spa_controller.rb +6 -0
  54. data/spec/rails_app/app/javascript/App.vue +50 -0
  55. data/spec/rails_app/app/javascript/channels/consumer.js +6 -0
  56. data/spec/rails_app/app/javascript/channels/index.js +5 -0
  57. data/spec/rails_app/app/javascript/components/DeviseTokenAuth.vue +84 -0
  58. data/spec/rails_app/app/javascript/components/meetings/Index.vue +100 -0
  59. data/spec/rails_app/app/javascript/components/meetings/Meeting.vue +178 -0
  60. data/spec/rails_app/app/javascript/components/rooms/Index.vue +53 -0
  61. data/spec/rails_app/app/javascript/components/rooms/Show.vue +91 -0
  62. data/spec/rails_app/app/javascript/packs/application.js +17 -0
  63. data/spec/rails_app/app/javascript/packs/spa.js +14 -0
  64. data/spec/rails_app/app/javascript/router/index.js +74 -0
  65. data/spec/rails_app/app/javascript/store/index.js +37 -0
  66. data/spec/rails_app/app/models/application_record.rb +3 -0
  67. data/spec/rails_app/app/models/entry.rb +5 -0
  68. data/spec/rails_app/app/models/room.rb +12 -0
  69. data/spec/rails_app/app/models/user.rb +6 -0
  70. data/spec/rails_app/app/views/devise/registrations/new.html.erb +34 -0
  71. data/spec/rails_app/app/views/layouts/_header.html.erb +20 -0
  72. data/spec/rails_app/app/views/layouts/application.html.erb +18 -0
  73. data/spec/rails_app/app/views/meetings/index.html.erb +28 -0
  74. data/spec/rails_app/app/views/meetings/show.html.erb +136 -0
  75. data/spec/rails_app/app/views/rooms/_form.html.erb +22 -0
  76. data/spec/rails_app/app/views/rooms/_room.json.jbuilder +7 -0
  77. data/spec/rails_app/app/views/rooms/edit.html.erb +6 -0
  78. data/spec/rails_app/app/views/rooms/index.html.erb +27 -0
  79. data/spec/rails_app/app/views/rooms/index.json.jbuilder +1 -0
  80. data/spec/rails_app/app/views/rooms/new.html.erb +5 -0
  81. data/spec/rails_app/app/views/rooms/show.html.erb +42 -0
  82. data/spec/rails_app/app/views/rooms/show.json.jbuilder +1 -0
  83. data/spec/rails_app/app/views/spa/index.html.erb +1 -0
  84. data/spec/rails_app/babel.config.js +72 -0
  85. data/spec/rails_app/bin/bundle +114 -0
  86. data/spec/rails_app/bin/rails +9 -0
  87. data/spec/rails_app/bin/rake +9 -0
  88. data/spec/rails_app/bin/setup +36 -0
  89. data/spec/rails_app/bin/spring +17 -0
  90. data/spec/rails_app/bin/webpack +18 -0
  91. data/spec/rails_app/bin/webpack-dev-server +18 -0
  92. data/spec/rails_app/bin/yarn +11 -0
  93. data/spec/rails_app/config.ru +5 -0
  94. data/spec/rails_app/config/application.rb +21 -0
  95. data/spec/rails_app/config/boot.rb +4 -0
  96. data/spec/rails_app/config/cable.yml +10 -0
  97. data/spec/rails_app/config/credentials.yml.enc +1 -0
  98. data/spec/rails_app/config/database.yml +25 -0
  99. data/spec/rails_app/config/environment.rb +14 -0
  100. data/spec/rails_app/config/environments/development.rb +62 -0
  101. data/spec/rails_app/config/environments/production.rb +112 -0
  102. data/spec/rails_app/config/environments/test.rb +49 -0
  103. data/spec/rails_app/config/initializers/application_controller_renderer.rb +8 -0
  104. data/spec/rails_app/config/initializers/assets.rb +15 -0
  105. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  106. data/spec/rails_app/config/initializers/chime_sdk.rb +28 -0
  107. data/spec/rails_app/config/initializers/content_security_policy.rb +30 -0
  108. data/spec/rails_app/config/initializers/cookies_serializer.rb +5 -0
  109. data/spec/rails_app/config/initializers/devise.rb +311 -0
  110. data/spec/rails_app/config/initializers/devise_token_auth.rb +60 -0
  111. data/spec/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
  112. data/spec/rails_app/config/initializers/inflections.rb +16 -0
  113. data/spec/rails_app/config/initializers/mime_types.rb +4 -0
  114. data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
  115. data/spec/rails_app/config/locales/devise.en.yml +65 -0
  116. data/spec/rails_app/config/locales/en.yml +33 -0
  117. data/spec/rails_app/config/puma.rb +38 -0
  118. data/spec/rails_app/config/routes.rb +24 -0
  119. data/spec/rails_app/config/secrets.yml +8 -0
  120. data/spec/rails_app/config/spring.rb +6 -0
  121. data/spec/rails_app/config/storage.yml +34 -0
  122. data/spec/rails_app/config/webpack/development.js +5 -0
  123. data/spec/rails_app/config/webpack/environment.js +7 -0
  124. data/spec/rails_app/config/webpack/loaders/vue.js +6 -0
  125. data/spec/rails_app/config/webpack/production.js +5 -0
  126. data/spec/rails_app/config/webpack/test.js +5 -0
  127. data/spec/rails_app/config/webpacker.yml +97 -0
  128. data/spec/rails_app/db/migrate/20200912140231_devise_create_users.rb +45 -0
  129. data/spec/rails_app/db/migrate/20200912140352_add_tokens_to_users.rb +12 -0
  130. data/spec/rails_app/db/migrate/20200912140657_create_rooms.rb +9 -0
  131. data/spec/rails_app/db/migrate/20200912140749_create_entries.rb +10 -0
  132. data/spec/rails_app/db/schema.rb +49 -0
  133. data/spec/rails_app/db/seeds.rb +41 -0
  134. data/spec/rails_app/log/.keep +0 -0
  135. data/spec/rails_app/package.json +23 -0
  136. data/spec/rails_app/postcss.config.js +12 -0
  137. data/spec/rails_app/public/404.html +67 -0
  138. data/spec/rails_app/public/422.html +67 -0
  139. data/spec/rails_app/public/500.html +66 -0
  140. data/spec/rails_app/public/favicon.ico +0 -0
  141. data/spec/rails_app/public/robots.txt +1 -0
  142. data/spec/rails_app/tmp/.keep +0 -0
  143. data/spec/requests/atendees_spec.rb +182 -0
  144. data/spec/requests/meetings_spec.rb +433 -0
  145. data/spec/spec_helper.rb +35 -0
  146. metadata +400 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 58ba4a5120f7627c132916b953a9220df353788aef966f2a56f8915c3a0a9ef6
4
+ data.tar.gz: 2b59830799578d63ad1d87ec4cf5754be896974a7726ced42be3139adcedfd50
5
+ SHA512:
6
+ metadata.gz: b36d2ecafa05d835679ef5e7c8351a7c45f31b996010253b62fca9cc6b7cb0288fd3a0f4cbc5f985c654491afbd7d546acd98d409381d8805ab29e0199047271
7
+ data.tar.gz: e233e6b6f840da4b8b3eb7186a2b279112c39bfc0352a1fb83075a46a90c74acea25abbab2d8d8e0b9ec7a677b4e5335f4326156d8196338806ca6668c2a93f8
@@ -0,0 +1,87 @@
1
+ *.rbc
2
+ capybara-*.html
3
+ /spec/rails_app/db/*.sqlite3
4
+ /spec/rails_app/db/*.sqlite3-journal
5
+ /spec/rails_app/db/*.sqlite3-[0-9]*
6
+ /spec/rails_app/public/system
7
+ /coverage/
8
+ /tmp/
9
+ /spec/rails_app/spec/tmp
10
+ *.orig
11
+ rerun.txt
12
+ pickle-email-*.html
13
+ /Gemfile.lock
14
+ /gemfiles/Gemfile*.lock
15
+
16
+ # Ignore all logfiles and tempfiles.
17
+ /spec/rails_app/log/*
18
+ /spec/rails_app/tmp/*
19
+ !/spec/rails_app/log/.keep
20
+ !/spec/rails_app/tmp/.keep
21
+
22
+ # TODO Comment out this rule if you are OK with secrets being uploaded to the repo
23
+ /spec/rails_app/config/initializers/secret_token.rb
24
+ /spec/rails_app/config/master.key
25
+
26
+ # Only include if you have production secrets in this file, which is no longer a Rails default
27
+ # config/secrets.yml
28
+
29
+ # dotenv
30
+ # TODO Comment out this rule if environment variables can be committed
31
+ .env
32
+
33
+ ## Environment normalization:
34
+ /.bundle
35
+ /vendor/bundle
36
+ /gemfiles/vendor/bundle
37
+ /spec/rails_app/vendor/bundle
38
+
39
+ # these should all be checked in to normalize the environment:
40
+ # Gemfile.lock, .ruby-version, .ruby-gemset
41
+
42
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
43
+ .rvmrc
44
+
45
+ # if using bower-rails ignore default bower_components path bower.json files
46
+ /vendor/assets/bower_components
47
+ *.bowerrc
48
+ bower.json
49
+
50
+ # Ignore pow environment settings
51
+ .powenv
52
+
53
+ # Ignore Byebug command history file.
54
+ .byebug_history
55
+
56
+ # Ignore node_modules
57
+ /node_modules/
58
+ /spec/rails_app/node_modules/
59
+
60
+ # Ignore precompiled javascript packs
61
+ /spec/rails_app/public/packs
62
+ /spec/rails_app/public/packs-test
63
+ /spec/rails_app/public/assets
64
+
65
+ # Ignore yarn files
66
+ /spec/rails_app/yarn.lock
67
+ /spec/rails_app/yarn-error.log
68
+ yarn-debug.log*
69
+ .yarn-integrity
70
+ /package-lock.json
71
+
72
+ # Ignore uploaded files in development
73
+ /spec/rails_app/storage/*
74
+ !/spec/rails_app//storage/.keep
75
+
76
+ ## Documentation cache and generated files:
77
+ /.yardoc/
78
+ /_yardoc/
79
+ /doc/
80
+ /rdoc/
81
+
82
+ # Security files for testing
83
+ /spec/rails_app/config/initializers/aws.rb
84
+
85
+ # Compiled Amazon Chime SDK as single JavaScript file
86
+ /spec/rails_app/app/assets/javascripts/amazon-chime-sdk.min.js
87
+ /spec/rails_app/app/assets/javascripts/amazon-chime-sdk.min.js.map
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require spec_helper
2
+ --format documentation
@@ -0,0 +1,47 @@
1
+ language: ruby
2
+
3
+ branches:
4
+ except:
5
+ - images
6
+
7
+ rvm:
8
+ # - 2.7.2
9
+ - 2.6.6
10
+
11
+ gemfile:
12
+ - gemfiles/Gemfile.rails-5.0
13
+ - gemfiles/Gemfile.rails-5.1
14
+ - gemfiles/Gemfile.rails-5.2
15
+ - gemfiles/Gemfile.rails-6.0
16
+
17
+ matrix:
18
+ include:
19
+ - rvm: ruby-head
20
+ gemfile: Gemfile
21
+ allow_failures:
22
+ - rvm: ruby-head
23
+ fast_finish: true
24
+
25
+ sudo: false
26
+
27
+ cache: bundler
28
+
29
+ before_install:
30
+ - gem install bundler
31
+ - nvm install node
32
+
33
+ install:
34
+ - bundle install
35
+
36
+ before_script:
37
+ - cd spec/rails_app
38
+ - yarn --check-files
39
+ - bundle exec rails webpacker:compile
40
+ - bundle exec rails g chime_sdk:js
41
+ - cd -
42
+
43
+ script:
44
+ - bundle exec rspec
45
+
46
+ notifications:
47
+ email: true
@@ -0,0 +1,6 @@
1
+ --protected
2
+ --no-private
3
+ --markup markdown
4
+ --exclude /templates/
5
+ -
6
+ CHANGELOG.md
@@ -0,0 +1,3 @@
1
+ ## 1.0.0 / 2020-10-17
2
+
3
+ * First release
data/Gemfile ADDED
@@ -0,0 +1,25 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ # Bundle Rails
6
+ gem 'rails', '~> 6.0.0'
7
+
8
+ gem 'sqlite3'
9
+ gem 'puma'
10
+ gem 'sass-rails'
11
+ gem 'webpacker'
12
+ gem 'turbolinks'
13
+ gem 'jbuilder'
14
+
15
+ group :development do
16
+ gem 'web-console'
17
+ gem 'listen'
18
+ gem 'spring'
19
+ gem 'spring-watcher-listen'
20
+ end
21
+
22
+ group :test do
23
+ # gem 'coveralls', require: false
24
+ gem 'coveralls_reborn', require: false
25
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Shota Yamazaki
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,1109 @@
1
+ # amazon-chime-sdk-rails
2
+
3
+ [![Build Status](https://travis-ci.org/simukappu/amazon-chime-sdk-rails.svg?branch=master)](https://travis-ci.org/simukappu/amazon-chime-sdk-rails)
4
+ [![Coverage Status](https://coveralls.io/repos/github/simukappu/amazon-chime-sdk-rails/badge.svg?branch=master)](https://coveralls.io/github/simukappu/amazon-chime-sdk-rails?branch=master)
5
+ [![Dependency](https://img.shields.io/depfu/simukappu/amazon-chime-sdk-rails.svg)](https://depfu.com/repos/simukappu/amazon-chime-sdk-rails)
6
+ [![Inline Docs](http://inch-ci.org/github/simukappu/amazon-chime-sdk-rails.svg?branch=master)](http://inch-ci.org/github/simukappu/amazon-chime-sdk-rails)
7
+ [![Gem Version](https://badge.fury.io/rb/amazon-chime-sdk-rails.svg)](https://rubygems.org/gems/amazon-chime-sdk-rails)
8
+ [![Gem Downloads](https://img.shields.io/gem/dt/amazon-chime-sdk-rails.svg)](https://rubygems.org/gems/amazon-chime-sdk-rails)
9
+ [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
10
+
11
+ *amazon-chime-sdk-rails* brings server-side implementation of [Amazon Chime SDK](https://aws.amazon.com/chime/chime-sdk) to your [Ruby on Rails](https://rubyonrails.org) application. [Amazon Chime SDK](https://aws.amazon.com/chime/chime-sdk) provides client-side implementation to build real-time communications for your application, and *amazon-chime-sdk-rails* enables you to easily add server-side implementation to your Rails application.
12
+
13
+ *amazon-chime-sdk-rails* supports both of [Rails API Application](https://guides.rubyonrails.org/api_app.html) and [Rails Application with Action View](https://guides.rubyonrails.org/action_view_overview.html). The gem provides following functions:
14
+ * Meeting Coordinator - Wrapper client module of [AWS SDK for Ruby](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Chime/Client.html), which simulates [AWS SDK for JavaScript](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Chime.html) to communicate with Amazon Chime SDK client implementation by JSON format.
15
+ * Controller Templates - Mixin module implementation for meetings and attendees controllers.
16
+ * Rails Generators
17
+ * Controller Generator - Generator to create customizable meetings and attendees controllers in your Rails application.
18
+ * View Generator - Generator to create customizable meetings views for your Rails application with Action View.
19
+ * Single Javascript Generator - Generator to [bundle Amazon Chime SDK into single .js file](https://github.com/aws/amazon-chime-sdk-js/tree/master/demos/singlejs) and put it into [Asset Pipeline](https://guides.rubyonrails.org/asset_pipeline.html) for your Rails application with Action View.
20
+
21
+
22
+ ## Getting Started
23
+
24
+ ### Installation
25
+
26
+ Add *amazon-chime-sdk-rails* to your app’s Gemfile:
27
+
28
+ ```ruby:Gemfile
29
+ gem 'amazon-chime-sdk-rails'
30
+ ```
31
+
32
+ Then, in your project directory:
33
+
34
+ ```bash
35
+ $ bundle install
36
+ $ rails g chime_sdk:install
37
+ ```
38
+
39
+ The install generator will generate an initializer which describes all configuration options of *amazon-chime-sdk-rails*.
40
+
41
+ ### Set up AWS credentials
42
+
43
+ You need to set up AWS credentials or IAM role for *amazon-chime-sdk-rails* in your Rails app. See [Configuring the AWS SDK for Ruby](https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/setup-config.html) for more details.
44
+
45
+ *amazon-chime-sdk-rails* requires following IAM permissions:
46
+
47
+ * [chime:TagResource](https://docs.aws.amazon.com/chime/latest/APIReference/API_TagResource.html)
48
+ * [chime:UntagResource](https://docs.aws.amazon.com/chime/latest/APIReference/API_UntagResource.html)
49
+ * [chime:CreateMeeting](https://docs.aws.amazon.com/chime/latest/APIReference/API_CreateMeeting.html)
50
+ * [chime:GetMeeting](https://docs.aws.amazon.com/chime/latest/APIReference/API_GetMeeting.html)
51
+ * [chime:ListMeetings](https://docs.aws.amazon.com/chime/latest/APIReference/API_ListMeetings.html) (if necessary)
52
+ * [chime:DeleteMeeting](https://docs.aws.amazon.com/chime/latest/APIReference/API_DeleteMeeting.html) (if necessary)
53
+ * [chime:CreateAttendee](https://docs.aws.amazon.com/chime/latest/APIReference/API_CreateAttendee.html)
54
+ * [chime:GetAttendee](https://docs.aws.amazon.com/chime/latest/APIReference/API_GetAttendee.html)
55
+ * [chime:ListAttendees](https://docs.aws.amazon.com/chime/latest/APIReference/API_ListAttendees.html) (if necessary)
56
+ * [chime:DeleteAttendee](https://docs.aws.amazon.com/chime/latest/APIReference/API_DeleteAttendee.html) (if necessary)
57
+
58
+ See [Actions defined by Amazon Chime](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazonchime.html#amazonchime-actions-as-permissions) for more details.
59
+
60
+ ### A: Develop your Rails API Application
61
+
62
+ Let's start to building simple Rails API application providing real-time communications in a private room.
63
+ For example, create Rails API application using [Devise Token Auth](https://github.com/lynndylanhurley/devise_token_auth) for user authentication.
64
+
65
+ #### Prepare Rails API application
66
+
67
+ At first, create new Rails application:
68
+
69
+ ```bash
70
+ $ rails new chime_api_app --api
71
+ $ cd chime_api_app
72
+ ```
73
+
74
+ Add gems to your Gemfile:
75
+
76
+ ```ruby:Gemfile
77
+ # Gemfile
78
+
79
+ gem 'devise_token_auth'
80
+ gem 'amazon-chime-sdk-rails'
81
+ ```
82
+
83
+ Then, install *devise_token_auth*:
84
+
85
+ ```bash
86
+ $ bundle install
87
+ $ rails g devise:install
88
+ $ rails g devise_token_auth:install User auth
89
+ ```
90
+
91
+ Update your `application_controller.rb` like this:
92
+
93
+ ```ruby:app/controllers/application_controller.rb
94
+ # app/controllers/application_controller.rb
95
+
96
+ class ApplicationController < ActionController::API
97
+ include ActionController::Helpers
98
+ include DeviseTokenAuth::Concerns::SetUserByToken
99
+ before_action :configure_permitted_parameters, if: :devise_controller?
100
+
101
+ protected
102
+ def configure_permitted_parameters
103
+ devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
104
+ end
105
+ end
106
+ ```
107
+
108
+ Update your `user.rb` to remove unnecessary options like this:
109
+
110
+ ```ruby:app/models/user.rb
111
+ # app/models/user.rb
112
+
113
+ class User < ActiveRecord::Base
114
+ devise :database_authenticatable, :registerable
115
+ include DeviseTokenAuth::Concerns::User
116
+ end
117
+ ```
118
+
119
+ Update *devise_token_auth* configuration in `devise_token_auth.rb` to keep authorization headers:
120
+
121
+ ```ruby:config/initializers/devise_token_auth.rb
122
+ # config/initializers/devise_token_auth.rb
123
+
124
+ DeviseTokenAuth.setup do |config|
125
+ # Uncomment and update
126
+ config.change_headers_on_each_request = false
127
+ end
128
+ ```
129
+
130
+ #### Create private room functions
131
+
132
+ Create models and controllers by generator:
133
+
134
+ ```bash
135
+ $ rails g model room name:string
136
+ $ rails g scaffold_controller api/rooms name:string --model-name=room
137
+ $ rails g model entry room:references user:references
138
+ $ rails g scaffold_controller api/entries room:references user:references --model-name=entry
139
+ $ rake db:migrate
140
+ ```
141
+
142
+ Update your `room.rb` like this:
143
+
144
+ ```ruby:app/models/room.rb
145
+ # app/models/room.rb
146
+
147
+ class Room < ApplicationRecord
148
+ has_many :entries, dependent: :destroy
149
+ has_many :members, through: :entries, source: :user
150
+
151
+ def member?(user)
152
+ members.include?(user)
153
+ end
154
+
155
+ def as_json(options = {})
156
+ super options.merge(:methods => [:members])
157
+ end
158
+ end
159
+ ```
160
+
161
+ Add uniqueness validation to your `entry.rb` like this:
162
+
163
+ ```ruby:app/models/entry.rb
164
+ # app/models/entry.rb
165
+
166
+ class Entry < ApplicationRecord
167
+ belongs_to :room
168
+ belongs_to :user
169
+ # Add uniqueness validation
170
+ validates :user, uniqueness: { scope: :room }
171
+ end
172
+ ```
173
+
174
+ Remove location header from your `rooms_controller.rb` and `entries_controller.rb` like this:
175
+
176
+ ```ruby:app/controllers/api/rooms_controller.rb
177
+ # app/controllers/api/rooms_controller.rb
178
+
179
+ # POST /rooms
180
+ def create
181
+ @room = Room.new(room_params)
182
+
183
+ if @room.save
184
+ render json: @room, status: :created # Remove location header
185
+ else
186
+ render json: @room.errors, status: :unprocessable_entity
187
+ end
188
+ end
189
+ ```
190
+
191
+ ```ruby:app/controllers/api/entries_controller.rb
192
+ # app/controllers/api/entries_controller.rb
193
+
194
+ # POST /entries
195
+ def create
196
+ @entry = Entry.new(entry_params)
197
+
198
+ if @entry.save
199
+ render json: @entry, status: :created # Remove location header
200
+ else
201
+ render json: @entry.errors, status: :unprocessable_entity
202
+ end
203
+ end
204
+ ```
205
+
206
+ #### Develop meeting functions with amazon-chime-sdk-rails
207
+
208
+ Install *amazon-chime-sdk-rails* and generates your controllers:
209
+
210
+ ```bash
211
+ $ rails g chime_sdk:install
212
+ $ rails g chime_sdk:controllers -r room -n api
213
+ ```
214
+
215
+ Add and uncomment several functions in generated `meetings_controller.rb` and `meeting_attendees_controller.rb` for your app configurations:
216
+
217
+ ```ruby:app/controllers/api/meetings_controller.rb
218
+ # app/controllers/api/meetings_controller.rb
219
+
220
+ class Api::MeetingsController < ApplicationController
221
+ before_action :authenticate_api_user!
222
+ include DeviseTokenAuth::Concerns::SetUserByToken
223
+ before_action :set_room
224
+ before_action :check_membership
225
+
226
+ include ChimeSdk::Controller::Meetings::Mixin
227
+
228
+ private
229
+ # Add
230
+ def set_room
231
+ @room = Room.find(params[:room_id])
232
+ end
233
+
234
+ # Add
235
+ def check_membership
236
+ unless @room.member?(current_api_user)
237
+ message = 'Unauthorized: you are not a member of this private room.'
238
+ render json: { room: @room, notice: message }, status: :forbidden
239
+ end
240
+ end
241
+
242
+ # Uncomment
243
+ def meeting_request_id
244
+ "PrivateRoom-#{@room.id}"
245
+ end
246
+
247
+ # Uncomment and update
248
+ def attendee_request_id
249
+ "User-#{current_api_user.id}"
250
+ end
251
+
252
+ # Uncomment
253
+ def application_meeting_metadata(meeting)
254
+ {
255
+ "MeetingType": "PrivateRoom",
256
+ "Room": @room
257
+ }
258
+ end
259
+
260
+ # Uncomment
261
+ def application_attendee_metadata(attendee)
262
+ user_id = attendee[:Attendee][:ExternalUserId].split('-')[3]
263
+ {
264
+ "AttendeeType": "User",
265
+ "User": User.find_by_id(user_id)
266
+ }
267
+ end
268
+ end
269
+ ```
270
+
271
+ ```ruby:app/controllers/api/meeting_attendees_controller.rb
272
+ # app/controllers/api/meeting_attendees_controller.rb
273
+
274
+ class Api::MeetingAttendeesController < ApplicationController
275
+ before_action :authenticate_api_user!
276
+ include DeviseTokenAuth::Concerns::SetUserByToken
277
+ before_action :set_room
278
+ before_action :check_membership
279
+
280
+ include ChimeSdk::Controller::Attendees::Mixin
281
+
282
+ private
283
+ # Add
284
+ def set_room
285
+ @room = Room.find(params[:room_id])
286
+ end
287
+
288
+ # Add
289
+ def check_membership
290
+ unless @room.member?(current_api_user)
291
+ message = 'Unauthorized: you are not a member of this private room.'
292
+ render json: { room: @room, notice: message }, status: :forbidden
293
+ end
294
+ end
295
+
296
+ # Uncomment and update
297
+ def attendee_request_id
298
+ "User-#{current_api_user.id}"
299
+ end
300
+
301
+ # Uncomment
302
+ def application_attendee_metadata(attendee)
303
+ user_id = attendee[:Attendee][:ExternalUserId].split('-')[3]
304
+ {
305
+ "AttendeeType": "User",
306
+ "User": User.find_by_id(user_id)
307
+ }
308
+ end
309
+ end
310
+ ```
311
+
312
+ Then, update your `routes.rb` like this:
313
+
314
+ ```ruby:config/routes.rb
315
+ # config/routes.rb
316
+
317
+ Rails.application.routes.draw do
318
+ namespace :api do
319
+ scope :"v1" do
320
+ mount_devise_token_auth_for 'User', at: 'auth'
321
+ resources :rooms do
322
+ resources :entries, only: [:create, :destroy]
323
+ resources :meetings, defaults: { format: :json }, only: [:index, :show, :create, :destroy] do
324
+ resources :meeting_attendees, as: :attendees, path: :attendees, only: [:index, :show, :create, :destroy]
325
+ end
326
+ end
327
+ end
328
+ end
329
+ end
330
+ ```
331
+
332
+ Note that you need to set up AWS credentials or IAM role for *amazon-chime-sdk-rails*. See [Set up AWS credentials](#set-up-aws-credentials) for more details.
333
+
334
+ Finally, start rails server:
335
+
336
+ ```bash
337
+ $ rails server
338
+ ```
339
+
340
+ Now ready to take off!
341
+
342
+ #### Get meeting configurations through Rails API
343
+
344
+ Created Rails API works like this:
345
+
346
+ ```bash
347
+ # Sign up users
348
+
349
+ $ curl localhost:3000/api/v1/auth -X POST -H "content-type:application/json" -d '{"email":"ichiro@example.com", "password":"password", "password_confirmation":"password", "name":"ichiro"}'
350
+
351
+ {"status":"success","data":{"id":1,"provider":"email","uid":"ichiro@example.com","allow_password_change":false,"name":"ichiro","nickname":null,"image":null,"email":"ichiro@example.com","created_at":"2020-10-16T11:14:48.731Z","updated_at":"2020-10-16T11:14:48.827Z"}}
352
+
353
+ $ curl localhost:3000/api/v1/auth -X POST -H "content-type:application/json" -d '{"email":"stephen@example.com", "password":"password", "password_confirmation":"password", "name":"stephen"}'
354
+
355
+ {"status":"success","data":{"id":2,"provider":"email","uid":"stephen@example.com","allow_password_change":false,"name":"stephen","nickname":null,"image":null,"email":"stephen@example.com","created_at":"2020-10-16T11:15:33.226Z","updated_at":"2020-10-16T11:15:33.314Z"}}
356
+
357
+ # Create private room
358
+
359
+ $ curl localhost:3000/api/v1/rooms -X POST -H "content-type:application/json" -d '{"room":{"name":"PrivateRoom-1"}}'
360
+
361
+ {"id":1,"name":"PrivateRoom-1","created_at":"2020-10-16T11:15:56.223Z","updated_at":"2020-10-16T11:15:56.223Z","members":[]}
362
+
363
+ # You cannot create meeting yet because the user is not signed in
364
+
365
+ $ curl localhost:3000/api/v1/rooms/3/meetings -X POST -H "content-type:application/json"
366
+
367
+ {"errors":["You need to sign in or sign up before continuing."]}
368
+
369
+ # Sign in as ichiro
370
+
371
+ $ curl localhost:3000/api/v1/auth/sign_in -X POST -H "content-type:application/json" -D auth_headers.txt -d '{"email":"ichiro@example.com", "password":"password"}'
372
+
373
+ {"data":{"id":1,"email":"ichiro@example.com","provider":"email","uid":"ichiro@example.com","allow_password_change":false,"name":"ichiro","nickname":null,"image":null}}
374
+
375
+ $ _ACCESS_TOKEN=$(cat auth_headers.txt | grep access-token | rev | cut -c 2- | rev)
376
+ $ _CLIENT=$(cat auth_headers.txt | grep client | rev | cut -c 2- | rev)
377
+ $ _UID=$(cat auth_headers.txt | grep uid | rev | cut -c 2- | rev)
378
+
379
+ # You cannot create meeting yet because the user is not a member of the private room
380
+
381
+ $ curl localhost:3000/api/v1/rooms/1/meetings -X POST -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}"
382
+
383
+ {"room":{"id":1,"name":"PrivateRoom-1","created_at":"2020-10-16T11:15:56.223Z","updated_at":"2020-10-16T11:15:56.223Z","members":[]},"notice":"Unauthorized: you are not a member of this private room."}
384
+
385
+ # Add users to the private room
386
+
387
+ $ curl localhost:3000/api/v1/rooms/1/entries -X POST -H "content-type:application/json" -d '{"entry":{"room_id":1,"user_id":1}}'
388
+
389
+ {"id":1,"room_id":1,"user_id":1,"created_at":"2020-10-16T11:18:22.839Z","updated_at":"2020-10-16T11:18:22.839Z"}
390
+
391
+ $ curl localhost:3000/api/v1/rooms/1/entries -X POST -H "content-type:application/json" -d '{"entry":{"room_id":1,"user_id":2}}'
392
+
393
+ {"id":2,"room_id":1,"user_id":2,"created_at":"2020-10-16T11:18:41.116Z","updated_at":"2020-10-16T11:18:41.116Z"}
394
+
395
+ # Now you can create meeting as a member of the private room
396
+
397
+ $ curl localhost:3000/api/v1/rooms/1/meetings -X POST -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq .
398
+
399
+ {
400
+ "Meeting": {
401
+ "MeetingId": "2f550432-579c-4058-bbb9-be8a01d3beea",
402
+ "ExternalMeetingId": "ChimeSdkRailsApp-development-PrivateRoom-1",
403
+ "MediaPlacement": {
404
+ "AudioHostUrl": "d3175d855e633b72aedb275a0dd6504f.k.m2.ue1.app.chime.aws:3478",
405
+ "AudioFallbackUrl": "wss://haxrp.m2.ue1.app.chime.aws:443/calls/2f550432-579c-4058-bbb9-be8a01d3beea",
406
+ "ScreenDataUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/v2/screen/2f550432-579c-4058-bbb9-be8a01d3beea",
407
+ "ScreenSharingUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/v2/screen/2f550432-579c-4058-bbb9-be8a01d3beea",
408
+ "ScreenViewingUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/ws/connect?passcode=null&viewer_uuid=null&X-BitHub-Call-Id=2f550432-579c-4058-bbb9-be8a01d3beea",
409
+ "SignalingUrl": "wss://signal.m2.ue1.app.chime.aws/control/2f550432-579c-4058-bbb9-be8a01d3beea",
410
+ "TurnControlUrl": "https://ccp.cp.ue1.app.chime.aws/v2/turn_sessions"
411
+ },
412
+ "MediaRegion": "us-east-1",
413
+ "ApplicationMetadata": {
414
+ "MeetingType": "PrivateRoom",
415
+ "Room": {
416
+ "id": 1,
417
+ "name": "PrivateRoom-1",
418
+ "created_at": "2020-10-16T11:15:56.223Z",
419
+ "updated_at": "2020-10-16T11:15:56.223Z",
420
+ "members": [
421
+ {
422
+ "id": 1,
423
+ "provider": "email",
424
+ "uid": "ichiro@example.com",
425
+ "allow_password_change": false,
426
+ "name": "ichiro",
427
+ "nickname": null,
428
+ "image": null,
429
+ "email": "ichiro@example.com",
430
+ "created_at": "2020-10-16T11:14:48.731Z",
431
+ "updated_at": "2020-10-16T11:16:56.927Z"
432
+ },
433
+ {
434
+ "id": 2,
435
+ "provider": "email",
436
+ "uid": "stephen@example.com",
437
+ "allow_password_change": false,
438
+ "name": "stephen",
439
+ "nickname": null,
440
+ "image": null,
441
+ "email": "stephen@example.com",
442
+ "created_at": "2020-10-16T11:15:33.226Z",
443
+ "updated_at": "2020-10-16T11:15:33.314Z"
444
+ }
445
+ ]
446
+ }
447
+ }
448
+ },
449
+ "Attendee": {
450
+ "ExternalUserId": "ChimeSdkRailsApp-development-User-1",
451
+ "AttendeeId": "b581c46d-661f-92bb-d80e-f4b157d95fe9",
452
+ "JoinToken": "YjU4MWM0NmQtNjYxZi05MmJiLWQ4MGUtZjRiMTU3ZDk1ZmU5OjgyZmM2NTMxLTIwMjctNGMxMS04OTE0LTQwZjkxNmJmNjM3MQ",
453
+ "ApplicationMetadata": {
454
+ "AttendeeType": "User",
455
+ "User": {
456
+ "id": 1,
457
+ "provider": "email",
458
+ "uid": "ichiro@example.com",
459
+ "allow_password_change": false,
460
+ "name": "ichiro",
461
+ "nickname": null,
462
+ "image": null,
463
+ "email": "ichiro@example.com",
464
+ "created_at": "2020-10-16T11:14:48.731Z",
465
+ "updated_at": "2020-10-16T11:16:56.927Z"
466
+ }
467
+ }
468
+ }
469
+ }
470
+
471
+ # Get attendee data from created meeting ID
472
+
473
+ $ MEETING_ID=$(curl localhost:3000/api/v1/rooms/1/meetings -X POST -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq -r .Meeting.MeetingId)
474
+
475
+ $ curl localhost:3000/api/v1/rooms/1/meetings/${MEETING_ID}/attendees -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq .
476
+
477
+ {
478
+ "attendees": [
479
+ {
480
+ "Attendee": {
481
+ "ExternalUserId": "ChimeSdkRailsApp-development-User-1",
482
+ "AttendeeId": "b581c46d-661f-92bb-d80e-f4b157d95fe9",
483
+ "JoinToken": "YjU4MWM0NmQtNjYxZi05MmJiLWQ4MGUtZjRiMTU3ZDk1ZmU5OjgyZmM2NTMxLTIwMjctNGMxMS04OTE0LTQwZjkxNmJmNjM3MQ",
484
+ "ApplicationMetadata": {
485
+ "AttendeeType": "User",
486
+ "User": {
487
+ "id": 1,
488
+ "provider": "email",
489
+ "uid": "ichiro@example.com",
490
+ "allow_password_change": false,
491
+ "name": "ichiro",
492
+ "nickname": null,
493
+ "image": null,
494
+ "email": "ichiro@example.com",
495
+ "created_at": "2020-10-16T11:14:48.731Z",
496
+ "updated_at": "2020-10-16T11:16:56.927Z"
497
+ }
498
+ }
499
+ }
500
+ }
501
+ ]
502
+ }
503
+
504
+ $ ATTENDEE_ID=$(curl localhost:3000/api/v1/rooms/1/meetings/${MEETING_ID}/attendees -X GET -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq -r .attendees[0].Attendee.AttendeeId)
505
+
506
+ $ curl localhost:3000/api/v1/rooms/1/meetings/${MEETING_ID}/attendees/${ATTENDEE_ID} -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq .
507
+
508
+ {
509
+ "Attendee": {
510
+ "ExternalUserId": "ChimeSdkRailsApp-development-User-1",
511
+ "AttendeeId": "b581c46d-661f-92bb-d80e-f4b157d95fe9",
512
+ "JoinToken": "YjU4MWM0NmQtNjYxZi05MmJiLWQ4MGUtZjRiMTU3ZDk1ZmU5OjgyZmM2NTMxLTIwMjctNGMxMS04OTE0LTQwZjkxNmJmNjM3MQ",
513
+ "ApplicationMetadata": {
514
+ "AttendeeType": "User",
515
+ "User": {
516
+ "id": 1,
517
+ "provider": "email",
518
+ "uid": "ichiro@example.com",
519
+ "allow_password_change": false,
520
+ "name": "ichiro",
521
+ "nickname": null,
522
+ "image": null,
523
+ "email": "ichiro@example.com",
524
+ "created_at": "2020-10-16T11:14:48.731Z",
525
+ "updated_at": "2020-10-16T11:16:56.927Z"
526
+ }
527
+ }
528
+ }
529
+ }
530
+
531
+ # Sign in as stephen
532
+
533
+ $ curl localhost:3000/api/v1/auth/sign_in -X POST -H "content-type:application/json" -D auth_headers.txt -d '{"email":"stephen@example.com", "password":"password"}'
534
+
535
+ {"data":{"id":2,"email":"stephen@example.com","provider":"email","uid":"stephen@example.com","allow_password_change":false,"name":"stephen","nickname":null,"image":null}}
536
+
537
+ $ _ACCESS_TOKEN=$(cat auth_headers.txt | grep access-token | rev | cut -c 2- | rev)
538
+ $ _CLIENT=$(cat auth_headers.txt | grep client | rev | cut -c 2- | rev)
539
+ $ _UID=$(cat auth_headers.txt | grep uid | rev | cut -c 2- | rev)
540
+
541
+ # Confirm attending same meeting in the private room as different attendee
542
+
543
+ $ curl localhost:3000/api/v1/rooms/1/meetings -X POST -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq .
544
+
545
+ {
546
+ "Meeting": {
547
+ "MeetingId": "2f550432-579c-4058-bbb9-be8a01d3beea",
548
+ "ExternalMeetingId": "ChimeSdkRailsApp-development-PrivateRoom-1",
549
+ "MediaPlacement": {
550
+ "AudioHostUrl": "d3175d855e633b72aedb275a0dd6504f.k.m2.ue1.app.chime.aws:3478",
551
+ "AudioFallbackUrl": "wss://haxrp.m2.ue1.app.chime.aws:443/calls/2f550432-579c-4058-bbb9-be8a01d3beea",
552
+ "ScreenDataUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/v2/screen/2f550432-579c-4058-bbb9-be8a01d3beea",
553
+ "ScreenSharingUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/v2/screen/2f550432-579c-4058-bbb9-be8a01d3beea",
554
+ "ScreenViewingUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/ws/connect?passcode=null&viewer_uuid=null&X-BitHub-Call-Id=2f550432-579c-4058-bbb9-be8a01d3beea",
555
+ "SignalingUrl": "wss://signal.m2.ue1.app.chime.aws/control/2f550432-579c-4058-bbb9-be8a01d3beea",
556
+ "TurnControlUrl": "https://ccp.cp.ue1.app.chime.aws/v2/turn_sessions"
557
+ },
558
+ "MediaRegion": "us-east-1",
559
+ "ApplicationMetadata": {
560
+ "MeetingType": "PrivateRoom",
561
+ "Room": {
562
+ "id": 1,
563
+ "name": "PrivateRoom-1",
564
+ "created_at": "2020-10-16T11:15:56.223Z",
565
+ "updated_at": "2020-10-16T11:15:56.223Z",
566
+ "members": [
567
+ {
568
+ "id": 1,
569
+ "provider": "email",
570
+ "uid": "ichiro@example.com",
571
+ "allow_password_change": false,
572
+ "name": "ichiro",
573
+ "nickname": null,
574
+ "image": null,
575
+ "email": "ichiro@example.com",
576
+ "created_at": "2020-10-16T11:14:48.731Z",
577
+ "updated_at": "2020-10-16T11:16:56.927Z"
578
+ },
579
+ {
580
+ "id": 2,
581
+ "provider": "email",
582
+ "uid": "stephen@example.com",
583
+ "allow_password_change": false,
584
+ "name": "stephen",
585
+ "nickname": null,
586
+ "image": null,
587
+ "email": "stephen@example.com",
588
+ "created_at": "2020-10-16T11:15:33.226Z",
589
+ "updated_at": "2020-10-16T11:21:46.011Z"
590
+ }
591
+ ]
592
+ }
593
+ }
594
+ },
595
+ "Attendee": {
596
+ "ExternalUserId": "ChimeSdkRailsApp-development-User-2",
597
+ "AttendeeId": "986886fc-dcbc-1d44-4708-917ab23117de",
598
+ "JoinToken": "OTg2ODg2ZmMtZGNiYy0xZDQ0LTQ3MDgtOTE3YWIyMzExN2RlOjNjNjAzM2E5LWFlNGUtNGVmZi1iNjZjLWMwY2M1YjU3OTE4OA",
599
+ "ApplicationMetadata": {
600
+ "AttendeeType": "User",
601
+ "User": {
602
+ "id": 2,
603
+ "provider": "email",
604
+ "uid": "stephen@example.com",
605
+ "allow_password_change": false,
606
+ "name": "stephen",
607
+ "nickname": null,
608
+ "image": null,
609
+ "email": "stephen@example.com",
610
+ "created_at": "2020-10-16T11:15:33.226Z",
611
+ "updated_at": "2020-10-16T11:21:46.011Z"
612
+ }
613
+ }
614
+ }
615
+ }
616
+
617
+ $ MEETING_ID_2=$(curl localhost:3000/api/v1/rooms/1/meetings -X POST -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq -r .Meeting.MeetingId)
618
+
619
+ $ echo ${MEETING_ID}
620
+
621
+ 2f550432-579c-4058-bbb9-be8a01d3beea
622
+
623
+ $ echo ${MEETING_ID_2}
624
+
625
+ 2f550432-579c-4058-bbb9-be8a01d3beea
626
+ ```
627
+
628
+ Now you can start online meeting using [Amazon Chime SDK](https://aws.amazon.com/chime/chime-sdk) client-side implementation with this responded *Meeting* and *Attendee* data.
629
+
630
+ You can see [sample single page application](/spec/rails_app/app/javascript/) using [Vue.js](https://vuejs.org) and [Amazon Chime SDK for JavaScript](https://github.com/aws/amazon-chime-sdk-js) as a part of [example Rails application](#examples).
631
+
632
+
633
+ ### B: Develop your Rails Application with Action View
634
+
635
+ Let's start to building simple Rails application with Action View providing real-time communications in a private room.
636
+ For example, create Rails application using [Devise](https://github.com/heartcombo/devise) for user authentication.
637
+
638
+ #### Prepare Rails application
639
+
640
+ At first, create new Rails application:
641
+
642
+ ```bash
643
+ $ rails new chime_view_app
644
+ $ cd chime_view_app
645
+ ```
646
+
647
+ Add gems to your Gemfile:
648
+
649
+ ```ruby:Gemfile
650
+ # Gemfile
651
+
652
+ gem 'devise'
653
+ gem 'amazon-chime-sdk-rails'
654
+ ```
655
+
656
+ Then, install *devise*:
657
+
658
+ ```bash
659
+ $ bundle install
660
+ $ rails g devise:install
661
+ $ rails g devise User
662
+ $ rails g migration add_name_to_users name:string
663
+ $ rails g devise:views User
664
+ ```
665
+
666
+ Update your `application_controller.rb` like this:
667
+
668
+ ```ruby:app/controllers/application_controller.rb
669
+ # app/controllers/application_controller.rb
670
+
671
+ class ApplicationController < ActionController::Base
672
+ before_action :configure_permitted_parameters, if: :devise_controller?
673
+
674
+ protected
675
+ def configure_permitted_parameters
676
+ devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
677
+ end
678
+ end
679
+ ```
680
+
681
+ Add user name form to your `app/views/users/registrations/new.html.erb` view template like this:
682
+
683
+ ```erb:app/views/users/registrations/new.html.erb
684
+ # app/views/users/registrations/new.html.erb
685
+
686
+ <div class="field">
687
+ <%= f.label :name %><br />
688
+ <%= f.text_field :name, autocomplete: "name" %>
689
+ </div>
690
+
691
+ <div class="field">
692
+ <%= f.label :email %><br />
693
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
694
+ </div>
695
+ ```
696
+
697
+ Update *devise* configuration in `devise.rb` to use scoped views:
698
+
699
+ ```ruby:config/initializers/devise.rb
700
+ # config/initializers/devise.rb
701
+
702
+ Devise.setup do |config|
703
+ # Uncomment and update
704
+ config.scoped_views = true
705
+ end
706
+ ```
707
+
708
+ Add login header to your application. Create new `app/views/layouts/_header.html.erb` and update your `app/views/layouts/application.html.erb` like this:
709
+
710
+ ```erb:app/views/layouts/_header.html.erb
711
+ # app/views/layouts/_header.html.erb
712
+
713
+ <header>
714
+ <div>
715
+ <div>
716
+ <strong>Rails Application for Amazon Chime SDK Meeting (Rails App with Action View)</strong>
717
+ </div>
718
+ <div>
719
+ <% if user_signed_in? %>
720
+ <%= current_user.name %>
721
+ <%= link_to 'Logout', destroy_user_session_path, method: :delete %>
722
+ <% else %>
723
+ <%= link_to "Sign up", new_user_registration_path %>
724
+ <%= link_to 'Login', new_user_session_path %>
725
+ <% end %>
726
+ </div>
727
+ </div>
728
+ </header>
729
+ ```
730
+
731
+ ```erb:app/views/layouts/application.html.erb
732
+ # app/views/layouts/application.html.erb
733
+
734
+ <!DOCTYPE html>
735
+ <html>
736
+ <head>
737
+ <title>Rails Application for Amazon Chime SDK Meeting</title>
738
+ <%= csrf_meta_tags %>
739
+ <%= csp_meta_tag %>
740
+
741
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
742
+ <%= yield(:javascript_pack_tag) %>
743
+ <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
744
+ </head>
745
+
746
+ <body>
747
+ <div id="app">
748
+ <%= render 'layouts/header' %>
749
+ <%= yield %>
750
+ <div>
751
+ </body>
752
+ </html>
753
+ ```
754
+
755
+ #### Create private room functions
756
+
757
+ Create MVC by generator:
758
+
759
+ ```bash
760
+ $ rails g scaffold room name:string
761
+ $ rails g scaffold entry room:references user:references
762
+ $ rake db:migrate
763
+ ```
764
+
765
+ Update your `room.rb` like this:
766
+
767
+ ```ruby:app/models/room.rb
768
+ # app/models/room.rb
769
+
770
+ class Room < ApplicationRecord
771
+ has_many :entries, dependent: :destroy
772
+ has_many :members, through: :entries, source: :user
773
+
774
+ def member?(user)
775
+ members.include?(user)
776
+ end
777
+ end
778
+ ```
779
+
780
+ Add uniqueness validation to your `entry.rb` like this:
781
+
782
+ ```ruby:app/models/entry.rb
783
+ # app/models/entry.rb
784
+
785
+ class Entry < ApplicationRecord
786
+ belongs_to :room
787
+ belongs_to :user
788
+ # Add uniqueness validation
789
+ validates :user, uniqueness: { scope: :room }
790
+ end
791
+ ```
792
+
793
+ Update *create* and *destroy* method in your `entries_controller.rb` like this:
794
+
795
+ ```ruby:app/controllers/entries_controller.rb
796
+ # app/controllers/entries_controller.rb
797
+
798
+ class EntriesController < ApplicationController
799
+ before_action :authenticate_user!
800
+ before_action :set_room
801
+ before_action :set_entry, only: [:destroy]
802
+
803
+ # POST /entries
804
+ # POST /entries.json
805
+ def create
806
+ @entry = Entry.new(entry_params)
807
+
808
+ respond_to do |format|
809
+ if @entry.save
810
+ format.html { redirect_to @room, notice: 'Member was successfully added.' }
811
+ format.json { render :show, status: :created, location: @room }
812
+ else
813
+ format.html { redirect_to @room, notice: @entry.errors }
814
+ format.json { render json: @entry.errors, status: :unprocessable_entity }
815
+ end
816
+ end
817
+ end
818
+
819
+ # DELETE /entries/1
820
+ # DELETE /entries/1.json
821
+ def destroy
822
+ @entry.destroy
823
+ respond_to do |format|
824
+ format.html { redirect_to @room, notice: 'Member was successfully removed.' }
825
+ format.json { head :no_content }
826
+ end
827
+ end
828
+
829
+ private
830
+ # Use callbacks to share common setup or constraints between actions.
831
+ def set_room
832
+ @room = Room.find(params[:room_id])
833
+ end
834
+
835
+ # Use callbacks to share common setup or constraints between actions.
836
+ def set_entry
837
+ @entry = Entry.find(params[:id])
838
+ end
839
+
840
+ # Only allow a list of trusted parameters through.
841
+ def entry_params
842
+ params.require(:entry).permit(:room_id, :user_id)
843
+ end
844
+ end
845
+ ```
846
+
847
+ #### Develop meeting functions with amazon-chime-sdk-rails
848
+
849
+ Install *amazon-chime-sdk-rails* and generates your controllers:
850
+
851
+ ```bash
852
+ $ rails g chime_sdk:install
853
+ $ rails g chime_sdk:controllers -r room
854
+ ```
855
+
856
+ Add and uncomment several functions in generated `meetings_controller.rb` and `meeting_attendees_controller.rb` for your app configurations:
857
+
858
+ ```ruby:app/controllers/api/meetings_controller.rb
859
+ # app/controllers/api/meetings_controller.rb
860
+
861
+ class MeetingsController < ApplicationController
862
+ before_action :authenticate_user!
863
+ before_action :set_room
864
+ before_action :check_membership
865
+
866
+ include ChimeSdk::Controller::Meetings::Mixin
867
+
868
+ private
869
+ # Add
870
+ def set_room
871
+ @room = Room.find(params[:room_id])
872
+ end
873
+
874
+ # Add
875
+ def check_membership
876
+ unless @room.member?(current_user)
877
+ message = 'Unauthorized: you are not a member of this private room.'
878
+ redirect_to @room, notice: message
879
+ end
880
+ end
881
+
882
+ # Uncomment
883
+ def meeting_request_id
884
+ "PrivateRoom-#{@room.id}"
885
+ end
886
+
887
+ # Uncomment
888
+ def attendee_request_id
889
+ "User-#{current_user.id}"
890
+ end
891
+
892
+ # Uncomment
893
+ def application_meeting_metadata(meeting)
894
+ {
895
+ "MeetingType": "PrivateRoom",
896
+ "Room": @room
897
+ }
898
+ end
899
+
900
+ # Uncomment
901
+ def application_attendee_metadata(attendee)
902
+ user_id = attendee[:Attendee][:ExternalUserId].split('-')[3]
903
+ {
904
+ "AttendeeType": "User",
905
+ "User": User.find_by_id(user_id)
906
+ }
907
+ end
908
+
909
+ # Uncomment
910
+ def application_attendee_metadata(attendee)
911
+ user_id = attendee[:Attendee][:ExternalUserId].split('-')[3]
912
+ {
913
+ "AttendeeType": "User",
914
+ "User": User.find_by_id(user_id)
915
+ }
916
+ end
917
+ end
918
+ ```
919
+
920
+ ```ruby:app/controllers/api/meeting_attendees_controller.rb
921
+ # app/controllers/api/meeting_attendees_controller.rb
922
+
923
+ class MeetingAttendeesController < ApplicationController
924
+ before_action :authenticate_user!
925
+ before_action :set_room
926
+ before_action :check_membership
927
+
928
+ include ChimeSdk::Controller::Attendees::Mixin
929
+
930
+ private
931
+ # Add
932
+ def set_room
933
+ @room = Room.find(params[:room_id])
934
+ end
935
+
936
+ # Add
937
+ def check_membership
938
+ unless @room.member?(current_user)
939
+ message = 'Unauthorized: you are not a member of this private room.'
940
+ redirect_to @room, notice: message
941
+ end
942
+ end
943
+
944
+ # Uncomment
945
+ def attendee_request_id
946
+ "User-#{current_user.id}"
947
+ end
948
+
949
+ # Uncomment
950
+ def application_attendee_metadata(attendee)
951
+ user_id = attendee[:Attendee][:ExternalUserId].split('-')[3]
952
+ {
953
+ "AttendeeType": "User",
954
+ "User": User.find_by_id(user_id)
955
+ }
956
+ end
957
+ end
958
+ ```
959
+
960
+ Generates meeting views by *amazon-chime-sdk-rails* generator:
961
+
962
+ ```bash
963
+ $ rails g chime_sdk:views
964
+ ```
965
+
966
+ Simply customize your meeting view generated *app/views/meetings/show.html.erb*:
967
+
968
+ ```javascript
969
+ // app/views/meetings/show.html.erb
970
+
971
+ function showApplicationUserName(attendee) {
972
+ // Comment
973
+ // return attendee.Attendee.AttendeeId;
974
+ // Uncomment
975
+ return `${attendee.Attendee.ApplicationMetadata.User.name} (${attendee.Attendee.AttendeeId})`;
976
+ }
977
+ ```
978
+
979
+ Bundle Amazon Chime SDK into single amazon-chime-sdk.min.js file and copy it to *app/assets/javascripts* by *amazon-chime-sdk-rails* generator:
980
+
981
+ ```bash
982
+ $ rails g chime_sdk:js
983
+ ```
984
+
985
+ Add *amazon-chime-sdk.min.js* to your Asset Pipeline:
986
+
987
+ ```ruby:config/initializers/assets.rb
988
+ # config/initializers/assets.rb
989
+
990
+ Rails.application.config.assets.precompile += %w( amazon-chime-sdk.min.js )
991
+ ```
992
+
993
+ Then, add member management and meeting link to your room view:
994
+
995
+ ```erb:app/views/rooms/show.html.erb
996
+ # app/views/rooms/show.html.erb
997
+
998
+ <p id="notice"><%= notice %></p>
999
+
1000
+ <p>
1001
+ <strong>Name:</strong>
1002
+ <%= @room.name %>
1003
+ </p>
1004
+
1005
+ <p>
1006
+ <strong>Private Meeting:</strong>
1007
+ <p><%= link_to 'Show Meetings', room_meetings_path(@room) %></p>
1008
+ <p><%= link_to 'Join the Meeting', room_meetings_path(@room), method: :post %></p>
1009
+ </p>
1010
+
1011
+ <p>
1012
+ <strong>Members:</strong>
1013
+ <table>
1014
+ <tbody>
1015
+ <% @room.entries.each do |entry| %>
1016
+ <tr>
1017
+ <td><%= entry.user.name %></td>
1018
+ <td><%= link_to 'Remove', [@room, entry], method: :delete, data: { confirm: 'Are you sure?' } %></td>
1019
+ </tr>
1020
+ <% end %>
1021
+ </tbody>
1022
+ </table>
1023
+ </p>
1024
+
1025
+ <p>
1026
+ <strong>Add members:</strong>
1027
+ <%= form_for [@room, Entry.new] do |f| %>
1028
+ <%= f.hidden_field :room_id, value: @room.id %>
1029
+ <%= f.collection_select :user_id, User.all, :id, :name %>
1030
+ <%= f.submit "Add" %>
1031
+ <% end %>
1032
+ </p>
1033
+
1034
+ <%= link_to 'Edit', edit_room_path(@room) %> |
1035
+ <%= link_to 'Back', rooms_path %>
1036
+ ```
1037
+
1038
+ Update your `routes.rb` like this:
1039
+
1040
+ ```ruby:config/routes.rb
1041
+ # config/routes.rb
1042
+
1043
+ Rails.application.routes.draw do
1044
+ root "rooms#index"
1045
+ devise_for :users
1046
+ resources :rooms do
1047
+ resources :entries, only: [:create, :destroy]
1048
+ resources :meetings, only: [:index, :show, :create, :destroy] do
1049
+ resources :meeting_attendees, as: :attendees, path: :attendees, only: [:index, :show]
1050
+ end
1051
+ end
1052
+ end
1053
+ ```
1054
+
1055
+ Note that you need to set up AWS credentials or IAM role for *amazon-chime-sdk-rails*. See [Set up AWS credentials](#set-up-aws-credentials) for more details.
1056
+
1057
+ Finally, start rails server:
1058
+
1059
+ ```bash
1060
+ $ rails server
1061
+ ```
1062
+
1063
+ Now ready to take off!
1064
+
1065
+ #### Start meeting with your Rails application
1066
+
1067
+ Access *http://localhost:3000/* through your web browser.
1068
+
1069
+ Sign up users from *Sign up* header. For example, sign up *ichiro* as *ichiro@example.com* and *stephen* as *stephen@example.com*.
1070
+
1071
+ Create new room and add *ichiro* and *stephen* as a room member.
1072
+
1073
+ Now you can join the meeting from *"Join the Meeting"* link in your room view. Your rails application includes simple online meeting implementation using [Amazon Chime SDK](https://aws.amazon.com/chime/chime-sdk) as a Rails view.
1074
+
1075
+ ##### The meeting has been created
1076
+
1077
+ <kbd>![meeting-created-image](https://raw.githubusercontent.com/simukappu/amazon-chime-sdk-rails/images/meeting_created.png)</kbd>
1078
+
1079
+ ##### Ichiro and Stephen have joined the meeting
1080
+
1081
+ <kbd>![meeting-created-image](https://raw.githubusercontent.com/simukappu/amazon-chime-sdk-rails/images/meeting_joined.png)</kbd>
1082
+
1083
+ You should customize your meeting view using [Amazon Chime SDK for JavaScript](https://github.com/aws/amazon-chime-sdk-js). See [sample Rails application](/spec/rails_app/) using [Amazon Chime SDK for JavaScript](https://github.com/aws/amazon-chime-sdk-js) as a part of [example Rails application](#examples).
1084
+
1085
+
1086
+ ## Documentation
1087
+
1088
+ See [API Reference](http://www.rubydoc.info/github/simukappu/amazon-chime-sdk-rails/index) for more details.
1089
+
1090
+
1091
+ ## Examples
1092
+
1093
+ See example Rails application in *[/spec/rails_app](/spec/rails_app)*. You can run this example Rails application by the following steps:
1094
+
1095
+ ```bash
1096
+ $ git clone https://github.com/simukappu/amazon-chime-sdk-rails.git
1097
+ $ cd amazon-chime-sdk-rails
1098
+ $ bundle install
1099
+ $ cd spec/rails_app
1100
+ $ bin/rake db:migrate
1101
+ $ bin/rake db:seed
1102
+ $ bin/rails g chime_sdk:js
1103
+ $ bin/rails server
1104
+ ```
1105
+
1106
+
1107
+ ## License
1108
+
1109
+ *amazon-chime-sdk-rails* project rocks and uses [MIT License](LICENSE).