Rails 对象散列

我已经创建了以下对象

@post = Post.create(:name => 'test', :post_number => 20, :active => true)

一旦保存完毕,我希望能够将对象返回到散列,例如,通过执行以下操作:

@object.to_hash

这怎么可能从铁轨内部进行?

129825 次浏览

如果你只是在寻找属性,那么你可以通过以下方法获得:

@post.attributes

请注意,每次调用它时都会调用 ActiveModel::AttributeSet.to_hash,因此如果需要多次访问散列,应该将其缓存在局部变量中:

attribs = @post.attributes

您完全可以使用这些属性来返回所有属性,但是您可以向 Post 添加一个实例方法,称之为“ to _ hash”,并让它返回您希望在散列中使用的数据。差不多

def to_hash
{ name: self.name, active: true }
end

在最新版本的 Rails 中(虽然不能确切说出是哪一个) ,您可以使用 as_json方法:

@post = Post.first
hash = @post.as_json
puts hash.pretty_inspect

将输出:

{
:name => "test",
:post_number => 20,
:active => true
}

更进一步,您可以重写这个方法来定制属性的显示方式,方法如下:

class Post < ActiveRecord::Base
def as_json(*args)
{
:name => "My name is '#{self.name}'",
:post_number => "Post ##{self.post_number}",
}
end
end

然后,使用与上面相同的实例,将输出:

{
:name => "My name is 'test'",
:post_number => "Post #20"
}

这当然意味着您必须显式地指定必须显示哪些属性。

希望这个能帮上忙。

编辑:

你也可以检查 哈希贝尔的宝石。

不确定这是否是你需要的,但是在 Ruby 控制台尝试一下:

h = Hash.new
h["name"] = "test"
h["post_number"] = 20
h["active"] = true
h

显然它会在控制台中返回一个 hash。如果你想从一个方法中返回一个散列-不要只用“ h”尝试使用“ return h.sight”,类似于:

def wordcount(str)
h = Hash.new()
str.split.each do |key|
if h[key] == nil
h[key] = 1
else
h[key] = h[key] + 1
end
end
return h.inspect
end

Swanand 的回答很棒。

如果使用的是 FactoryGirl,则可以使用其 build方法生成不带键 id的属性散列。例如:。

build(:post).attributes
@object.as_json

As _ json 有非常灵活的方法根据模型关系配置复杂对象

例子

型号 竞选属于 商店,有一个 名单

型号 名单有许多 列表 _ 任务和每个 列表 _ 任务有许多 评论

我们可以得到一个 json,它可以轻松地组合所有这些数据。

@campaign.as_json(
{
except: [:created_at, :updated_at],
include: {
shop: {
except: [:created_at, :updated_at, :customer_id],
include: {customer: {except: [:created_at, :updated_at]}}},
list: {
except: [:created_at, :updated_at, :observation_id],
include: {
list_tasks: {
except: [:created_at, :updated_at],
include: {comments: {except: [:created_at, :updated_at]}}
}
}
},
},
methods: :tags
})

注意,方法: : 标记可以帮助您附加任何与其他对象没有关系的附加对象。您只需要在模型 竞选中定义一个名为 标签的方法。这个方法应该返回您需要的任何内容(例如 Tags.all)

就像 Json 一样的正式文件

这里有一些很好的建议。

我认为值得注意的是,您可以像下面这样将 ActiveRecord 模型看作一个散列:

@customer = Customer.new( name: "John Jacob" )
@customer.name    # => "John Jacob"
@customer[:name]  # => "John Jacob"
@customer['name'] # => "John Jacob"

因此,您可以使用对象本身作为散列,而不是生成属性的散列。

我的解决办法是:

Hash[ post.attributes.map{ |a| [a, post[a]] } ]

您可以使用以下两种方法之一获取作为散列返回的模型对象的属性

@post.attributes

或者

@post.as_json

as_json允许您包含关联及其属性,并指定包含/排除哪些属性(参见 文件)。然而,如果你只需要基本对象的属性,在我的应用中使用 ruby 2.2.3和 ails 4.2.2进行基准测试表明,attributes所需的时间不到 as_json的一半。

>> p = Problem.last
Problem Load (0.5ms)  SELECT  "problems".* FROM "problems"  ORDER BY "problems"."id" DESC LIMIT 1
=> #<Problem id: 137, enabled: true, created_at: "2016-02-19 11:20:28", updated_at: "2016-02-26 07:47:34">
>>
>> p.attributes
=> {"id"=>137, "enabled"=>true, "created_at"=>Fri, 19 Feb 2016 11:20:28 UTC +00:00, "updated_at"=>Fri, 26 Feb 2016 07:47:34 UTC +00:00}
>>
>> p.as_json
=> {"id"=>137, "enabled"=>true, "created_at"=>Fri, 19 Feb 2016 11:20:28 UTC +00:00, "updated_at"=>Fri, 26 Feb 2016 07:47:34 UTC +00:00}
>>
>> n = 1000000
>> Benchmark.bmbm do |x|
?>   x.report("attributes") { n.times { p.attributes } }
?>   x.report("as_json")    { n.times { p.as_json } }
>> end
Rehearsal ----------------------------------------------
attributes   6.910000   0.020000   6.930000 (  7.078699)
as_json     14.810000   0.160000  14.970000 ( 15.253316)
------------------------------------ total: 21.900000sec


user     system      total        real
attributes   6.820000   0.010000   6.830000 (  7.004783)
as_json     14.990000   0.050000  15.040000 ( 15.352894)

这是个老问题,但是引用很多... ... 我认为大多数人使用其他方法,但是实际上有一个 to_hash方法,它必须被正确设置。一般来说,在 Rails4之后,pluck 是一个更好的答案... 回答这个问题主要是因为我不得不搜索一大堆来找到这个帖子或者任何有用的东西,假设其他人也遇到了同样的问题..。

注意: 不建议大家这样做,但边缘的情况下!


从红宝石轨道 api... http://api.rubyonrails.org/classes/ActiveRecord/Result.html..。

This class encapsulates a result returned from calling #exec_query on any database connection adapter. For example:


result = ActiveRecord::Base.connection.exec_query('SELECT id, title, body FROM posts')
result # => #<ActiveRecord::Result:0xdeadbeef>


...


# Get an array of hashes representing the result (column => value):
result.to_hash
# => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
{"id" => 2, "title" => "title_2", "body" => "body_2"},
...
] ...