【问题标题】:How to assign hash values to an object while creating each key-value pair as a new object in Ruby如何在 Ruby 中将每个键值对创建为新对象时为对象分配哈希值
【发布时间】:2019-08-27 15:18:27
【问题描述】:

我有一个 person 对象,它从 web 服务调用(大约 400 个键值对)中获取有关此人的大量信息。散列中的每个项目都有些不同,并且在向用户显示之前必须进行不同的处理(例如时间戳值转换、处理的 nil 或以其他方式转换的文本)等,并且键本身在其他地方也很重要,必须从固定映射列表中“翻译”。

目前在 Rails 视图中直接访问属性的哈希值,然后在帮助程序中清理返回值,如

<%= clean_up(person.attributes["some_strangly_formatted_name"]) %>

<%= show_timestamp(person.attributes["some_nonhuman_time"]) %>

我试图弄清楚如何将这些值中的每一个动态分配给人员对象本身,同时还将每个属性创建为不同类(例如属性)的自己的对象,以将相关行为移动到那里,如辅助方法的数量和复杂性正在失控。

在理想情况下,我可以调用person.some_timestamp,它会返回人类可读的时间或person.name,并返回一个人名字符串

我已尝试按此处所示分配变量,但似乎必须在对象上预定义属性,并且我试图避免 400 attr_accessors 并试图适应新属性可能是的可能性添加 Set Attribute Dynamically of Ruby Object Having a hash, set object properties in Ruby DRY way to assign hash values to an object

不工作的方法看起来像

  def process_attributes(attributes)
    attributes.each {|k,v| public_send("#{k}=", v)}
  end

我怎样才能实现这个目标?更一般地说,这种策略是否有意义?

【问题讨论】:

  • 也许您想探索Model-View-Presenter 设计模式。如果模型处理表示问题,事情可能会变得非常混乱。您的演示者可以是默认情况下只是通过的代理,但可以自定义以重新格式化。
  • 您能否对 DB 列使用 JSON 类型,然后以这种方式访问​​键/值对?

标签: ruby oop ruby-on-rails-4


【解决方案1】:

编辑

我开始重复下面的答案,但它让我想到“在 Ruby/Rails 中通常有一种内置的方法可以做到这一点”,我会查看 SimpleDelgator,如果有人想尝试使用它来创建一个像 PersonAttributor &lt; SimpleDelgator 这样的模型并在其中进行转换,我会支持它。


不确定这是否是您想要的方向,但您可以使用 JSON 序列化做一些事情。如果您碰巧使用 Postgres,您可以使用 JASONB 列类型并将数据存储为可以直接查询的 JSON。但是普通的序列化可能会像这样发生:

person.attributes = {'one' => 'something', 'two' => 'some_other_thing'}.to_json
=> "{\"one\":\"something\",\"two\":\"some_other_thing\"}"
person.save

JSON(person.attributes)
=> {"one"=>"something", "two"=>"some_other_thing"}

JSON(person.attributes)["one"]
=> "something"

这是一个非常简单的即兴例子。它将所有键/值对放入一列中,而无需创建大量 attr_accessors。您可以在哈希首次分配给该人时进行清理。

这不包括您将这些属性移动到它们自己的类中的想法。如果您正在寻找动态创建这些对象,我不确定您这样做会为自己节省什么。如果您希望它们可以作为方法访问,您可以以某种方式使用 OpenStruct,这里有一个:

在你的人模型中,你可以有一个方法:

class Person < ApplicationRecord
...
def attr_object
  OpenStruct.new(self.attributes)
end
...

然后,您将获得一个对象,其中所有键作为方法,值作为这些方法的返回...

os_obj = person.attr_object
=> #<OpenStruct one='something', two='something_else'....>

您现在有一个对象,它为您提供方法oneone=。您可以使用方法将所有转换应用于该对象...

os_obj.one
=> 'something'
os_obj.one = 'something new'
=> 'something new'

您可以创建一个继承自 Person 的模型并创建 OpenStruct 对象。它还可以通过将 OpenStruct 对象序列化为 JSON 来存储更新后的键/值对:

person.attr_store = os_obj.to_h.to_json
"{\"one\":\"something new\"....}"

new_obj = Openstruct.new(JSON(person.attr_store))
=> #<OpenStruct one='something_new', two='something_else'....>

希望能给你带来一些有用的东西。

【讨论】:

  • 鉴于数据在应用程序其他部分的使用方式以及我无法控制来自 web 服务(无 DB)的 JSON 返回格式的限制,我前往SimpleDelegator 的方向,我认为它对我很有帮助,非常感谢您的评论。
猜你喜欢
  • 2011-03-13
  • 2018-05-22
  • 1970-01-01
  • 2018-04-13
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-15
相关资源
最近更新 更多