active_record_survey 0.1.25 → 0.1.26

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e31b5194f981037636d99848bcf20cca47ff08d
4
- data.tar.gz: 826afd06292c6edb0c7c66c125d09f719960b656
3
+ metadata.gz: d9764b3647e3386e4d60b9753940515b78881b88
4
+ data.tar.gz: 899bf6944ac349d04d2aca7b20254837a2a93bd2
5
5
  SHA512:
6
- metadata.gz: d549e57755d6ccbfdd39d65a5250076de67bf434412f8ecbdce4009bfceb275ef935acd4f49bec8025269fc35127f08e9810a4b574889bd7c3cab7ccd2154f0b
7
- data.tar.gz: bda3002f375e5dccff9be201873e2ca52fa3a482271ea4f730035f20c3e46ed01e8bbffc7706454f72179589e8e8b7d34feaf8717f5451823916d8755f9ec783
6
+ metadata.gz: 765649c5e0aa37a8b02fac5ef171852d45f4a5145ea414f1486a4fa73f3b95834bee2f68192145681bd3975cba6e1b580eb09d959e139a9c59ea95f2b1d46402
7
+ data.tar.gz: b23afb8a510de738c55fd823fdc03d498471b4e4c65e4b3eca5a9ff7a919a5359e066b8e0ea782b4adeddbb28083f33c8310d034f24e6d73c4dd9377752e9a26
data/README.md CHANGED
@@ -12,6 +12,11 @@ The goal is to give a simple interface for creating surveys and validating the a
12
12
  Release Notes
13
13
  ============
14
14
 
15
+ **0.1.26**
16
+ - Major refactor of answer#build_link and answer#remove_link
17
+ - `ActiveRecordSurvey::Node` now has a direct reference to its survey. Don't forget to run the install task Update_0_1_26_ActiveRecordSurvey
18
+ - survey#build_question removed, no longer needed, just use survey.questions.build
19
+
15
20
  **0.1.24**
16
21
  - Refactored class `ActiveRecordSurvey::Node::Answer::Chain` to module `ActiveRecordSurvey::Node::Answer::Chained` - this functionality makes way more sense implemented as a module.
17
22
 
@@ -72,38 +77,34 @@ The usage below with `:text => ""` will not actually work unless you implement `
72
77
  ### Build a basic survey
73
78
  ```ruby
74
79
 
75
- # New method for building surveys
80
+ # Building surveys
76
81
  @survey = ActiveRecordSurvey::Survey.new()
77
82
 
78
- @q1 = ActiveRecordSurvey::Node::Question.new(:text => "Question #1")
79
- @survey.build_question(@q1)
83
+ @q1 = @survey.questions.build(:type => "ActiveRecordSurvey::Node::Question", :text => "Question #1", :survey => @survey)
80
84
  @q1_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 Answer #1")
81
85
  @q1_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 Answer #2")
82
86
  @q1_a3 = ActiveRecordSurvey::Node::Answer.new(:text => "Q1 Answer #3")
83
- @q1.build_answer(@q1_a1, @survey)
84
- @q1.build_answer(@q1_a2, @survey)
85
- @q1.build_answer(@q1_a3, @survey)
87
+ @q1.build_answer(@q1_a1)
88
+ @q1.build_answer(@q1_a2)
89
+ @q1.build_answer(@q1_a3)
86
90
 
87
- @q2 = ActiveRecordSurvey::Node::Question.new(:text => "Question #2")
88
- @survey.build_question(@q2)
91
+ @q2 = @survey.questions.build(:type => "ActiveRecordSurvey::Node::Question", :text => "Question #2", :survey => @survey)
89
92
  @q2_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q2 Answer #1")
90
93
  @q2_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q2 Answer #2")
91
- @q2.build_answer(@q2_a1, @survey)
92
- @q2.build_answer(@q2_a2, @survey)
94
+ @q2.build_answer(@q2_a1)
95
+ @q2.build_answer(@q2_a2)
93
96
 
94
- @q3 = ActiveRecordSurvey::Node::Question.new(:text => "Question #3")
95
- @survey.build_question(@q3)
97
+ @q3 = @survey.questions.build(:type => "ActiveRecordSurvey::Node::Question", :text => "Question #3", :survey => @survey)
96
98
  @q3_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q3 Answer #1")
97
99
  @q3_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q3 Answer #2")
