【问题标题】:Rails Object to hashRails 要散列的对象
【发布时间】:2011-04-21 19:06:51
【问题描述】:

我已经创建了以下对象

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

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

@object.to_hash

这怎么可能在 Rails 中实现?

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

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

    @post.attributes
    

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

    attribs = @post.attributes
    

    【讨论】:

    • 循环时不要使用这个,Expensive method。使用 as_json
    • .to_json 将在模型不完整时查询数据库
    • joinsselectPerson.joins(:address).select("addresses.street, persons.name").find_by_id(id).attributes 一起使用,将返回{ street: "", name: "" }
    • @AnkitG 我不相信 as_json 更便宜。如果您查看as_json 的源代码,它会调用serializable_hash,而后者又会调用attributes!所以你的建议实际上是在attributes 上增加了两层复杂性,使其更加昂贵。
    • .as_json 会将对象序列化为 ruby​​ 哈希
    【解决方案2】:

    您当然可以使用属性返回所有属性,但您可以向 Post 添加一个实例方法,将其称为“to_hash”并让它返回您想要的散列数据。像

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      【解决方案4】:

      不确定这是否是您需要的,但请在 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
      

      【讨论】:

      • 海报询问 Rails 中的 ActiveRecord 模型。
      【解决方案5】:

      Swanand 的回答很棒。

      如果你使用的是FactoryGirl,你可以使用它的build方法来生成没有id键的属性哈希。例如

      build(:post).attributes
      

      【讨论】:

        【解决方案6】:
        @object.as_json
        

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

        示例

        模型campaign属于shop,并且有一个list

        模型list有很多list_tasks,每个list_tasks都有很多cmets

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

        注意 methods: :tags 可以帮助您附加任何与他人没有关系的附加对象。您只需要在模型 campaign 中定义一个名称为 tags 的方法。此方法应返回您需要的任何内容(例如 Tags.all)

        as_json的官方文档

        【讨论】:

        • 在找到这个之前做了一个自定义函数。想要更多的一次性方法,而不是为类定义一个函数。出于某种原因,即使在使用 XML 序列化方法之后也错过了这一点。 to_ 变体似乎与as_ 变体几乎完全相同,除了引用的输出。我唯一不喜欢的是不保留过滤条件的顺序。它似乎是按字母顺序排序的。我认为这与我的环境中的 awesome_print gem 有关,但我认为情况并非如此。
        【解决方案7】:

        这里有一些很棒的建议。

        我认为值得注意的是,您可以像这样将 ActiveRecord 模型视为哈希:

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

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

        【讨论】:

          【解决方案8】:

          我的解决方案:

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

          【讨论】:

            【解决方案9】:

            您可以使用以下任一方法获取作为哈希返回的模型对象的属性

            @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)
            

            【讨论】:

            • as_json 将再次调用数据库查询,如果您使用连接方法运行嵌套资源
            【解决方案10】:

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

            注意:不是向所有人推荐这个,而是在极端情况下!


            来自 ruby​​ 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"},
                  ...
                 ] ...
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-01-26
              • 1970-01-01
              • 2014-02-16
              • 1970-01-01
              • 1970-01-01
              • 2013-06-22
              • 2012-06-12
              • 2011-10-09
              相关资源
              最近更新 更多