ask_it 0.1.1

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 (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