-
-
Save supertinou/6f1e8fd4436471278238 to your computer and use it in GitHub Desktop.
Snippets for the Realtime quiz tutorial
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| git clone git@github.com:supertinou/livequiz.git && cd livequiz && git reset --hard SAMPLE-QUIZ-APP |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| gem 'pubnub', '~> 3.7' | |
| gem 'pubnub-js', '~> 3.7' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class LiveQuiz | |
| constructor: () -> | |
| @heartbeat = 20 | |
| @uuid = ............. | |
| @auth_key = ........ | |
| @session_key = ............ | |
| @participant = .............. | |
| @client_channel = @session_key+"-client" | |
| @server_channel = @session_key+"-server" | |
| @chat_channel = @session_key+"-chat" | |
| @pubnub = PUBNUB( | |
| publish_key: '<%= ENV.fetch('PUBNUB_PUBLISH_KEY') %>' | |
| subscribe_key: '<%= ENV.fetch('PUBNUB_SUBSCRIBE_KEY') %>' | |
| auth_key: @auth_key | |
| uuid: @uuid | |
| origin: 'pubsub.pubnub.com' | |
| ssl: true | |
| ) | |
| ##################### UTILITIES ######################## | |
| # Fetch a react component from the react name | |
| react: (react_name) -> | |
| $("[data-react-class=#{react_name}]").get(0) | |
| @liveQuiz = new LiveQuiz() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| gem 'gon' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <%= include_gon %> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| gon.push({ | |
| participant: @participant, | |
| session_key: @session.access_key | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @uuid = gon.participant.authorization_key | |
| @auth_key = gon.participant.authorization_password | |
| @session_key = gon.session_key | |
| @participant = gon.participant |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| after_commit :set_forbidden_access_to_session_channels, on: [:create,:destroy] | |
| after_commit :allow_full_rights_to_channels_to_quiz, on: [:create] | |
| def server_channel | |
| "#{access_key}-server" | |
| end | |
| def client_channel | |
| "#{access_key}-client" | |
| end | |
| def chat_channel | |
| "#{access_key}-chat" | |
| end | |
| def set_forbidden_access_to_session_channels | |
| [server_channel,client_channel,chat_channel].each do |chan| | |
| PubnubSingleton.client.grant(http_sync: true, channel: chan, read: false, write: false){|envelope|} | |
| end | |
| end | |
| def allow_full_rights_to_channels_to_quiz | |
| [server_channel,client_channel].each do |chan| | |
| PubnubSingleton.client.grant(http_sync: true, channel: chan, presence: chan, auth_key: auth_key, read: true, write: true){|envelope| puts envelope.payload} | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| after_commit :grant_access_to_session_channels, on: :create | |
| after_commit :revoke_access_to_session_channels, on: :destroy | |
| def grant_access_to_session_channels | |
| PubnubSingleton.client.grant(channel: self.session.server_channel, auth_key: self.authorization_password , read: true, write: false){|envelope|} | |
| PubnubSingleton.client.grant(channel: self.session.client_channel, auth_key: self.authorization_password , read: false, write: true){|envelope|} | |
| PubnubSingleton.client.grant(channel: self.session.chat_channel, presence: self.session.chat_channel, auth_key: self.authorization_password){|envelope|} | |
| end | |
| def revoke_access_to_session_channels | |
| PubnubSingleton.client.revoke(channel: self.session.server_channel, auth_key: self.authorization_password){|envelope|} | |
| PubnubSingleton.client.revoke(channel: self.session.client_channel, auth_key: self.authorization_password){|envelope|} | |
| PubnubSingleton.client.revoke(channel: self.session.chat_channel, presence: self.session.chat_channel, auth_key: self.authorization_password){|envelope|} | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <%= react_component('ParticipantsList', participants: [] ) %> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| whoIsHereNow: -> | |
| @pubnub.here_now | |
| channel: @chat_channel | |
| state: true | |
| callback: (message) => | |
| participants = _.map(message.uuids, (participant) -> | |
| { uuid: participant.uuid, status: 'online', name: participant.state.name, email: participant.state.email } | |
| React.render(<ParticipantsList participants=participants />, @react('ParticipantsList')) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @whoIsHereNow() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //= require pubnub |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| subscribeToChatChannel: -> | |
| @pubnub.subscribe | |
| channel: @chat_channel | |
| state: | |
| name: @participant.name | |
| email: @participant.email | |
| message: -> | |
| presence: @presenceCallback | |
| connect: -> | |
| heartbeat: @heartbeat | |
| presenceCallback: (message) -> | |
| status = switch message.action | |
| when 'leave' then 'offline' | |
| when 'timeout' then 'offline' | |
| when 'join' then 'online' | |
| data = message.data || {} | |
| participants = [{uuid: message.uuid, status: status, name: data.name, email: data.email }] | |
| React.render(<ParticipantsList participants=participants />, @react('ParticipantsList')) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @subscribeToChatChannel() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <%= react_component('ParticipantsList', participants: @participant_list ) %> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @participant_list = @session.participants.to_a.collect do |participant| | |
| status = (@participant.id == participant.id) ? 'online' : '' | |
| { uuid: participant.authorization_key, status: status , name: participant.name, email: participant.email } | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| rails g AddCurrentQuestionIndexFieldToSessions current_question_index:integer | |
| rake db:migrate |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def start! | |
| self.current_question_index = 0 | |
| send_current_question() | |
| schedule_switch_to_next_question!(30) | |
| save() | |
| end | |
| def schedule_switch_to_next_question!(secondes) | |
| Rufus::Scheduler.singleton.in "#{secondes}s" do | |
| ActiveRecord::Base.connection_pool.with_connection do | |
| if switch_to_next_question! | |
| schedule_switch_to_next_question!(secondes) | |
| else | |
| finish! | |
| end | |
| end | |
| end | |
| end | |
| def send_current_question | |
| send_event_with_data('question', {question: current_question.format(:title_with_answers)} ) | |
| end | |
| def send_event_with_data(event, data) | |
| message = {event: event, data: data} | |
| PubnubSingleton.client.publish(message: message, channel: self.server_channel, auth_key: auth_key){|envelope|} | |
| end | |
| def switch_to_next_question! | |
| next_question_index = self.current_question_index + 1 | |
| next_question_exist = self.quiz.questions[next_question_index] | |
| succeeded_to_switch = if !next_question_exist.nil? | |
| self.current_question_index = next_question_index | |
| send_current_question() | |
| save() | |
| else | |
| false | |
| end | |
| return succeeded_to_switch | |
| end | |
| def finish! | |
| ## The quiz is finished, do whatever you want! | |
| self.current_question_index = nil | |
| end | |
| def current_question | |
| current_question_index ? self.quiz.questions[current_question_index] : nil | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def format(format_name) | |
| format = if format_name == :title_with_answers | |
| h = { title: title } | |
| h[:answers] = answers.to_a.collect{|answer| {id: answer.id, title: answer.title }} | |
| h | |
| else | |
| raise 'Unknown format' | |
| end | |
| format | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| subscribeToServerChannel: -> | |
| @pubnub.subscribe( | |
| channel: @server_channel | |
| message: @serverCallback | |
| connect: -> | |
| ) | |
| serverCallback: (message, env, ch, timer, magic_ch) => | |
| switch(message.event) | |
| when 'question' then React.render(<QuestionDisplay question=message.data.question />, @react('QuestionDisplay')) | |
| ### Commands called from the QuestionDisplay React component ### | |
| answerQuestion: (id) -> | |
| @sendEvent('answer', {answer_id: id}) | |
| sendEvent: (event, data) -> | |
| @pubnub.publish | |
| channel: @client_channel | |
| message: { event: event, auth_key: @auth_key, data: data} | |
| callback : -> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <%= react_component('QuestionDisplay') %> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def subscribe_to_client_events | |
| PubnubSingleton.client.subscribe( | |
| channel: client_channel, | |
| auth_key: auth_key, | |
| callback: handle_client_events | |
| ) | |
| end | |
| def handle_client_events | |
| lambda do |envelope| | |
| m = envelope.message | |
| case m['event'] | |
| when 'answer' | |
| handle_question_answer(m['auth_key'], m['data']['answer_id']) | |
| end | |
| end | |
| end | |
| def handle_question_answer(auth_key, answer_id) | |
| # Do whatever you want | |
| # Maybe store the answers in the database ? | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'pubnub' | |
| pubnub = Pubnub.new( | |
| subscribe_key: 'demo', | |
| publish_key: 'demo', | |
| ) | |
| pubnub.publish(message: 'hello', channel: 'chan') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| rails g model ParticipantAnswer participant:references answer:references | |
| rake db:migrate |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def handle_question_answer(auth_key, answer_id) | |
| ActiveRecord::Base.connection_pool.with_connection | |
| participant = Participant.find_by(authorization_password: auth_key) | |
| answer = Answer.find(answer_id) | |
| allowed_to_answer_question = ( answer.question.id == current_question.id ) | |
| if allowed_to_answer_question && !participant.have_already_answered_the_question?(answer.question) | |
| participant.answer_question(current_question, answer) | |
| end | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def have_already_answered_the_question?(question) | |
| question.participant_answers.where(participant_id: self.id).count >= 1 | |
| end | |
| def answer_question(question, answer) | |
| participant_answers.build(answer: answer) | |
| save() | |
| answer.correct? | |
| end | |
| def number_of_correct_answers | |
| participant_answers.joins(:answer).where({answers: {correct: true}}).count | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <%= react_component('ActivityFeed' ) %> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| React.render(<ActivityFeed newActivity=message />, @react('ActivityFeed')) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| answered_correctly = participant.answer_question(current_question, answer) | |
| send_event_with_data('answered', { | |
| uuid: participant.authorization_key, | |
| name: participant.name, | |
| timestamp: Time.now.to_i, | |
| answered_correctly | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| switch(message.event) | |
| when 'answered' | |
| activity = { | |
| action: message.event | |
| timestamp: message.data.timestamp | |
| uuid: message.data.uuid | |
| data: | |
| name: message.data.name | |
| correct: message.data.correct | |
| } | |
| React.render(<ActivityFeed newActivity=activity />, @react('ActivityFeed')) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| switch(message.event) | |
| when 'answered' | |
| if message.data.uuid == @uuid | |
| React.render(<SuccessNotifier success=message.data.correct />, @react('QuestionDisplay')) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def finish! | |
| send_results() | |
| self.current_question_index = nil | |
| save() | |
| end | |
| def results | |
| participants.collect do |participant| | |
| { | |
| points: participant.number_of_correct_answers, | |
| uuid: participant.authorization_key, | |
| name: participant.name, | |
| email: participant.email, | |
| correct_answers_number: participant.number_of_correct_answers, | |
| wrong_answers_number: participant.number_of_wrong_answers | |
| } | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| switch(message.event) | |
| when 'results' then React.render(<ResultsDisplay results=message.data.results />, @react('ResultsDisplay')) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'singleton' | |
| class PubnubSingleton | |
| include Singleton | |
| attr_accessor :pubnub | |
| def initialize() | |
| @pubnub = Pubnub.new( | |
| publish_key: ENV['PUBNUB_PUBLISH_KEY'], | |
| subscribe_key: ENV['PUBNUB_SUBSCRIBE_KEY'], | |
| secret_key: ENV['PUBNUB_SECRET_KEY'], | |
| logger: Rails.logger | |
| ) | |
| end | |
| def self.client | |
| self.instance.pubnub | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'pubnub_singleton' | |
| PubnubSingleton.client.publish(message: 'hello', channel: 'chan') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| get 'quiz_sessions/:session_key/:authorization_key/:authorization_password', to: "quiz_sessions#show" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class QuizSessionsController < ApplicationController | |
| def show | |
| @participant = Participant.find_by(authorization_key: params[:authorization_key], authorization_password: params[:authorization_password] ) | |
| @session = Session.find_by(access_key: params[:session_key]) | |
| if @participant.nil? || (@session.id != @participant.session ) | |
| redirect_to root_path, notice: 'You are not authorized to access this session' | |
| end | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def quiz_session_link(participant) | |
| path = "/quiz_sessions/#{participant.session.access_key}/#{participant.authorization_key}/#{participant.authorization_password}" | |
| "http://"+ ENV['HOST']+path | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <%= quiz_session_link(@participant) %> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment