ask_it 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +11 -0
  3. data/LICENSE.md +21 -0
  4. data/README.md +287 -0
  5. data/Rakefile +29 -0
  6. data/app/controllers/ask_it/attempts_controller.rb +36 -0
  7. data/app/controllers/ask_it/surveys_controller.rb +58 -0
  8. data/app/models/ask_it/answer.rb +99 -0
  9. data/app/models/ask_it/attempt.rb +108 -0
  10. data/app/models/ask_it/option.rb +65 -0
  11. data/app/models/ask_it/options_type.rb +39 -0
  12. data/app/models/ask_it/predefined_value.rb +24 -0
  13. data/app/models/ask_it/question.rb +73 -0
  14. data/app/models/ask_it/question_type.rb +32 -0
  15. data/app/models/ask_it/section.rb +66 -0
  16. data/app/models/ask_it/survey.rb +77 -0
  17. data/config/locales/en.yml +54 -0
  18. data/config/locales/pt-PT.yml +48 -0
  19. data/config/locales/pt.yml +48 -0
  20. data/lib/ask_it/active_record.rb +25 -0
  21. data/lib/ask_it/engine.rb +8 -0
  22. data/lib/ask_it/railtie.rb +13 -0
  23. data/lib/ask_it/version.rb +5 -0
  24. data/lib/ask_it.rb +20 -0
  25. data/lib/generators/ask_it/install_generator.rb +57 -0
  26. data/lib/generators/ask_it/survey_generator.rb +117 -0
  27. data/lib/generators/templates/active_admin.rb +87 -0
  28. data/lib/generators/templates/controllers/attempts_controller.rb +11 -0
  29. data/lib/generators/templates/controllers/surveys_controller.rb +31 -0
  30. data/lib/generators/templates/helpers/ask_it/surveys_helper.rb +56 -0
  31. data/lib/generators/templates/migration.rb.tt +59 -0
  32. data/lib/generators/templates/migration_add_head_number_to_options_table.rb.tt +8 -0
  33. data/lib/generators/templates/migration_add_mandatory_to_questions_table.rb.tt +8 -0
  34. data/lib/generators/templates/migration_add_types_to_questions_and_options.rb.tt +15 -0
  35. data/lib/generators/templates/migration_create_predefined_values_table.rb.tt +16 -0
  36. data/lib/generators/templates/migration_section.rb.tt +24 -0
  37. data/lib/generators/templates/migration_update_survey_tables.rb.tt +24 -0
  38. data/lib/generators/templates/rails_admin.rb +10 -0
  39. data/lib/generators/templates/views/attempts/_form.html.erb +61 -0
  40. data/lib/generators/templates/views/attempts/new.html.erb +10 -0
  41. data/lib/generators/templates/views/surveys/_form.html.erb +78 -0
  42. data/lib/generators/templates/views/surveys/_option_fields.html.erb +26 -0
  43. data/lib/generators/templates/views/surveys/_question_fields.html.erb +42 -0
  44. data/lib/generators/templates/views/surveys/_section_fields.html.erb +29 -0
  45. data/lib/generators/templates/views/surveys/edit.html.erb +2 -0
  46. data/lib/generators/templates/views/surveys/index.html.erb +14 -0
  47. data/lib/generators/templates/views/surveys/new.html.erb +2 -0
  48. data/lib/survey.rb +7 -0
  49. data/lib/tasks/changelog.rake +10 -0
  50. metadata +372 -0
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AskIt
4
+ class Option < ActiveRecord::Base
5
+ self.table_name = 'survey_options'
6
+ # relations
7
+ belongs_to :question
8
+ has_many :answers
9
+
10
+ # rails 3 attr_accessible support
11
+ if Rails::VERSION::MAJOR < 4
12
+ attr_accessible :text, :correct, :weight, :question_id, :locale_text, :options_type_id, :head_number
13
+ end
14
+
15
+ # validations
16
+ validates :text, presence: true, allow_blank: false, if: :requires_text?
17
+ validates :options_type_id, presence: true
18
+ validates :options_type_id, inclusion: { in: AskIt::OptionsType.options_type_ids, unless: proc { |o|
19
+ o.options_type_id.blank?
20
+ } }
21
+
22
+ scope :correct, -> { where(correct: true) }
23
+ scope :incorrect, -> { where(correct: false) }
24
+
25
+ before_create :default_option_weigth
26
+
27
+ def to_s
28
+ text
29
+ end
30
+
31
+ def correct?
32
+ correct == true
33
+ end
34
+
35
+ def text
36
+ if I18n.locale == I18n.default_locale
37
+ super
38
+ else
39
+ locale_text.blank? ? super : locale_text
40
+ end
41
+ end
42
+
43
+ #######
44
+
45
+ private
46
+
47
+ #######
48
+
49
+ def default_option_weigth
50
+ self.weight = 1 if correct && weight.zero?
51
+ end
52
+
53
+ def requires_text?
54
+ [
55
+ AskIt::OptionsType.multi_choices,
56
+ AskIt::OptionsType.single_choice,
57
+ AskIt::OptionsType.single_choice_with_text,
58
+ AskIt::OptionsType.single_choice_with_number,
59
+ AskIt::OptionsType.multi_choices_with_text,
60
+ AskIt::OptionsType.multi_choices_with_number,
61
+ AskIt::OptionsType.large_text
62
+ ].include?(options_type_id)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AskIt
4
+ class OptionsType
5
+ @@options_types = { multi_choices: 1,
6
+ single_choice: 2,
7
+ number: 3,
8
+ text: 4,
9
+ multi_choices_with_text: 5,
10
+ single_choice_with_text: 6,
11
+ multi_choices_with_number: 7,
12
+ single_choice_with_number: 8,
13
+ large_text: 9 }
14
+
15
+ def self.options_types
16
+ @@options_types
17
+ end
18
+
19
+ def self.options_types_title
20
+ titled = {}
21
+ AskIt::OptionsType.options_types.each { |k, v| titled[k.to_s.titleize] = v }
22
+ titled
23
+ end
24
+
25
+ def self.options_type_ids
26
+ @@options_types.values
27
+ end
28
+
29
+ def self.options_type_keys
30
+ @@options_types.keys
31
+ end
32
+
33
+ @@options_types.each do |key, val|
34
+ define_singleton_method key.to_s do
35
+ val
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AskIt
4
+ class PredefinedValue < ActiveRecord::Base
5
+ self.table_name = 'survey_predefined_values'
6
+
7
+ # relations
8
+ belongs_to :question
9
+
10
+ # rails 3 attr_accessible support
11
+ attr_accessible :head_number, :name, :locale_name, :question_id if Rails::VERSION::MAJOR < 4
12
+
13
+ # validations
14
+ validates :name, presence: true
15
+
16
+ def to_s
17
+ name
18
+ end
19
+
20
+ def name
21
+ I18n.locale == I18n.default_locale ? super : locale_name || super
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # app/models/ask_it/question.rb
4
+
5
+ module AskIt
6
+ class Question < ActiveRecord::Base
7
+ self.table_name = 'survey_questions'
8
+ # relations
9
+ has_many :options
10
+ has_many :predefined_values
11
+ has_many :answers
12
+ belongs_to :section
13
+
14
+ # rails 3 attr_accessible support
15
+ if Rails::VERSION::MAJOR < 4
16
+ attr_accessible :options_attributes, :predefined_values_attributes, :text, :section_id, :head_number, :description,
17
+ :locale_text, :locale_head_number, :locale_description, :questions_type_id
18
+ end
19
+
20
+ accepts_nested_attributes_for :options,
21
+ reject_if: ->(a) { a[:options_type_id].blank? },
22
+ allow_destroy: true
23
+
24
+ accepts_nested_attributes_for :predefined_values,
25
+ reject_if: ->(a) { a[:name].blank? },
26
+ allow_destroy: true
27
+
28
+ # validations
29
+ validates :text, presence: true, allow_blank: false
30
+ validates :questions_type_id, presence: true
31
+ validates :questions_type_id, inclusion: { in: AskIt::QuestionType.questions_type_ids, unless: proc { |q|
32
+ q.questions_type_id.blank?
33
+ } }
34
+
35
+ scope :mandatory_only, -> { where(mandatory: true) }
36
+
37
+ def correct_options
38
+ options.correct
39
+ end
40
+
41
+ def incorrect_options
42
+ options.incorrect
43
+ end
44
+
45
+ def text
46
+ if I18n.locale == I18n.default_locale
47
+ super
48
+ else
49
+ locale_text.blank? ? super : locale_text
50
+ end
51
+ end
52
+
53
+ def description
54
+ if I18n.locale == I18n.default_locale
55
+ super
56
+ else
57
+ locale_description.blank? ? super : locale_description
58
+ end
59
+ end
60
+
61
+ def head_number
62
+ if I18n.locale == I18n.default_locale
63
+ super
64
+ else
65
+ locale_head_number.blank? ? super : locale_head_number
66
+ end
67
+ end
68
+
69
+ def mandatory?
70
+ mandatory == true
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # app/models/ask_it/questions_type.rb
4
+ module AskIt
5
+ class QuestionType
6
+ @@questions_types = { multiple_choice: 2, free_response: 9, multi_select: 1 }
7
+
8
+ def self.questions_types
9
+ @@questions_types
10
+ end
11
+
12
+ def self.questions_types_title
13
+ titled = {}
14
+ AskIt::QuestionType.questions_types.each { |k, v| titled[k.to_s.titleize] = v }
15
+ titled
16
+ end
17
+
18
+ def self.questions_type_ids
19
+ @@questions_types.values
20
+ end
21
+
22
+ def self.questions_type_keys
23
+ @@questions_types.keys
24
+ end
25
+
26
+ @@questions_types.each do |key, val|
27
+ define_singleton_method key.to_s do
28
+ val
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AskIt
4
+ class Section < ActiveRecord::Base
5
+ self.table_name = 'survey_sections'
6
+
7
+ # relations
8
+ has_many :questions
9
+ belongs_to :survey
10
+
11
+ # rails 3 attr_accessible support
12
+ if Rails::VERSION::MAJOR < 4
13
+ attr_accessible :questions_attributes, :head_number, :name, :description, :survey_id, :locale_head_number,
14
+ :locale_name, :locale_description
15
+ end
16
+
17
+ accepts_nested_attributes_for :questions,
18
+ reject_if: ->(q) { q[:text].blank? }, allow_destroy: true
19
+
20
+ # validations
21
+ validates :name, presence: true, allow_blank: false
22
+ validate :check_questions_requirements
23
+
24
+ def name
25
+ if I18n.locale == I18n.default_locale
26
+ super
27
+ else
28
+ locale_name.blank? ? super : locale_name
29
+ end
30
+ end
31
+
32
+ def description
33
+ if I18n.locale == I18n.default_locale
34
+ super
35
+ else
36
+ locale_description.blank? ? super : locale_description
37
+ end
38
+ end
39
+
40
+ def head_number
41
+ if I18n.locale == I18n.default_locale
42
+ super
43
+ else
44
+ locale_head_number.blank? ? super : locale_head_number
45
+ end
46
+ end
47
+
48
+ def full_name
49
+ head_name = head_number.blank? ? '' : "#{head_number}: "
50
+ "#{head_name}#{name}"
51
+ end
52
+
53
+ #######
54
+
55
+ private
56
+
57
+ #######
58
+
59
+ # a section only can be saved if has one or more questions and options
60
+ def check_questions_requirements
61
+ return unless questions.empty? || questions.collect(&:options).empty?
62
+
63
+ errors.add(:base, 'Section without questions or options cannot be saved')
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AskIt
4
+ class Survey < ActiveRecord::Base
5
+ self.table_name = 'survey_surveys'
6
+
7
+ # relations
8
+ has_many :attempts, class_name: 'AskIt::Attempt'
9
+ has_many :sections, class_name: 'AskIt::Section'
10
+ has_many :questions, through: :sections, class_name: 'AskIt::Question'
11
+
12
+ # rails 3 attr_accessible support
13
+ if Rails::VERSION::MAJOR < 4
14
+ attr_accessible :name, :description, :finished, :active, :sections_attributes, :attempts_number, :locale_name,
15
+ :locale_description
16
+ end
17
+
18
+ accepts_nested_attributes_for :sections,
19
+ reject_if: ->(q) { q[:name].blank? }, allow_destroy: true
20
+
21
+ scope :active, -> { where(active: true) }
22
+ scope :inactive, -> { where(active: false) }
23
+
24
+ validates :attempts_number,
25
+ numericality: { only_integer: true, greater_than: -1 }
26
+
27
+ # validations
28
+ validates :description, :name, presence: true, allow_blank: false
29
+ validate :check_active_requirements
30
+
31
+ # returns all the correct options for current surveys
32
+ def correct_options
33
+ AskIt::Question.where(section_id: section_ids).map(&:correct_options).flatten
34
+ end
35
+
36
+ # returns all the incorrect options for current surveys
37
+ def incorrect_options
38
+ AskIt::Question.where(section_id: sections.collect(&:id)).map(&:incorrect_options).flatten
39
+ end
40
+
41
+ def avaliable_for_participant?(participant)
42
+ current_number_of_attempts =
43
+ attempts.for_participant(participant).size
44
+ upper_bound = attempts_number
45
+ !(current_number_of_attempts >= upper_bound && upper_bound != 0)
46
+ end
47
+
48
+ def name
49
+ if I18n.locale == I18n.default_locale
50
+ super
51
+ else
52
+ locale_name.blank? ? super : locale_name
53
+ end
54
+ end
55
+
56
+ def description
57
+ if I18n.locale == I18n.default_locale
58
+ super
59
+ else
60
+ locale_description.blank? ? super : locale_description
61
+ end
62
+ end
63
+
64
+ #######
65
+
66
+ private
67
+
68
+ #######
69
+
70
+ # a surveys only can be activated if has one or more sections and questions
71
+ def check_active_requirements
72
+ return unless sections.empty? || sections.collect(&:questions).empty?
73
+
74
+ errors.add(:base, 'Survey without sections or questions cannot be saved')
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,54 @@
1
+ en:
2
+ surveys_controller:
3
+ create: Your Survey has been successfull created
4
+ update: Your Survey has been successfull updated
5
+ attempts_controller:
6
+ create: "Congratulations, you have responded to Survey."
7
+ surveys: Surveys
8
+ survey_details: Survey Details
9
+ questions: Questions
10
+ sections: Sections
11
+ predefined_values: Predefined Values
12
+ activerecord:
13
+ models:
14
+ survey:
15
+ survey: Survey
16
+ other: Surveys
17
+ attributes:
18
+ survey:
19
+ name: Name
20
+ locale_name: Localized name
21
+ finished: Finished
22
+ description: Short description
23
+ locale_description: Localized short description
24
+ active: "Activated?"
25
+ attempts_number: Number of Maximum Attempts
26
+ sections_attributes: Sections
27
+ section:
28
+ head_number: Head Number
29
+ name: Name
30
+ description: Description
31
+ locale_head_number: Localized head number
32
+ locale_name: Localized name
33
+ locale_description: Localized Description
34
+ question:
35
+ head_number: Head Number
36
+ text: Question Text
37
+ description: Description
38
+ locale_head_number: Localized head number
39
+ locale_text: Localized Question Text
40
+ locale_description: Localized Description
41
+ options_attributes: Options
42
+ predefined_values_attributes: Predefined Values
43
+ options:
44
+ text: Option Text
45
+ locale_text: Localized Option Text
46
+ correct: Correct
47
+ attempt:
48
+ answers_attributes: Answers
49
+ survey: Survey
50
+ answer:
51
+ attempt: Attempt
52
+ question: Question
53
+ option: Option
54
+ correct: Answer Correct?
@@ -0,0 +1,48 @@
1
+ pt-PT:
2
+ questions: Perguntas
3
+ survey_details: Detalhes do Questionário
4
+ surveys_controller:
5
+ create: O questionário foi criado com sucesso
6
+ update: O questionário foi atualizado com sucesso
7
+ attempts_controller:
8
+ create: "A sua resposta foi efetuada com sucesso."
9
+ surveys: Questionários
10
+ survey_details: Detalhes do Questionário
11
+ questions: Perguntas
12
+ activerecord:
13
+ models:
14
+ survey:
15
+ survey: Questionário
16
+ other: Questionários
17
+ question:
18
+ question: Pergunta
19
+ other: Perguntas
20
+ option:
21
+ option: Opção
22
+ other: Opções
23
+ attempt:
24
+ option: Resposta
25
+ other: Respostas
26
+ attributes:
27
+ survey:
28
+ name: Nome
29
+ finished: Acabado
30
+ description: Pequena Descrição
31
+ active: "Ativo?"
32
+ attempts_number: Número máximo de tentativas
33
+ questions_attributes: Perguntas
34
+ question:
35
+ text: Corpo da Pergunta
36
+ options_attributes: Opções
37
+ options:
38
+ text: Corpo da Opção
39
+ correct: Correta
40
+ attempt:
41
+ answers_attributes: Respostas
42
+ survey: Questionário
43
+ winner: Vencedor
44
+ answer:
45
+ attempt: Tentativa
46
+ question: Pergunta
47
+ option: Opção
48
+ correct: Resposta Correta?
@@ -0,0 +1,48 @@
1
+ pt:
2
+ questions: Perguntas
3
+ survey_details: Detalhes do Questionário
4
+ surveys_controller:
5
+ create: O questionário foi criado com sucesso
6
+ update: O questionário foi atualizado com sucesso
7
+ attempts_controller:
8
+ create: "A sua resposta foi efetuada com sucesso."
9
+ surveys: Questionários
10
+ survey_details: Detalhes do Questionário
11
+ questions: Perguntas
12
+ activerecord:
13
+ models:
14
+ survey:
15
+ survey: Questionário
16
+ other: Questionários
17
+ question:
18
+ question: Pergunta
19
+ other: Perguntas
20
+ option:
21
+ option: Opção
22
+ other: Opções
23
+ attempt:
24
+ option: Resposta
25
+ other: Respostas
26
+ attributes:
27
+ survey:
28
+ name: Nome
29
+ finished: Acabado
30
+ description: Pequena Descrição
31
+ active: "Ativo?"
32
+ attempts_number: Número máximo de tentativas
33
+ questions_attributes: Perguntas
34
+ question:
35
+ text: Corpo da Pergunta
36
+ options_attributes: Opções
37
+ options:
38
+ text: Corpo da Opção
39
+ correct: Correta
40
+ attempt:
41
+ answers_attributes: Respostas
42
+ survey: Questionário
43
+ winner: Vencedor
44
+ answer:
45
+ attempt: Tentativa
46
+ question: Pergunta
47
+ option: Opção
48
+ correct: Resposta Correta?
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AskIt
4
+ module ActiveRecord
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def has_surveys
9
+ has_many :survey_attempts, as: :participant, class_name: 'AskIt::Attempt'
10
+
11
+ define_method('for_survey') do |survey|
12
+ survey_attempts.where(survey_id: survey.id)
13
+ end
14
+ end
15
+
16
+ def has_many_surveys
17
+ has_many :surveys, class_name: 'AskIt::Survey'
18
+ end
19
+
20
+ def has_one_survey
21
+ has_one :survey, class_name: 'AskIt::Survey'
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails'
4
+
5
+ module AskIt
6
+ class Engine < Rails::Engine
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AskIt
4
+ class Railtie < ::Rails::Railtie
5
+ generators do
6
+ require 'ask_it/generators/ask_it/install_generator'
7
+ end
8
+
9
+ initializer 'ask_it.load_models' do |app|
10
+ app.config.paths.add 'app/models/ask_it', eager_load: true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AskIt
4
+ VERSION = '0.1.1'
5
+ end
data/lib/ask_it.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require 'app/models/ask_it/survey'
4
+ require_relative '../app/models/ask_it/survey'
5
+ require_relative '../app/models/ask_it/section'
6
+ require_relative '../app/models/ask_it/question_type'
7
+ require_relative '../app/models/ask_it/question'
8
+ require_relative '../app/models/ask_it/predefined_value'
9
+ require_relative '../app/models/ask_it/options_type'
10
+ require_relative '../app/models/ask_it/option'
11
+ require_relative '../app/models/ask_it/attempt'
12
+ require_relative '../app/models/ask_it/answer'
13
+ require_relative 'ask_it/active_record'
14
+ require_relative '../app/controllers/ask_it/surveys_controller'
15
+ require_relative '../app/controllers/ask_it/attempts_controller'
16
+
17
+ module AskIt
18
+ end
19
+
20
+ ActiveRecord::Base.include AskIt::ActiveRecord
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AskIt
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __dir__)
7
+
8
+ def copy_migration
9
+ timestamp_number = Time.now.utc.strftime('%Y%m%d%H%M%S').to_i
10
+
11
+ migration_files = [{ new_file_name: 'create_survey', origin_file_name: 'migration' },
12
+ { new_file_name: 'create_sections', origin_file_name: 'migration_section' },
13
+ { new_file_name: 'update_survey_tables',
14
+ origin_file_name: 'migration_update_survey_tables' },
15
+ { new_file_name: 'add_types_to_questions_and_options',
16
+ origin_file_name: 'migration_add_types_to_questions_and_options' },
17
+ { new_file_name: 'add_head_number_to_options_table',
18
+ origin_file_name: 'migration_add_head_number_to_options_table' },
19
+ { new_file_name: 'create_predefined_values_table',
20
+ origin_file_name: 'migration_create_predefined_values_table' },
21
+ { new_file_name: 'add_mandatory_to_questions_table',
22
+ origin_file_name: 'migration_add_mandatory_to_questions_table' }]
23
+
24
+ migration_files.each do |migration_file|
25
+ next if already_exists?(migration_file[:new_file_name])
26
+
27
+ template "#{migration_file[:origin_file_name]}.rb.tt",
28
+ "db/migrate/#{timestamp_number}_#{migration_file[:new_file_name]}.rb"
29
+ timestamp_number += 1
30
+ end
31
+ end
32
+
33
+ def migration_version
34
+ return unless rails5_and_up?
35
+
36
+ puts(Rails::VERSION)
37
+
38
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
39
+ end
40
+
41
+ def rails5_and_up?
42
+ Rails::VERSION::MAJOR >= 5
43
+ end
44
+
45
+ #######
46
+
47
+ private
48
+
49
+ #######
50
+
51
+ def already_exists?(file_name)
52
+ Dir.glob("#{File.join(destination_root,
53
+ File.join('db', 'migrate'))}/[0-9]*_*.rb").grep(Regexp.new("\\d+_#{file_name}.rb$")).first
54
+ end
55
+ end
56
+ end
57
+ end