在Ruby中将每个键值对创建为新对象时,如何为对象分配哈希值

时间:2019-04-05 16:52:13

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

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

当前,可以在Rails视图中直接访问属性的哈希,然后像

一样在帮助器中清除返回值。
<%= clean_up(person.attributes["some_strangly_formatted_name"]) %>

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

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

理想情况下,我可以调用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

我如何实现这个目标?更笼统地说,这种策略是否有意义?

1 个答案:

答案 0 :(得分:0)

修改

我开始细读下面的一个答案,但是让我想到“在Ruby / Rails中通常有一种内置的方法来进行此操作”,我将检查SimpleDelgator,如果有人想破解使用该方法来创建一个像PersonAttributor < 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对象。通过将其序列化为JSON,它还可以存储来自OpenStruct对象的更新的键/值对:

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'....>

希望对您有所帮助。