amazon-chime-sdk-rails 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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).