
[英]How to map hash keys to methods for an encapsulated Ruby class (tableless model)?
[英]Ruby: How to map a model on XML
在 Ruby-on-Rails 6.0 中,我想创建一个名为 services 的资源,包含模型、视图和控制器。
每个服务都有一个 ID、一个名称、一个类型和一个图像索引
但我想要 XML 上的模型映射(见下文)而不是 ActiveRecord。 我希望操作(索引、显示、新建、编辑和销毁)修改 XML 本身。
我的第一个尝试是在控制器中添加代码来解析 XML,如下所示:
def index
@services = []
f = File.open("xml/eidos/LeftTree/Services.xml")
doc = Nokogiri::XML(f)
f.close
root = doc.root
tags = root.xpath("Tag")
tags.each do |tag|
@service = Service.new
@service.node_name = tag.xpath("NodeName").text
@service.text = tag.xpath("Text").text
@service.image_index = tag.xpath("ImageIndex").text
@services << @service
end
@services
end
这成功并将完整的实例列表返回给我。 我正在为def Show
做同样的事情(请注意,我不需要编辑或删除 XML)
现在的中间问题是:
如何管理主要 Tag 元素的子元素?
我应该至少创建两个其他资源:一个request
和一个choice
(以及更多,基于type
元素的内容),我的方法看起来不干净。
最后一个问题是:
这就是为什么我想找到/构建一种像 ActiveRecord 替换这样的方法,我可以在其中列出我的资源的属性和关系。
在这个方向有什么建议吗?
示例 XML 如下所示:
<Services>
<Tag>
<ID>X401ED7DA027C</ID>
<Name>Accertamento Ici Con Adesione</Name>
<Type>Service</Type>
<ImageIndex>0</ImageIndex>
</Tag>
<Tag>
<ID>X3F9BEB550223</ID>
<Name>Cambio di abitazione</Name>
<Type>Service</Type>
<ImageIndex>0</ImageIndex>
<Tag>
<ID>X3F9BEB550223/X400E4CBA032E</ID>
<Name>Richiesta Di Cambio Di Abitazione</Name>
<Type>Request</Type>
<ImageIndex>1</ImageIndex>
<Tag>
<ID>X3F9BEB550223/X400E4CBA032E/X40091B660349_X3FFF3E980118</ID>
<Name>Allegato</Name>
<Type>Choice</Type>
<Multiplicity>
<MinOccurrence>0</MinOccurrence>
<MaxOccurrence>*</MaxOccurrence>
</Multiplicity>
<Required>False</Required>
<ImageIndex>5</ImageIndex>
<IDRole>X40091B660349</IDRole>
<NameSpace>OggettiCondivisi</NameSpace>
</Tag>
</Tag>
</Tag>
</Services>
ActiveRecord 没有对平面文件数据库的内置支持。 如果您想使用 ActiveRecord,我建议您使用受支持的数据库之一并从 XML 导入/导出。
这个答案真的只是给猪化妆。 因为制作您自己的基于 XML 的对象持久性根本没有任何好处(没有人这样做是有原因的),并且您本可以更好地使用它只是需要时间。 如果数据不符合严格的模式,只需使用 Mongoid 或其他一些 NoSQL 数据库。
第一步是将导入移动到模型中并使其减少:
class Service
include ActiveModel::Model
include ActiveModel::Attributes
attribute :node_name, String
attribute :text, String
attribute :image_index, String
def self.import(fn = "xml/eidos/LeftTree/Services.xml")
doc = Nokogiri::XML(File.read(fn))
tags = doc.root.xpath("Tag")
tags.map do |tag|
Service.new(
node_name: tag.xpath("NodeName").text,
text: tag.xpath("Text").text,
image_index: tag.xpath("ImageIndex").text
)
end
end
end
这将使您将控制器操作精简为:
def index
@services = Service.import
end
#each
应该只在你只关心循环的副作用而不是返回值时使用。 例如:
@users.each do |u|
u.send_welcome_email!
end
对于其他一切,请使用#map
或可枚举的其他方法,例如#collect
、 #reject
...
您还为循环的每次迭代重新分配实例变量@service
。 了解实例变量和局部变量之间的区别。 并且您分配的局部变量数量要少一些。 您不需要将所有内容都分配给变量 - 特别是如果您只使用它一次。
您想要在模型(甚至是单独的服务对象)中进行导入的原因是控制器很难测试。 它们有大量的依赖项,真正测试它们的唯一好方法是间接通过 HTTP 请求。 控制器是将 Rails 中的所有东西联系在一起的胶水代码——不要让它们膨胀。
另一方面,模型更容易测试,因为您只需调用Service.import
并编写关于结果的断言。
我希望操作(索引、显示、新建、编辑和销毁)修改 >XML 本身。
玩得开心。 您需要使用 Nokogiri 加载和修改文档树。 在n小时后,您将构建一些基本上可以完成数据库功能的东西,但在各方面都更糟,因为它根本无法扩展。
这就是为什么我想找到/构建一种像 ActiveRecord 替换这样的方法,我可以在其中列出我的资源的属性和关系。
再次 - 完全浪费时间。 你可以用ActiveModel::Model
创建一些东西,就像 ActiveRecord 中的关联一样。 但为什么?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.