Ruby on Rails中属性包装器的设计模式

时间:2017-07-11 08:57:28

标签: ruby-on-rails ruby design-patterns activerecord

我正在寻找在Ruby on Rails 5.1中实现以下内容的正确方法:

我有一个ActiveRecord 平台,其属性为{em> LONGTEXT 的属性structure_xml。它包含纯XML。我想添加一个包含辅助方法的包装器来查询XML(使用Nokogiri),例如找到某些节点或验证它。

我目前的解决方案

非ActiveRecord模型结构实现了所需的方法:

def Structure   
  def initialize(xml)
    @xml_root = Nokogiri::XML(xml).root
  end

  def get_node_by_id(node_id)
    @xml_root.xpath(".//Node[@id='#{node_id}']").first
  end
  ...
end

如果需要,ActiveRecord模型会初始化此模型:

class Platform < ApplicationRecord
  attr_accessor :structure

  def structure
    @structure || (@structure = Structure.new(structure_xml))
  end
  ...
end

它有效,但对我来说似乎并不理想。实现这个的正确方法是什么?

3 个答案:

答案 0 :(得分:1)

我相信,Rails的方式是引入类似的DSL(未经过测试,但它应该开箱即用):

module Structured
  def self.extended base
    base.send :define_method, :structure do
      @structure ||= {}
    end
  end
  def structured(*fields)
    fields.each do |field|
      define_method "#{field}_structure" do
        structure[field] ||= Structure.new(public_send field)
      end
    end
  end
end

在初始化程序中的某处:

ApplicationRecord.extend Structured

并在您的Platform中(假设它有一个包含原始xml的字段data):

class Platform < ApplicationRecord
  structured :data

  def print_it_out
    data_structure.get_node_by_id(3)
  end
end

答案 1 :(得分:1)

你似乎正走在正确的道路上。我可能会做同样的改变:

class Platform < ApplicationRecord
  delegate :xml_root, :my_method1, :my_method2, to: :structure

  def structure
    @structure ||= Structure.new(structure_xml)
  end
  ...
end

delegate允许您调用另一个对象中定义的操作,而无需浏览它。

只有在需要命名空间,多个类中的相同方法以及这些方法独立于类的对象时才创建模块。

答案 2 :(得分:0)

您可能需要查看PresenterDecorator设计模式。

  

装饰

     

装饰器类似于我们发现的继承功能   许多面向对象的编程语言。它允许添加   定义已经拥有的上下文对象的非泛型方法   任何共同实体的所有功能。像梅赛德斯品牌的汽车   在典型的汽车机器上安装先进的设施。

     

演示

     

演示者是装饰者本身的类型或子集。它是   接近查看MVC架构的模型。演示者是复合的   对象,我们为它提供多个选项。它产生了预期的结果   基于条件的成功匹配。   演示者的主要目标是将逻辑放在视图之外。

至少我很确定你需要的是什么,但装饰者模式也可能是你正在寻找的,链接有两个基本信息。