mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #5807 from Antiarchitect/store-improvement
Custom coders support for ActiveRecord::Store.
This commit is contained in:
commit
f443e119cd
5 changed files with 55 additions and 6 deletions
|
@ -1,4 +1,10 @@
|
|||
## 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 ActiveRecord
|
|||
|
||||
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 @@ module ActiveRecord
|
|||
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 @@ require 'models/admin/user'
|
|||
|
||||
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 @@ ActiveRecord::Schema.define do
|
|||
# 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
|
||||
|
||||
|
|
Loading…
Reference in a new issue