我有一个应用程序,我打算向用户发布问题以帮助确定sales_opportunity的资格。我不希望用户能够添加他们自己的问题,而是我计划将他们硬编码到应用程序中并使用他们提供的答案来驱动状态机,通过问题树将其发送到正确的时尚。
例如,我可能会问"潜在客户是否有预算"这将有一个是/否答案。如果他们回答"是",我会将他们发送给一个问题"预算多少?"如果他们回答"否"然后他们会被发送到一个问题"是否有分配预算的流程?"我需要保存他们提供的答案,并有机会回到问题树(例如,用户可能最初表明潜在客户没有预算,但一旦预算可用,他们需要更改答案并发送确定可用预算多少的路径。
我已经定义了我想问的所有问题,他们将根据他们的答案解决的路线,我知道我想对输入做些什么,但我无法弄清楚如何在Rails中对此进行建模。我有大约50个问题和8个不同的分支。一些答案要求用户将其他模型作为答案的一部分进行链接(例如,我可能会问"谁签署预算"用户必须从DB中选择联系人/添加新联系人)
我应该将一系列列添加到"答案"表,并将问题作为单个列添加到Question表中,然后使用gem State Machine确定向用户显示的内容?或者我会尝试为每个问题创建一个Object更好吗?
这让我觉得应该是相对简单易解的事情,而且我自我混淆/可能会使事情复杂化。任何人都可以帮我找到解决方案吗?
答案 0 :(得分:2)
对此类调查问卷的数据建模比最初想的要复杂得多。之前我做过一次,并使用问题模型,答案模型,SelectedAnswer模型和PossibleAnswer模型对其进行建模。后两种模型可以满足用户可以选择多个答案的问题。
class Question
QUESTION_TYPES = %w(TextField Checkbox Radio Textarea)
has_many :answers
has_many :possible_answers, dependent: :destroy
accepts_nested_attributes_for :possible_answers
validates :title, presence: true
validates :field_type, presence: true, :inclusion => { :in => QUESTION_TYPES }
end
class Answer
belongs_to :question
has_many :selected_answers, inverse_of: :answer, dependent: :destroy
has_many :possible_answers, through: :selected_answers
accepts_nested_attributes_for :selected_answers
validates :question, presence: true
end
class PossibleAnswer
belongs_to :question
has_many :answers, through: :selected_answers
has_many :selected_answers
validates :question, presence: true
validates :text, presence: true
end
class SelectedAnswer
belongs_to :answer
belongs_to :possible_answer
validates :answer, :possible_answer, presence: true
end
问题还有一个field_type属性,您可以在其中设置问题的类型 - 文本字段,复选框,广播或文本框。此属性将决定您如何显示输入答案的视图,具体取决于它是一个简单的是/否问题,还是允许自由文本输入的问题或允许用户选择多个答案的问题。
问题还有一个位置属性,用于指示它们的显示顺序。在我的例子中,我只有一个分支。对于多个分支,您必须使用一些逻辑来确定要显示的下一个问题,具体取决于答案。
还有其他方法可以做到这一点,但这对我有用。它允许使用不同类型的问题和答案,因为我们也使用图像来获得一些可能的答案。
答案 1 :(得分:1)
所以模型会是这样的:
class Question < ActiveRecord::Base
has_many :question_links
has_many :next_question, through: :question_links
has_many :previous_question, through: :question_links
class QuestionLink < ActiveRecord::Base
belongs_to :previous_question, class_name: "Question"
belongs_to :next_question, class_name: "Question"
validate_presence_of :rating
您可以在表单(或硬编码)中通过question_link(嵌套表单)定义一个带有前一个问题(嵌套表单)链接的问题。在这个问题中,链接会得到一个答案的评级。
一个问题将有两个next_questions(一个具有正面评级,一个具有负面或更低评级)。至少有一个previous_question。
当问题没有next_question
时,表示调查已完成。您可以将所有评分相加并获得分数。
答案 2 :(得分:1)
让我们从数据结构的角度描述你的问题 - 因为你有一个链接的问题,它可以被描述为图形。确切地说,考虑&#34;是&#34; /&#34;否&#34;回答和定义的路由响应,这个图是一个二叉树。图片更清晰:
页面中的http://www.sfs.uni-tuebingen.de/~vhenrich/ss12/java/homework/hw7/decisionTrees.html因此,您需要使用ActiveRecord将树结构保留在数据库中。这里有一个有趣的特征,问题之间的关系也有一些信息(答案值 - &#34;是&#34;或&#34;否&#34;)。这些知识应该保存在数据库的某个地方。我建议引入新的模型答案,以保持答案文本和外键到父母/子女的问题。
class Question < ActiveRecord::Base
has_one :parent_answer, class_name: 'Answer' # route to parental question
has_one :parent, through: :parent_answer, class_name: 'Question'
has_many :answers # we suppose to have maximum 2 answers per question
has_many :children, through: :answers, class_name: 'Question'
end
class Answer < ActiveRecord::Base
# has attribute text: "Yes, No"
enum text: [:yes, :no]
belongs_to :parent_question, class_name: 'Question'
belongs_to :child_question, class_name: 'Question'
end
# Let's create some questions
root = Question.create text: 'Is the picture clear?'
yes_child = Question.create text: 'Is there sound?'
no_child = Question.create text: 'Is the screen blank?'
# Let's build the tree
yes_answer = Answer.create text: :yes, parent_question: root, child_question: yes_child
no_answer = Answer.create text: :no, parent_question: root, child_question: no_child
这里的另一个问题是如何坚持用户的答案?第一个想法只是创建一个关系user has many answers through users_answers
# model UserAnswer
class UserAnswer < ActiveRecord::Base
belongs_to :answer
belongs_to :user
end
# model User
class User < ActiveRecord::Base
has_many :answers, throught: :users_answers
end
我建议为answers
添加一个验证,即所有记录都在问题/答案树的同一分支中。
改进的想法:
如果你有更多的答案,硬编码的答案将来可能是一个痛点。这可以通过一个模型AnswerText和类似answer belongs_to answer_text
的关系来解决。