| @ -0,0 +1,33 @@ | |||
| class AnswersController < ApplicationController | |||
| include QuizHelperMethods | |||
| # POST /q/:id/answer | |||
| def create | |||
| not_found unless question | |||
| @answer = Answer.new(answer_params.merge(player_id: current_player.id, node_id: question.id)) | |||
| respond_to do |format| | |||
| if @answer.save | |||
| format.html { redirect_to url_for(controller: 'questions', action: 'answer', id: params[:id]) } | |||
| else | |||
| format.html { render 'questions/show', status: :unprocessable_entity } | |||
| end | |||
| end | |||
| end | |||
| private | |||
| # Only allow a list of trusted parameters through. | |||
| def answer_params | |||
| params.require(:answer).permit( | |||
| :value | |||
| ) | |||
| end | |||
| end | |||
| @ -0,0 +1,60 @@ | |||
| module QuizHelperMethods | |||
| extend ActiveSupport::Concern | |||
| included do | |||
| before_action :require_player! | |||
| before_action :set_locale | |||
| helper_method :current_player, | |||
| :questions, | |||
| :question, | |||
| :questions_size, | |||
| :question_index | |||
| end | |||
| private | |||
| def questions | |||
| @questions ||= Node.at_depth(1).viewable.ordered.to_a | |||
| end | |||
| def question | |||
| @question ||= questions[params[:id].to_i-1] | |||
| end | |||
| def questions_size | |||
| @questions_size ||= questions.size + 1 | |||
| end | |||
| def question_index | |||
| @question_index ||= (params[:id].to_i + 1) | |||
| end | |||
| def require_player! | |||
| unless player_present? | |||
| redirect_to url_for(controller: 'players', action: 'new') | |||
| end | |||
| end | |||
| def current_player | |||
| Current.player ||= player_from_session | |||
| end | |||
| def player_from_session | |||
| Player.find_by(id: session[:player_id]) | |||
| end | |||
| def player_present? | |||
| current_player.present? | |||
| end | |||
| end | |||
| @ -0,0 +1,42 @@ | |||
| class PlayersController < ApplicationController | |||
| include QuizHelperMethods | |||
| skip_before_action :require_player! | |||
| # GET /player | |||
| def new | |||
| reset_session | |||
| Current.player = nil | |||
| @player = Player.new | |||
| end | |||
| # POST /player | |||
| def create | |||
| @player = Player.new(player_params.merge(locale: I18n.locale)) | |||
| respond_to do |format| | |||
| if @player.save | |||
| session[:player_id] = @player.id | |||
| format.html { redirect_to url_for(controller: 'questions', action: 'show', id: 1) } | |||
| else | |||
| format.html { render :new, status: :unprocessable_entity } | |||
| end | |||
| end | |||
| end | |||
| private | |||
| # Only allow a list of trusted parameters through. | |||
| def player_params | |||
| params.require(:player).permit( | |||
| :name | |||
| ) | |||
| end | |||
| end | |||
| @ -0,0 +1,24 @@ | |||
| class QuestionsController < ApplicationController | |||
| include QuizHelperMethods | |||
| def show | |||
| not_found unless question | |||
| @answer = Answer.new(player_id: current_player.id, node_id: question.id) | |||
| end | |||
| def answer | |||
| @answer = Answer.find_by(node_id: question.id, player_id: current_player.id) | |||
| @question_answer = question.attachments.with_text.each_slice(2).to_a[@answer.value] | |||
| end | |||
| end | |||
| @ -0,0 +1,2 @@ | |||
| module AnswersHelper | |||
| end | |||
| @ -0,0 +1,2 @@ | |||
| module PlayersHelper | |||
| end | |||
| @ -0,0 +1,2 @@ | |||
| module QuestionsHelper | |||
| end | |||
| @ -0,0 +1,9 @@ | |||
| class Answer < ApplicationRecord | |||
| belongs_to :player | |||
| belongs_to :node | |||
| validates :value, presence: true | |||
| validates :value, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 1 } | |||
| end | |||
| @ -1,3 +1,3 @@ | |||
| class Current < ActiveSupport::CurrentAttributes | |||
| attribute :user | |||
| attribute :user, :player | |||
| end | |||
| @ -0,0 +1,7 @@ | |||
| class Player < ApplicationRecord | |||
| validates_presence_of :name | |||
| has_many :answers, dependent: :destroy | |||
| end | |||
| @ -1,9 +1,10 @@ | |||
| <turbo-stream action="append" targets="#attachments"> | |||
| <template> | |||
| <% time_stamp = (Time.now.to_f * 1000).to_i %> | |||
| <% @attachments.each_with_index do |attachment, i| %> | |||
| <% tmp_id = Time.now.to_i + i %> | |||
| <% tmp_id = time_stamp + i %> | |||
| <%= fields_for "#{@attachable_for.class.name.underscore.singularize}[attachments_attributes][#{ tmp_id }]", attachment do |builder| %> | |||
| <%= render partial: 'admin/attachments/attachment', locals: {f: builder, tmp_id: tmp_id}, formats: :html %> | |||
| <%= render partial: 'admin/attachments/attachment', locals: {f: builder, tmp_id: tmp_id}, formats: :html %> | |||
| <% end %> | |||
| <% end %> | |||
| </template> | |||
| @ -1,6 +1,7 @@ | |||
| <% Node.roots.first.attachments.limit(2).each_with_index do |attachment, i| %> | |||
| <% Node.roots.viewable.first.attachments.limit(2).each_with_index do |attachment, i| %> | |||
| <%= tag.div attachment.body.html_safe, class: i == 0 ? "intro-content-header" : "intro-content-body" %> | |||
| <% end %> | |||
| <%= link_to t('get_started'), Node.roots.first.children.first.url, class: 'button__base' %> | |||
| <%= link_to t('get_started'), url_for(controller: 'players', action: 'new', locale: I18n.locale), class: 'button__base' %> | |||
| @ -0,0 +1,26 @@ | |||
| <%- | |||
| content_for :title, t('what_is_your_name') | |||
| %> | |||
| <%= form_with model: @player, url: url_for(controller: 'players', action: 'create') do |form| %> | |||
| <div class="question-container"> | |||
| <div class="question-step"> | |||
| <div>1/<%= questions_size %></div> | |||
| </div> | |||
| <div class="question-header"> | |||
| <%= t 'what_is_your_name' %> | |||
| </div> | |||
| <%= form.label :name, class: "question-answer" do %> | |||
| <%= form.text_field :name, placeholder: t('what_is_your_name') %> | |||
| <% end %> | |||
| <%= form.submit t('submit'), class: 'button__base' %> | |||
| </div> | |||
| <% end %> | |||
| @ -0,0 +1,19 @@ | |||
| <%- | |||
| content_for :title, question.page_title.blank? ? question.title : question.page_title | |||
| content_for :meta_description, question.page_description | |||
| %> | |||
| <div class="question-container"> | |||
| <div class="question-step"> | |||
| <div><%= question_index %>/<%= questions_size %></div> | |||
| </div> | |||
| <div class="question-result"> | |||
| <%= @question_answer.last.body.html_safe %> | |||
| </div> | |||
| <%= link_to t('next_question'), url_for(controller: 'questions', action: 'show', id: question_index), class: 'button__base' %> | |||
| </div> | |||
| @ -0,0 +1,31 @@ | |||
| <%- | |||
| content_for :title, question.page_title.blank? ? question.title : question.page_title | |||
| content_for :meta_description, question.page_description | |||
| %> | |||
| <%= form_with model: @answer, url: url_for(controller: 'answers', action: 'create') do |form| %> | |||
| <div class="question-container"> | |||
| <div class="question-step"> | |||
| <div><%= question_index %>/<%= questions_size %></div> | |||
| </div> | |||
| <div class="question-header"> | |||
| <%= question.title %> | |||
| </div> | |||
| <% question.attachments.with_text.each_slice(2).each_with_index do |answer_option, i| %> | |||
| <div class="question-answer"> | |||
| <%= form.label :value, for: nil do %> | |||
| <%= answer_option.first.body.html_safe %> | |||
| <%= form.radio_button :value, i %> | |||
| <%- end -%> | |||
| </div> | |||
| <% end %> | |||
| <%= form.submit t('submit'), class: 'button__base' %> | |||
| </div> | |||
| <% end %> | |||
| @ -0,0 +1,11 @@ | |||
| class CreatePlayers < ActiveRecord::Migration[8.0] | |||
| def change | |||
| create_table :players do |t| | |||
| t.text :name | |||
| t.text :locale | |||
| t.timestamps | |||
| end | |||
| end | |||
| end | |||
| @ -0,0 +1,14 @@ | |||
| class CreateAnswers < ActiveRecord::Migration[8.0] | |||
| def change | |||
| create_table :answers do |t| | |||
| t.references :player | |||
| t.references :node | |||
| t.integer :value, default: nil, index: true | |||
| t.timestamps | |||
| end | |||
| end | |||
| end | |||
| @ -0,0 +1,7 @@ | |||
| require "test_helper" | |||
| class AnswersControllerTest < ActionDispatch::IntegrationTest | |||
| # test "the truth" do | |||
| # assert true | |||
| # end | |||
| end | |||
| @ -0,0 +1,7 @@ | |||
| require "test_helper" | |||
| class PlayersControllerTest < ActionDispatch::IntegrationTest | |||
| # test "the truth" do | |||
| # assert true | |||
| # end | |||
| end | |||
| @ -0,0 +1,7 @@ | |||
| require "test_helper" | |||
| class QuestionsControllerTest < ActionDispatch::IntegrationTest | |||
| # test "the truth" do | |||
| # assert true | |||
| # end | |||
| end | |||
| @ -0,0 +1,11 @@ | |||
| # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html | |||
| # This model initially had no columns defined. If you add columns to the | |||
| # model remove the "{}" from the fixture names and add the columns immediately | |||
| # below each fixture, per the syntax in the comments below | |||
| # | |||
| one: {} | |||
| # column: value | |||
| # | |||
| two: {} | |||
| # column: value | |||
| @ -0,0 +1,11 @@ | |||
| # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html | |||
| # This model initially had no columns defined. If you add columns to the | |||
| # model remove the "{}" from the fixture names and add the columns immediately | |||
| # below each fixture, per the syntax in the comments below | |||
| # | |||
| one: {} | |||
| # column: value | |||
| # | |||
| two: {} | |||
| # column: value | |||
| @ -0,0 +1,7 @@ | |||
| require "test_helper" | |||
| class AnswerTest < ActiveSupport::TestCase | |||
| # test "the truth" do | |||
| # assert true | |||
| # end | |||
| end | |||
| @ -0,0 +1,7 @@ | |||
| require "test_helper" | |||
| class PlayerTest < ActiveSupport::TestCase | |||
| # test "the truth" do | |||
| # assert true | |||
| # end | |||
| end | |||