98
- @q3.build_answer(@q3_a1, @survey)
99
- @q3.build_answer(@q3_a2, @survey)
100
+ @q3.build_answer(@q3_a1)
101
+ @q3.build_answer(@q3_a2)
100
102
 
101
- @q4 = ActiveRecordSurvey::Node::Question.new(:text => "Question #4")
102
- @survey.build_question(@q4)
103
+ @q4 = @survey.questions.build(:type => "ActiveRecordSurvey::Node::Question", :text => "Question #4", :survey => @survey)
103
104
  @q4_a1 = ActiveRecordSurvey::Node::Answer.new(:text => "Q4 Answer #1")
104
105
  @q4_a2 = ActiveRecordSurvey::Node::Answer.new(:text => "Q4 Answer #2")
105
- @q4.build_answer(@q4_a1, @survey)
106
- @q4.build_answer(@q4_a2, @survey)
106
+ @q4.build_answer(@q4_a1)
107
+ @q4.build_answer(@q4_a2)
107
108
 
108
109
  # Link up Q1
109
110
  @q1_a1.build_link(@q2)
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "activerecord", [">= 3.0", "< 5.0"]
22
- spec.add_dependency "awesome_nested_set", [">= 2.0"]
22
+ spec.add_dependency "awesome_nested_set", [">= 3.0"]
23
23
  if RUBY_PLATFORM == 'java'
24
24
  spec.add_development_dependency "jdbc-sqlite3", "> 0"
25
25
  spec.add_development_dependency "activerecord-jdbcsqlite3-adapter", "> 0"
@@ -12,7 +12,7 @@ module ActiveRecordSurvey
12
12
  instance_node.errors[:base] << "INVALID_PATH"
13
13
  end
14
14
 
15
- parent_nodes = self.node.node_maps.collect { |j| j.parent }
15
+ parent_nodes = self.node.survey.node_maps.select { |i| i.node == self.node }.collect { |j| j.parent }
16
16
 
17
17
  # Two instance_nodes on the same node for this instance
18
18
  if self.instance.instance_nodes.select { |i|
@@ -21,7 +21,7 @@ module ActiveRecordSurvey
21
21
  }.select { |i|
22
22
  # And the two arrays
23
23
  # Two votes share a parent (this means a question has two answers for this instance)
24
- (i.node.node_maps.collect { |j| j.parent } & parent_nodes).length > 0
24
+ (i.node.survey.node_maps.select { |j| i.node == j.node }.collect { |j| j.parent } & parent_nodes).length > 0
25
25
  }.length > 1
26
26
  instance_node.errors[:base] << "DUPLICATE_PATH"
27
27
  end
@@ -2,19 +2,24 @@ module ActiveRecordSurvey
2
2
  class Answer
3
3
  module Chained
4
4
  # Chain nodes are different - they must find the final answer node added and add to it
5
- def build_answer(question_node, survey)
5
+ def build_answer(question_node)
6
+ self.survey = question_node.survey
7
+
8
+ question_node_maps = self.survey.node_maps.select { |i| i.node == question_node && !i.marked_for_destruction? }
9
+
6
10
  # No node_maps exist yet from this question
7
- if question_node.node_maps.length === 0
11
+ if question_node_maps.length === 0
8
12
  # Build our first node-map
9
- question_node.node_maps.build(:node => question_node, :survey => survey)
13
+ question_node_maps << self.survey.node_maps.build(:node => question_node, :survey => self.survey)
10
14
  end
11
15
 
12
- last_in_chain = question_node.answers.last || question_node
16
+ last_answer_in_chain = (question_node.answers.last || question_node)
13
17
 
14
18
  # Each instance of this question needs the answer hung from it
