英文:
Rails - How to Model Dynamic Form Fields?
问题
我有一个请求模型。请求有一个分类。我想要建立的是将一堆表单字段存储在数据库中。它们的类型、名称等。不同的分类将有不同的表单字段供用户在请求表单上填写。所以最终,用户创建一个具有分类 C 的新请求,然后他们会看到一个具有适合分类 C 的适当字段的表单。
我希望将这些值存储在请求的表中。我的问题是如何对其建模?
请求有一个分类。
分类有多个请求。
我不确定如何处理动态表单字段。我希望能够创建这些字段并将它们附加到分类。因此,如果需要名字和姓氏这些字段,我不必为每个分类都创建它们。只需创建它们一次并通过一个关联表将它们与分类关联起来。
寻求如何进行建模并能够轻松地从请求中引用它们的建议。
谢谢!感谢任何信息或想法。
英文:
I have a request model. A request has one classification. What I want to set up is to store a bunch of form fields in the DB. Their types, names etc. Different classifications will have different form fields for the user to fill out on a request form. So ultimately User creates new request with classification C, and they are presented with a form with the appropriate fields for classification C.
I would like the values stored in a table with the request. My question is how should this be modeled?
Request has one classification.
Classification has_many requests.
I'm just not sure what to do with the dynamic form fields. I would like to be able to create the fields and attach them to the classification. So if first name, last name are fields needed I wouldn't have to create them for every classification. Just create them once and set associate them with a classification through a join table.
Looking for advice on how to model this out and be able to easily reference them from a request.
Thanks! Any info or thoughts are appreciated.
答案1
得分: 1
我建议你首先尽可能按照关系模型来建模。
# 注意可能与控制器中的核心方法冲突
class Request < ApplicationRecord
has_many :classifications
end
class Classification < ApplicationRecord
belongs_to :request
end
对于你能够归一化的所有已知数据,都应该进行建模。通常比你想象的要多。
处理不符合固定模式的数据可以有几种方式:
- 只需定义所有字段,然后接受其中偶尔出现的空值。
- 实体-属性-值(EAV)模式。这种经典方法包括一个单独的表,其中每行表示分类的一个值,例如
rails g model ClassificationAttribute classification:references attr_name attr_value
。这在很大程度上已经被 JSON 数据类型取代。 - 使用 JSON/JSONB 列。这个额外的列可以用来存储任何无法归一化的非结构化数据。
- 序列化数据列。这也已经被 JSON/JSONB 取代。
所有这些方法都可以与单表继承模式相结合使用。
如果分类可以分解为有限数量的变种,你可以考虑多表继承,其中你将基本数据存储在分类表中,然后使用单独的表来存储更具体的数据。Rails 的 delegated_type
功能可以用于这个目的。
英文:
I would say that you should first try to model it according the relational model as far as possible.
# beware of potential conflicts with this name as it clashes with core method in controllers
class Request < ApplicationRecord
has_many :classifications
end
class Classification < ApplicationRecord
belongs_to :request
end
Model everything you know you can normalize. It's usually more then you think.
Dealing with data that doesn't adhere to a fixed schema can then be dealt with a few ways:
- Just define all the fields and live with a few nulls here and there.
- The Entity–attribute–value (EAV) pattern. This classic approach consists of a separate table where each row represents a value for a classification eg
rails g model ClassificationAttribute classification:references attr_name attr_value
. This is largely made obsolete by JSON data types. - A JSON/JSONB column. This additional column would be used to shove any unstructured data that cannot be normalized.
- Serialized data columns. This also made obsolete by JSON/JSONB.
All of these can be combined with the Single Table Inheritance pattern.
If classification can be broken down into a limited number of variants you could consider Multiple Table Inheritance where you store the base data in the classification table and then use separate tables for the more specific data. Rails delegated_type
feature can be used for this.
答案2
得分: 0
你的问题真的很混乱,很难理解你想要实现什么。但有一些备注:
-
你说“请求有一个分类。分类有多个请求”。但如果请求有一个分类,那么分类应该属于请求。这样,分类模型会包含一个名为
request_id
(外键)的字段,帮助ActiveRecord将这两个模型关联起来(子模型是持有外键的模型)。
如果它们是彼此的父级(has_one
或has_many
),那么外键在哪里呢? -
动态字段是不可能的。你的数据库是硬编码的:每个字段在关系数据库中都有声明,Rails ActiveRecord允许轻松访问和验证它。确实有一个解决方案:让模型中的一个持有一个JSON或JSONB字段。而值不是常见类型(字符串、文本、整数等),而是JSON类型,并且由Rails转换为哈希:
{
first_name: "Arthur",
last_name: "Smith",
age: "23"
}
这对购物车非常方便,因为你可以保存实际的项目列表,而不是一个关联。拥有关联需要对项目的更改进行版本控制(例如,当项目的价格发生变化时),这需要一些良好的工程技巧。
问题是:这是否是你真正想要做的?因为这不适用于所有应用程序或用途。
- 此外,你说请求依赖于分类。我在上面提到了外键的问题。但一个记录的行为是由直接关系设置的,似乎有些奇怪。谁创建分类?是应用程序模型之一,如用户?管理员?还是由应用程序的创建者提供(那么分类是一个独立的模型)?在这种情况下,分类在请求之前存在,也许
has_and_belongs_to_many
关联(一个联接表)更合适…
也许给我们提供一些更清晰的示例,以便我们可以进一步帮助你。
英文:
Your question is really confused and it is hard to understand what you are trying to achieve. But a few remarks:
-
You say "Request has one classification. Classification has_many requests" But if Request has one classification. Then classification should belongs to request. This way The Classification model holds a field called
request_id
(foreign key) that will help ActiveRecord link the two models together. (The child model is the one holding a foreign key)
If each is the parent of the other (has_one
orhas_many
), then where is the foreign key ? -
dynamic fields is not something possible. Your databse if hard coded: each field is declared in the relational database and Rails ActiveRecord's allows to access it easily and validate it. There is indeed a solution: have one of the model holds a JSON or JSONB field. And the value instead of being of the common types: string, text, integer.. be of JSON type and holds a value that is converted to a hash by Rails :
{
first_name: "Arthur",
last_name: "Smith",
age: "23"
}
This is pretty convenient for shopping carts as you can save an actual list of items rather than an association. Having an association would need to version your items changes (when the price of an item changes for example) which need some good engineering.
The question is : is it what you really want to do ? Because this is an option that doesn't fit all apps or uses.
- Also you say the request depends on the classification. I have mentionned the problem of the foreign key above. But it seems weird that one of your record behavior is set by a direct relationship relationship. Who creates the classification ? Is it one of the app models such as the User ? an Admin ? or is it seeded by the app creator (then Classification is a standalone model) ? In this case the classification preexists the request the Request and maybe a has_and_belongs_to_many association (a join table ) would fit better...
Maybe give us a clearer view of what you want to achieve with real life examples so we can help further
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论