gpt4 book ai didi

ruby-on-rails - Rails 单表继承 : determining class programmatically

转载 作者:行者123 更新时间:2023-12-03 15:19:09 25 4
gpt4 key购买 nike

在我的 Rails 应用程序中,我正在实现一个类似于调查的表单,它允许用户填写一组动态变化的问题的答案。目前,我计划支持三种不同“类型”的问题:是/否、评级(1-5 级)和文本。对于这些问题类型中的每一个,我需要相应答案模型的行为略有不同(以适应不同的方法、验证要求等)。我目前正在尝试使用单表继承来实现这些不同的行为,如下所示:

class Question < ActiveRecord::Base
validates_presence_of :question_type

# ...
end

class Answer < ActiveRecord::Base
belongs_to :question

validates_presence_of :answer

# ...
end

class YesNoAnswer < Answer
validates :answer, inclusion: {in: %w(Yes No N/A)}

# ...
end

class RatingAnswer < Answer
validates :answer, numericality: { only_integer: true }, inclusion: {in: 1..5}

def answer
self[:answer].to_i
end

# ...
end

class TextAnswer < Answer
validates :answer, length: { minimum: 2 }

# ...
end

问题在于,对于单表继承,选择的类通常由数据库中每条记录的字段确定。 (默认情况下,该字段为 "type" ,但您可以通过设置 inheritance_column 来更改它)。

但就我而言,答案的类型应始终与其相应问题的类型相匹配,因此需要管理这样一个额外的数据库字段,这样既尴尬又多余。因此,我不想严格依赖数据库中的内容,而是想以编程方式确定给定记录应该使用哪个类。例如。:
class Answer < ActiveRecord::Base
# I want a value on the associated question to determine this record's type.
# Simply defining a type method as shown here doesn't work though.
def type
question.try(:question_type)
end
end

这可能吗?如果是这样,怎么做?

最佳答案

inheritance_column不确定类,它存储 type 的名称列,然后确定用于给定记录的类。

因此,通过更改 inheritance_column值,您可以存储通常存储在 type 中的内容另一列中的列。

这不会帮助您动态确定类名称的存储位置,因为它只是指向另一列,然后由该列中的值确定类。

另见:http://apidock.com/rails/ActiveRecord/ModelSchema/ClassMethods/inheritance_column

Single-Table-Inheritance (STI) 专门用于您希望保留有些相似但根据类型保留不同属性的模型的情况。
换句话说:除非你想在模型中保留不同的东西,否则你不应该使用 STI。

如果您只是想要根据问题类型的不同行为,您可以这样做:
根据问题的类型,您可以通过调用 extend 以您喜欢的行为扩展 Answer 实例。在必要的 Ruby 模块上:

class Question < ActiveRecord::Base
validates_presence_of :kind
has_many :answers
# ... contains an attribute 'kind' to determine the kind of question
end

class Answer < ActiveRecord::Base
belongs_to :question
validates_presence_of :answer

# when a new instance of Answer is created, it automatically extends itself's
# behavior from the given Ruby Module, which is conveniently stored as a Rails Concern
def initialize
case question.kind
when 'yes_no'
self.class.send(:extend, YesNo)
when 'rating'
self.class.send(:extend, Rating)
when 'text'
self.class.send(:extend, Text)
else
# ...
end
end

end

在你的 ./app/models/concerns您有不同的文件,其中包含定义要添加到 Answer 类的行为的模块,具体取决于问题的类型:
 # file concerns/yes_no.rb
module YesNo
validates :answer, inclusion: {in: %w(Yes No N/A)}
end

# file concerns/rating.rb
module Rating
validates :answer, numericality: { only_integer: true }, inclusion: {in: 1..5}

def answer
self[:answer].to_i
end
# ...
end

# file concerns/text.rb
module Text
validates :answer, length: { minimum: 2 }
end

为了进一步美化代码,您可以将这些答案行为放入子目录'./concerns/answer_behavior/',并将它们包装在模块'AnswerBehavior'中。

关于ruby-on-rails - Rails 单表继承 : determining class programmatically,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25409149/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com