Rails对象哈希

时间:2010-10-06 12:10:01

标签: ruby-on-rails ruby

我有以下创建的对象

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

保存后,我希望能够将对象恢复为哈希,例如做类似的事情:

@object.to_hash

如何在轨道内实现这一目标?

10 个答案:

答案 0 :(得分:267)

如果您只查找属性,那么您可以通过以下方式获取它们:

@post.attributes

答案 1 :(得分:39)

在最新版本的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"
}

这当然意味着您必须明确指定必须出现的属性。

希望这有帮助。

编辑:

您也可以查看Hashifiable gem。

答案 2 :(得分:21)

@object.as_json

as_json具有根据模型关系配置复杂对象的非常灵活的方式

示例

模型广告系列属于商店,并且有一个列表

模型列表有多个 list_tasks ,每个 list_tasks 都有很多评论

我们可以得到一个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)

as_json

的官方文档

答案 3 :(得分:7)

您可以使用

获取作为哈希返回的模型对象的属性
@post.attributes

@post.as_json

as_json允许您包含关联及其属性,以及指定要包含/排除的属性(请参阅documentation)。但是,如果您只需要基础对象的属性,那么在我的应用程序中使用ruby 2.2.3和rails 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)

答案 4 :(得分:6)

您绝对可以使用这些属性来返回所有属性,但您可以将一个实例方法添加到Post,将其称为“to_hash”并让它返回您想要的哈希数据。像

这样的东西
def to_hash
 { name: self.name, active: true }
end

答案 5 :(得分:6)

这里有一些很棒的建议。

我认为值得注意的是,您可以将ActiveRecord模型视为散列,如下所示:

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

因此,您可以将对象本身用作哈希值,而不是生成属性的哈希值。

答案 6 :(得分:2)

不确定这是否是您需要的,但请在ruby控制台中尝试:

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

显然它会在控制台中返回一个哈希值。如果你想从一个方法中返回一个哈希 - 而不仅仅是“h”尝试使用“return h.inspect”,类似于:

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

答案 7 :(得分:1)

我的解决方案:

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

答案 8 :(得分:0)

Swanand的回答很棒。

如果您使用的是FactoryGirl,则可以使用其build方法生成不带键id的属性哈希。 e.g。

build(:post).attributes

答案 9 :(得分:0)

老问题,但是大量引用...我认为大多数人使用其他方法,但实际上有to_hash方法,必须正确设置。一般来说,在追踪4之后,采摘是一个更好的答案...回答这个主要是因为我不得不搜索一堆来找到这个线程或任何有用的东西&amp;假设其他人遇到同样的问题...

注意:不是为每个人推荐这个,而是边缘情况!

来自rubi on rails 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"},
      ...
     ] ...