15
- last_in_chain.node_maps.each { |node_map|
16
- answer_node_map = self.node_maps.build(:node => self, :survey => survey)
17
- node_map.children << answer_node_map
19
+ self.survey.node_maps.select { |i|
20
+ i.node == last_answer_in_chain
21
+ }.each { |node_map|
22
+ node_map.children << self.survey.node_maps.build(:node => self, :survey => self.survey)
18
23
  }
19
24
 
20
25
  true
@@ -4,14 +4,18 @@ module ActiveRecordSurvey
4
4
  # Validate this node against an instance
5
5
  def validate_node(instance)
6
6
  # Ensure each parent node to this node (the goal here is to hit a question node) is valid
7
- !self.node_maps.collect { |node_map|
7
+ !self.survey.node_maps.select { |i|
8
+ i.node == self
9
+ }.collect { |node_map|
8
10
  node_map.parent.node.validate_node(instance)
9
11
  }.include?(false)
10
12
  end
11
13
 
12
14
  # Returns the question that preceeds this answer
13
15
  def question
14
- self.node_maps.collect { |node_map|
16
+ self.survey.node_maps.select { |i|
17
+ i.node == self
18
+ }.collect { |node_map|
15
19
  if node_map.parent && node_map.parent.node
16
20
  # Question is not the next parent - recurse!
17
21
  if node_map.parent.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer)
@@ -28,9 +32,11 @@ module ActiveRecordSurvey
28
32
 
29
33
  # Returns the question that follows this answer
30
34
  def next_question
31
- self.node_maps.each { |answer_node_map|
35
+ self.survey.node_maps.select { |i|
36
+ i.node == self && !i.marked_for_destruction?
37
+ }.each { |answer_node_map|
32
38
  answer_node_map.children.each { |child|
33
- if !child.node.nil?
39
+ if !child.node.nil? && !child.marked_for_destruction?
34
40
  if child.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
35
41
  return child.node
36
42
  elsif child.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer)
@@ -44,40 +50,32 @@ module ActiveRecordSurvey
44
50
  return nil
45
51
  end
46
52
 
47
- attr_accessor :ancestor_marked_for_destruction
48
- protected :ancestor_marked_for_destruction
49
-
50
- before_save do |node|
51
- # ------------------------ WARNING ------------------------
52
- # This code is to support #remove_link which uses mark_for_destruction
53
- # This code is necessary to clean everything up.
54
- # Calling save on this answer won't automatically go to its next_question -> node_maps and clean everything up
55
- (@ancestor_marked_for_destruction || []).each { |i|
56
- i.destroy
57
- }
58
- end
59
-
60
53
  # Removes the link
61
54
  def remove_link
62
- @ancestor_marked_for_destruction ||= []
63
-
64
55
  # not linked to a question - nothing to remove!
65
56
  return true if (question = self.next_question).nil?
66
57
 
67
- self.node_maps.each_with_index { |answer_nm, answer_nm_i|
68
- answer_nm.children = answer_nm.children.select { |question_nm|
69
- # This node_map links to the question
70
- if question_nm.node === question
71
- question_nm.parent = nil
72
- if answer_nm_i > 0
73
- question_nm.mark_for_destruction
74
- @ancestor_marked_for_destruction << question_nm
75
- end
76
- false
58
+ count = 0
59
+ to_remove = []
60
+ self.survey.node_maps.each { |node_map|
61
+ if node_map.node == question
62
+ if count > 0
63
+ to_remove.concat(node_map.self_and_descendants)
77
64
  else
78
- true
65
+ node_map.parent = nil
79
66
  end
80
- }
67
+ count = count + 1
68
+ end
69
+
70
+ if node_map.node == self
71
+ node_map.children = []
72
+ end
73
+ }
74
+ self.survey.node_maps.each { |node_map|
75
+ if to_remove.include?(node_map)
76
+ node_map.parent = nil
77
+ node_map.mark_for_destruction
78
+ end
81
79
  }
82
80
  end
83
81
 
@@ -89,48 +87,47 @@ module ActiveRecordSurvey
89
87
  raise ArgumentError.new "to_node must inherit from ::ActiveRecordSurvey::Node::Question"
90
88
  end
91
89
 
90
+ if self.question.nil?
91
+ raise ArgumentError.new "A question is required before calling #build_link"
92
+ end
93
+
94
+ if self.survey.nil?
95
+ raise ArgumentError.new "A survey is required before calling #build_link"
96
+ end
97
+
98
+ from_node_maps = self.survey.node_maps.select { |i| i.node == self && !i.marked_for_destruction? }
99
+
92
100
  # Answer has already got a question - throw error
93
- if self.node_maps.select { |i|
101
+ if from_node_maps.select { |i|
94
102
  i.children.length === 0
95
103
  }.length === 0
96
104
  raise RuntimeError.new "This answer has already been linked"
97
105
  end
98
106
 
99
- # Attempt to find an unused to_node node_map
100
- if !(to_without_parent = to_node.node_maps.select { |i| i.parent.nil? }.first)
101
- # no unused path exists
102
- # we need to recursively clone the existing path
103
-
104
- to_node_map = to_node.node_maps.first || to_node.node_maps.build(:node => to_node, :survey => self.node_maps.first.survey)
107
+ # Because we need something to clone - filter this further below
108
+ to_node_maps = self.survey.node_maps.select { |i| i.node == to_node && !i.marked_for_destruction? }
105
109
 
106
- # Add it to all the from_node_maps
107
- self.node_maps.each { |from_node_map|
108
- from_node_map.children << to_node_map.recursive_clone
109
- }
110
- else
111
- # Find the node map from this node that has no children
112
- from_with_no_children = self.node_maps.select { |i|
113
- i.children.length == 0
114
- }
110
+ if to_node_maps.first.nil?
111
+ to_node_maps << self.survey.node_maps.build(:survey => self.survey, :node => to_node)
112
+ end
115
113
 
116
- if from_with_no_children.length > 1
117
- to_node_map = to_node.node_maps.first || to_node.node_maps.build(:node => to_node, :survey => self.node_maps.first.survey)
118
- end
114
+ # Ensure we can through each possible path of getting to this answer
115
+ to_node_map = to_node_maps.first
116
+ to_node_map.survey = self.survey # required due to voodoo - we want to use the same survey with the same object_id
119
117
 
120
- from_with_no_children.each_with_index { |from_with_no_children, index|
121
- # Use up the node that hasn't been used yet
122
- if index === 0
123
- from_with_no_children.children << to_without_parent
124
- # We need to clone destinations for each of the subsequent
125
- else
126
- from_with_no_children.children << to_node_map.recursive_clone
127
- end
128
- }
129
-
130
- # TODO - check to make sure there is no path to itself
118
+ # We only want node maps that aren't linked somewhere
119
+ to_node_maps = to_node_maps.select { |i| i.parent.nil? }
120
+ while to_node_maps.length < from_node_maps.length do
121
+ to_node_maps.push(to_node_map.recursive_clone)
131
122
  end
132
123
 
133
- self.node_maps.each { |node_map|
124
+ # Link unused node_maps to the new parents
125
+ from_node_maps.each_with_index { |from_node_map, index|
126
+ from_node_map.children << to_node_maps[index]
127
+ }
128
+
129
+ # Ensure no infinite loops were created
130
+ from_node_maps.each { |node_map|
134
131
  # There is a path from Q -> A that is a loop
135
132
  if node_map.has_infinite_loop?
136
133
  raise RuntimeError.new "Infinite loop detected"
@@ -138,24 +135,27 @@ module ActiveRecordSurvey
138
135
  }
139
136
  end
140
137
 
141
- # By default - answers build off the original question node
142
- #
143
- # This allows us to easily override the answer building behaviour for different answer types
144
- #
145
- def build_answer(question_node, survey)
146
- # No node_maps exist yet from this question
147
- if question_node.node_maps.length === 0
148
- # Build our first node-map
149
- question_node.node_maps.build(:node => question_node, :survey => survey)
150
- end
138
+ private
139
+ # By default - answers build off the original question node
140
+ #
141
+ # This allows us to easily override the answer building behaviour for different answer types
142
+ def build_answer(question_node)
143
+ self.survey = question_node.survey
151
144
 
152
- # Each instance of this question needs the answer hung from it
153
- question_node.node_maps.each { |question_node_map|
154
- answer_node_map = self.node_maps.build(:node => self, :survey => survey)
155
- question_node_map.children << answer_node_map
156
- }
145
+ question_node_maps = self.survey.node_maps.select { |i| i.node == question_node && !i.marked_for_destruction? }
157
146
 
158
- true
159
- end
147
+ # No node_maps exist yet from this question
148
+ if question_node_maps.length === 0
149
+ # Build our first node-map
150
+ question_node_maps << self.survey.node_maps.build(:node => question_node, :survey => self.survey)
151
+ end
152
+
153
+ # Each instance of this question needs the answer hung from it
154
+ question_node_maps.each { |question_node_map|
155
+ question_node_map.children << self.survey.node_maps.build(:node => self, :survey => self.survey)
156
+ }
157
+
158
+ true
159
+ end
160
160
  end
161
161
  end
@@ -7,28 +7,15 @@ module ActiveRecordSurvey
7
7
  }.include?(false)
8
8
  end
9
9
 
10
- # Returns the survey to the question
11
- def survey
12
- if node_map = self.node_maps.first
13
- node_map.survey
14
- end
15
- end
16
-
17
10
  # Build an answer off this node
18
- def build_answer(answer_node, survey = nil)
19
- survey = survey || self.node_maps.select { |i|
20
- !i.survey.nil?
21
- }.collect { |i|
22
- i.survey
23
- }.first
24
-
25
- # A survey must either be passed or already present in node_maps
26
- if survey.nil?
11
+ def build_answer(answer_node)
12
+ # A survey must either be passed or already present in self.node_maps
13
+ if self.survey.nil?
27
14
  raise ArgumentError.new "A survey must be passed if Question is not yet added to a survey"
28
15
  end
29
16
 
30
- # Answers actually define how they're built off the parent node... yep
31
- answer_node.build_answer(self, survey)
17
+ # Answers actually define how they're built off the parent node
18
+ answer_node.send(:build_answer, self)
32
19
  end
33
20
  end
34
21
  end
@@ -1,13 +1,16 @@
1
1
  module ActiveRecordSurvey
2
2
  class Node < ::ActiveRecord::Base
3
3
  self.table_name = "active_record_survey_nodes"
4
+ belongs_to :survey, :class_name => "ActiveRecordSurvey::Survey", :foreign_key => :active_record_survey_id
4
5
  has_many :node_maps, :class_name => "ActiveRecordSurvey::NodeMap", :foreign_key => :active_record_survey_node_id, autosave: true
5
6
  has_many :node_validations, :class_name => "ActiveRecordSurvey::NodeValidation", :foreign_key => :active_record_survey_node_id, autosave: true
6
7
  has_many :instance_nodes, :class_name => "ActiveRecordSurvey::InstanceNode", :foreign_key => :active_record_survey_node_id
7
8
 
8
9
  # All the answer nodes that follow from this node
9
10
  def answers
10
- self.node_maps.collect { |i|
11
+ self.survey.node_maps.select { |i|
12
+ i.node == self
13
+ }.collect { |i|
11
14
  # Get all the children from this node
12
15
  i.children
13
16
  }.flatten.collect { |i|
@@ -17,6 +20,7 @@ module ActiveRecordSurvey
17
20
  # Only the nodes that are answers
18
21
  i.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer)
19
22
  }.uniq.collect { |i|
23
+ i.survey = self.survey # ensure that the survey being referenced by the answers is the original survey - needed for keeping consistent node_maps between build_link and remove_link
20
24
  [i] + i.answers
21
25
  }.flatten.uniq
22
26
  end
@@ -48,7 +52,7 @@ module ActiveRecordSurvey
48
52
 
49
53
  # Default behaviour is to recurse up the chain (goal is to hit a question node)
50
54
  def validate_parent_instance_node(instance_node, child_node)
51
- !self.node_maps.collect { |node_map|
55
+ !self.survey.node_maps.select { |i| i.node == self}.collect { |node_map|
52
56
  if node_map.parent
53
57
  node_map.parent.node.validate_parent_instance_node(instance_node, self)
54
58
  # Hit top node
@@ -72,7 +76,7 @@ module ActiveRecordSurvey
72
76
  # More complex....
73
77
  # Recureses to the parent node to check
74
78
  # This is to validate Node::Question since they don't have instance_nodes directly to validate them
75
- parent_validations_passed = !self.node_maps.collect { |node_map|
79
+ parent_validations_passed = !self.survey.node_maps.select { |i| i.node == self}.collect { |node_map|
76
80
  if node_map.parent
77
81
  node_map.parent.node.validate_parent_instance_node(instance_node, self)
78
82
  # Hit top node
@@ -96,7 +100,7 @@ module ActiveRecordSurvey
96
100
 
97
101
  # Start at each node_map of this node
98
102
  # Find the parent node ma
99
- paths = self.node_maps.collect { |node_map|
103
+ paths = self.survey.node_maps.select { |i| i.node == self }.collect { |node_map|
100
104
  # There is another level to traverse
101
105
  if node_map.parent
102
106
  node_map.parent.node.instance_node_path_to_root?(instance_node)
@@ -7,33 +7,34 @@ module ActiveRecordSurvey
7
7
 
8
8
  validates_presence_of :survey
9
9
 
10
- after_initialize do |i|
11
- # Required for all functions to work without creating
12
- i.survey.node_maps << self if i.new_record? && i.survey
13
- end
14
-
15
10
  # Recursively creates a copy of this entire node_map
16
11
  def recursive_clone
17
- node_map = self.node.node_maps.build(:survey => self.survey, :node => self.node)
12
+ node_map = self.survey.node_maps.build(:survey => self.survey, :node => self.node)
18
13
  self.children.each { |child_node|
14
+ child_node.survey = self.survey # required due to voodoo - we want to use the same survey with the same object_id
19
15
  node_map.children << child_node.recursive_clone
20
16
  }
21
17
  node_map
22
18
  end
23
19
 
24
- def as_map(node_maps = nil)
25
- children = (node_maps.nil?)? self.children : node_maps.select { |i|
26
- i.parent == self
20
+ def as_map(options)
21
+ node_maps = options[:node_maps]
22
+
23
+ c = (node_maps.nil?)? self.children : node_maps.select { |i|
24
+ i.parent == self && !i.marked_for_destruction?
27
25
  }
28
26
 
29
- {
30
- :id => self.id,
31
- :node_id => self.node.id,
27
+ result = {}
28
+ result.merge!({ :id => self.id, :node_id => self.node.id }) if !options[:no_ids]
29
+ result.merge!({
32
30
  :type => self.node.class.to_s,
33
- :children => children.collect { |i|
34
- i.as_map(node_maps)
31
+ :children => c.collect { |i|
32
+ i.as_map(options)
35
33
  }
36
- }
34
+ })
35
+
36
+
37
+ result
37
38
  end
38
39
 
39
40
  # Gets all the child nodes until one is not an ancestor of klass
@@ -57,5 +58,14 @@ module ActiveRecordSurvey
57
58
  }
58
59
  false
59
60
  end
61
+
62
+ def mark_self_and_children_for_destruction
63
+ removed = [self]
64
+ self.mark_for_destruction
65
+ self.children.each { |i|
66
+ removed.concat(i.mark_self_and_children_for_destruction)
67
+ }
68
+ removed
69
+ end
60
70
  end
61
71
  end
@@ -1,44 +1,21 @@
1
1
  module ActiveRecordSurvey
2
2
  class Survey < ::ActiveRecord::Base
3
3
  self.table_name = "active_record_surveys"
4
- has_many :node_maps, :class_name => "ActiveRecordSurvey::NodeMap", :foreign_key => :active_record_survey_id
4
+ has_many :node_maps, :class_name => "ActiveRecordSurvey::NodeMap", :foreign_key => :active_record_survey_id, autosave: true
5
5
  has_many :nodes, -> { distinct }, :through => :node_maps
6
-
7
- def questions
8
- self.node_maps.includes(:node).select { |i|
9
- i.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
10
- }.collect { |i|
11
- i.node
12
- }.uniq
13
- end
6
+ has_many :questions, :class_name => "ActiveRecordSurvey::Node::Question", :foreign_key => :active_record_survey_id
14
7
 
15
8
  def root_node
16
9
  self.node_maps.includes(:node).select { |i| i.depth === 0 }.first
17
10
  end
18
11
 
19
- def as_map
20
- list = self.node_maps
12
+ def as_map(*args)
13
+ options = args.extract_options!
14
+ options[:node_maps] ||= self.node_maps
21
15
 
22
- list.select { |i| !i.parent }.collect { |i|
23
- i.as_map(list)
16
+ self.node_maps.select { |i| !i.parent && !i.marked_for_destruction? }.collect { |i|
17
+ i.as_map(options)
24
18
  }
25
19
  end
26
-
27
- # Build a question for this survey
28
- def build_question(question)
29
- # build_question only accepts a node that inherits from Question
30
- if !question.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
31
- raise ArgumentError.new "Question must inherit from ::ActiveRecordSurvey::Node::Question"
32
- end
33
-
34
- # Already added - shouldn't add twice
35
- if question.node_maps.select { |node_map|
36
- node_map.survey === self
37
- }.length > 0
38
- raise RuntimeError.new "This question has already been added to the survey"
39
- end
40
-
41
- question.node_maps.build(:node => question, :survey => self)
42
- end
43
20
  end
44
21
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordSurvey
2
- VERSION = "0.1.25"
2
+ VERSION = "0.1.26"
3
3
  end
@@ -25,6 +25,8 @@ class AddActiveRecordSurvey < ActiveRecord::Migration
25
25
  t.integer :parent_id, :null => true, :index => true
26
26
  t.integer :lft, :null => false, :index => true
27
27
  t.integer :rgt, :null => false, :index => true
28
+
29
+ # optional fields
28
30
  t.integer :depth, :null => false, :default => 0
29
31
  t.integer :children_count, :null => false, :default => 0
30
32
 
@@ -0,0 +1,9 @@
1
+ class Update_0_1_26_ActiveRecordSurvey < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :active_record_survey_nodes, :active_record_survey_id, :integer
4
+ end
5
+
6
+ def self.down
7
+ remove_column :active_record_survey_nodes, :active_record_survey_id
8
+ end
9
+ end
@@ -3,21 +3,20 @@ require 'spec_helper'
3
3
  describe ActiveRecordSurvey::Node::Answer::Boolean, :boolean_spec => true do
4
4
  describe 'a boolean survey is' do
5
5
  before(:all) do
6
- @survey = ActiveRecordSurvey::Survey.new
7
-
8
- @q1 = ActiveRecordSurvey::Node::Question.new()
9
- @q1_a1 = ActiveRecordSurvey::Node::Answer::Boolean.new()
10
- @q1_a2 = ActiveRecordSurvey::Node::Answer::Boolean.new()
11
- @q1_a3 = ActiveRecordSurvey::Node::Answer::Boolean.new()
12
- @q1_a4 = ActiveRecordSurvey::Node::Answer::Boolean.new()
13
- @q1_a5 = ActiveRecordSurvey::Node::Answer::Boolean.new()
14
-
15
- @survey.build_question(@q1)
16
- @q1.build_answer(@q1_a1, @survey)
17
- @q1.build_answer(@q1_a2, @survey)
18
- @q1.build_answer(@q1_a3, @survey)
19
- @q1.build_answer(@q1_a4, @survey)
20
- @q1.build_answer(@q1_a5, @survey)
6
+ @survey = ActiveRecordSurvey::Survey.new()
7
+
8
+ @q1 = ActiveRecordSurvey::Node::Question.new(:text => "Q1", :survey => @survey)
9
+ @q1_a1 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "A")
10
+ @q1_a2 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "B")
11
+ @q1_a3 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "C")
12
+ @q1_a4 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "D")
13
+ @q1_a5 = ActiveRecordSurvey::Node::Answer::Boolean.new(:text => "E")
14
+
15
+ @q1.build_answer(@q1_a1)
16
+ @q1.build_answer(@q1_a2)
17
+ @q1.build_answer(@q1_a3)
18
+ @q1.build_answer(@q1_a4)
19
+ @q1.build_answer(@q1_a5)
21
20
 
22
21
  @survey.save
23
22
  end
@@ -5,19 +5,18 @@ describe ActiveRecordSurvey::Node::Answer::Rank, :rank_spec => true do
5
5
  before(:all) do
6
6
  @survey = ActiveRecordSurvey::Survey.new
7
7
 
8
- @q1 = ActiveRecordSurvey::Node::Question.new()
8
+ @q1 = ActiveRecordSurvey::Node::Question.new(:survey => @survey)
9
9
  @q1_a1 = ActiveRecordSurvey::Node::Answer::Rank.new()
10
10
  @q1_a2 = ActiveRecordSurvey::Node::Answer::Rank.new()
11
11
  @q1_a3 = ActiveRecordSurvey::Node::Answer::Rank.new()
12
12
  @q1_a4 = ActiveRecordSurvey::Node::Answer::Rank.new()
13
13
  @q1_a5 = ActiveRecordSurvey::Node::Answer::Rank.new()
14
14
 
15
- @survey.build_question(@q1)
16
- @q1.build_answer(@q1_a1, @survey)
17
- @q1.build_answer(@q1_a2, @survey)
18
- @q1.build_answer(@q1_a3, @survey)
19
- @q1.build_answer(@q1_a4, @survey)
20
- @q1.build_answer(@q1_a5, @survey)
15
+ @q1.build_answer(@q1_a1)
16
+ @q1.build_answer(@q1_a2)
17
+ @q1.build_answer(@q1_a3)
18
+ @q1.build_answer(@q1_a4)
19
+ @q1.build_answer(@q1_a5)
21
20
 
22
21
  @survey.save
23
22
  end