提交 f443e119 编写于 作者: R Rafael Mendonça França

Merge pull request #5807 from Antiarchitect/store-improvement

Custom coders support for ActiveRecord::Store. 
## Rails 4.0.0 (unreleased) ##
* Added custom coders support for ActiveRecord::Store. Now you can set
your custom coder like this:
store :settings, accessors: [ :color, :homepage ], coder: JSON
*Andrey Voronkov*
* `mysql` and `mysql2` connections will set `SQL_MODE=STRICT_ALL_TABLES` by
default to avoid silent data loss. This can be disabled by specifying
......
......@@ -10,15 +10,20 @@ module ActiveRecord
# Make sure that you declare the database column used for the serialized store as a text, so there's
# plenty of room.
#
# You can set custom coder to encode/decode your serialized attributes to/from different formats.
# JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+.
#
# Examples:
#
# class User < ActiveRecord::Base
# store :settings, accessors: [ :color, :homepage ]
# store :settings, accessors: [ :color, :homepage ], coder: JSON
# end
#
# u = User.new(color: 'black', homepage: '37signals.com')
# u.color # Accessor stored attribute
# u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
# u.settings['country'] = 'Denmark' # Any attribute, even if not specified with an accessor
# String keys should be used for direct access to virtual attributes because of most of the coders do not
# distinguish symbols and strings as keys.
#
# # Add additional accessors to an existing store through store_accessor
# class SuperUser < User
......@@ -29,7 +34,7 @@ module Store
module ClassMethods
def store(store_attribute, options = {})
serialize store_attribute, Hash
serialize store_attribute, options.fetch(:coder, Hash)
store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
end
......@@ -37,13 +42,13 @@ def store_accessor(store_attribute, *keys)
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)[key.to_s] = 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]
send(store_attribute)[key.to_s]
end
end
end
......
......@@ -4,7 +4,7 @@
class StoreTest < ActiveRecord::TestCase
setup do
@john = Admin::User.create(:name => 'John Doe', :color => 'black', :remember_login => true)
@john = Admin::User.create(:name => 'John Doe', :color => 'black', :remember_login => true, :height => 'tall', :is_a_good_guy => true)
end
test "reading store attributes through accessors" do
......@@ -40,4 +40,38 @@ class StoreTest < ActiveRecord::TestCase
@john.remember_login = false
assert_equal false, @john.remember_login
end
test "reading store attributes through accessors encoded with JSON" do
assert_equal 'tall', @john.height
assert_nil @john.weight
end
test "writing store attributes through accessors encoded with JSON" do
@john.height = 'short'
@john.weight = 'heavy'
assert_equal 'short', @john.height
assert_equal 'heavy', @john.weight
end
test "accessing attributes not exposed by accessors encoded with JSON" do
@john.json_data['somestuff'] = 'somecoolstuff'
@john.save
assert_equal 'somecoolstuff', @john.reload.json_data['somestuff']
end
test "updating the store will mark it as changed encoded with JSON" do
@john.height = 'short'
assert @john.json_data_changed?
end
test "object initialization with not nullable column encoded with JSON" do
assert_equal true, @john.is_a_good_guy
end
test "writing with not nullable column encoded with JSON" do
@john.is_a_good_guy = false
assert_equal false, @john.is_a_good_guy
end
end
......@@ -2,4 +2,6 @@ class Admin::User < ActiveRecord::Base
belongs_to :account
store :settings, :accessors => [ :color, :homepage ]
store :preferences, :accessors => [ :remember_login ]
store :json_data, :accessors => [ :height, :weight ], :coder => JSON
store :json_data_empty, :accessors => [ :is_a_good_guy ], :coder => JSON
end
......@@ -41,6 +41,8 @@ def create_table(*args, &block)
# MySQL does not allow default values for blobs. Fake it out with a
# big varchar below.
t.string :preferences, :null => false, :default => '', :limit => 1024
t.text :json_data, :null => true
t.text :json_data_empty, :null => false, :default => ""
t.references :account
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册