【问题标题】:Hstore and RailsHstore 和 Rails
【发布时间】:2012-11-25 19:42:18
【问题描述】:

我正在尝试使用最新版本的 activerecord-postgres-hstore gem 在 Rails 3.2.9 项目中使用 Hstore,但在使用 ActiveRecord 为 Hstore 中的值提供的 store_accessor 时遇到了一些麻烦。

我的模型如下所示:

class Person < ActiveRecord::Base
  serialize :data, ActiveRecord::Coders::Hstore
  attr_accessible :data, :name
  store_accessor :data, :age, :gender
end

当我进入 rails 控制台时,我得到了:

Loading development environment (Rails 3.2.9)
1.9.3-p327 :001 > p = Person.find(3)
  Person Load (9.8ms)  SELECT "people".* FROM "people" WHERE "people"."id" = $1 LIMIT 1  [["id", 3]]
 => #<Person id: 3, name: "Leo", data: {"age"=>"34", "gender"=>"male"}, created_at: "2012-12-07 15:01:53", updated_at: "2012-12-07 15:27:40"> 
1.9.3-p327 :002 > p.age
 => nil 
1.9.3-p327 :003 > p.age = "204"
 => "204" 
1.9.3-p327 :004 > p.save!
   (0.2ms)  BEGIN
   (0.6ms)  UPDATE "people" SET "data" = 'age=>34,gender=>male,age=>204', "updated_at" = '2012-12-07 15:28:33.097404' WHERE "people"."id" = 3
   (2.2ms)  COMMIT
 => true 
1.9.3-p327 :005 > p
 => #<Person id: 3, name: "Leo", data: {"age"=>"204", "gender"=>"male"}, created_at: "2012-12-07 15:01:53", updated_at: "2012-12-07 15:28:33">
1.9.3-p327 :006 > exit
% rails c                 12-12-07 - 10:28:35
Loading development environment (Rails 3.2.9)
1.9.3-p327 :001 > p = Person.find(3)
  Person Load (6.9ms)  SELECT "people".* FROM "people" WHERE "people"."id" = $1 LIMIT 1  [["id", 3]]
 => #<Person id: 3, name: "Leo", data: {"age"=>"34", "gender"=>"male"}, created_at: "2012-12-07 15:01:53", updated_at: "2012-12-07 15:28:33"> 

注意保存!确实更新了这个人。当我退出控制台并返回时,记录会返回到原始数据集。

另外,请注意,当我尝试访问 age 时,它返回 nil。

如果有人想知道 store_accessor 方法在 ActiveRecord 中的作用

store.rb

def store_accessor(store_attribute, *keys)
  Array(keys).flatten.each do |key|
    define_method("#{key}=") do |value|
      send("#{store_attribute}=", {}) unless send(store_attribute).is_a?(Hash)
      send(store_attribute)[key] = value
      send("#{store_attribute}_will_change!") 
    end

    define_method(key) do
      send("#{store_attribute}=", {}) unless send(store_attribute).is_a?(Hash)
      send(store_attribute)[key]
    end
  end
end        

这很奇怪,因为当我在控制台中执行相同的 send(store_attribute)[key] 行时它可以工作:

1.9.3-p327 :010 >   p.send(:data)['age']
 => "34" 

1.9.3-p327 :011 > p.send(:data)['age'] = "500"
 => "500" 
1.9.3-p327 :012 > p.send("data_will_change!")
 => {"age"=>"500", "gender"=>"male"} 
1.9.3-p327 :013 > p.save!
   (0.2ms)  BEGIN
   (0.7ms)  UPDATE "people" SET "data" = 'age=>500,gender=>male', "updated_at" = '2012-12-07 15:41:50.404719' WHERE "people"."id" = 3
   (1.8ms)  COMMIT
 => true 
1.9.3-p327 :014 > p
 => #<Person id: 3, name: "Leo", data: {"age"=>"500", "gender"=>"male"}, created_at: "2012-12-07 15:01:53", updated_at: "2012-12-07 15:41:50"> 
1.9.3-p327 :015 > exit
% rails c                 12-12-07 - 10:41:57
Loading development environment (Rails 3.2.9)
1.9.3-p327 :001 > p = Person.find(3)
  Person Load (9.3ms)  SELECT "people".* FROM "people" WHERE "people"."id" = $1 LIMIT 1  [["id", 3]]
 => #<Person id: 3, name: "Leo", data: {"age"=>"500", "gender"=>"male"}, created_at: "2012-12-07 15:01:53", updated_at: "2012-12-07 15:41:50"> 
1.9.3-p327 :002 > 

知道这里可能会发生什么吗?

【问题讨论】:

    标签: ruby postgresql activerecord ruby-on-rails-3.2 hstore


    【解决方案1】:

    我最终将 store_accessor 全部删除,并使用以下代码为 hstore 键添加访问器

    lib/hstore_accessor.rb

    module HstoreAccessor
      def self.included(base)
        base.extend(ClassMethods)
      end
    
      module ClassMethods
        def hstore_accessor(hstore_attribute, *keys)
          Array(keys).flatten.each do |key|
            define_method("#{key}=") do |value|
              send("#{hstore_attribute}=", (send(hstore_attribute) || {}).merge(key.to_s => value))
              send("#{hstore_attribute}_will_change!")
            end
            define_method(key) do
              send(hstore_attribute) && send(hstore_attribute)[key.to_s]
            end
          end
        end
      end
    end
    
    ActiveRecord::Base.send(:include, HstoreAccessor)
    

    config/initializers/active_record_extensions.rb

    require "hstore_accessor"
    

    人物

    class Person < ActiveRecord::Base
      hstore_accessor :data, :size, :shape, :smell
    end
    

    【讨论】:

    • 超级酷。等到 R4 时,这一切都是原生的,但现在很好用。
    • 同意,这个和 Postgres JSON 数据类型功能是我一直在等待的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-31
    • 2015-08-12
    • 2017-04-05
    • 2014-10-14
    相关资源
    最近更新 更多