BUGFIX: attribute protection

Fixes bug where documents recreated from the database were
being stripped of their protected attributes when instantiated

Signed-off-by: Marcos Tapajos <tapajos@Tapajos-MacBook.local>
This commit is contained in:
Will Leinweber 2009-12-04 01:58:07 -06:00
parent 5707d89290
commit d41c7c96da
5 changed files with 84 additions and 17 deletions

View file

@ -183,7 +183,7 @@ module CouchRest
if @container_class.nil? if @container_class.nil?
results results
else else
results['rows'].collect { |row| @container_class.new(row['doc']) } unless results['rows'].nil? results['rows'].collect { |row| @container_class.create_from_database(row['doc']) } unless results['rows'].nil?
end end
end end

View file

@ -51,11 +51,9 @@ module CouchRest
# db<Database>:: optional option to pass a custom database to use # db<Database>:: optional option to pass a custom database to use
def get(id, db = database) def get(id, db = database)
begin begin
doc = db.get id get!(id, db)
rescue rescue
nil nil
else
new(doc)
end end
end end
@ -72,7 +70,7 @@ module CouchRest
# db<Database>:: optional option to pass a custom database to use # db<Database>:: optional option to pass a custom database to use
def get!(id, db = database) def get!(id, db = database)
doc = db.get id doc = db.get id
new(doc) create_from_database(doc)
end end
end end

View file

@ -137,13 +137,13 @@ module CouchRest
collection_proxy_for(design_doc, name, opts.merge({:include_docs => true})) collection_proxy_for(design_doc, name, opts.merge({:include_docs => true}))
else else
view = fetch_view db, name, opts.merge({:include_docs => true}), &block view = fetch_view db, name, opts.merge({:include_docs => true}), &block
view['rows'].collect{|r|new(r['doc'])} if view['rows'] view['rows'].collect{|r|create_from_database(r['doc'])} if view['rows']
end end
rescue rescue
# fallback for old versions of couchdb that don't # fallback for old versions of couchdb that don't
# have include_docs support # have include_docs support
view = fetch_view(db, name, opts, &block) view = fetch_view(db, name, opts, &block)
view['rows'].collect{|r|new(db.get(r['id']))} if view['rows'] view['rows'].collect{|r|create_from_database(db.get(r['id']))} if view['rows']
end end
end end
end end

View file

@ -39,10 +39,19 @@ module CouchRest
define_callbacks :update, "result == :halt" define_callbacks :update, "result == :halt"
define_callbacks :destroy, "result == :halt" define_callbacks :destroy, "result == :halt"
def initialize(passed_keys={}) # Creates a new instance, bypassing attribute protection
#
# ==== Returns
# a document instance
def self.create_from_database(passed_keys={})
new(passed_keys, :directly_set_attributes => true)
end
def initialize(passed_keys={}, options={})
apply_defaults # defined in CouchRest::Mixins::Properties apply_defaults # defined in CouchRest::Mixins::Properties
set_attributes(passed_keys) unless passed_keys.nil? remove_protected_attributes(passed_keys) unless options[:directly_set_attributes]
super directly_set_attributes(passed_keys) unless passed_keys.nil?
super(passed_keys)
cast_keys # defined in CouchRest::Mixins::Properties cast_keys # defined in CouchRest::Mixins::Properties
unless self['_id'] && self['_rev'] unless self['_id'] && self['_rev']
self['couchrest-type'] = self.class.to_s self['couchrest-type'] = self.class.to_s
@ -282,13 +291,17 @@ module CouchRest
end end
end end
def directly_set_attributes(hash)
hash.each do |attribute_name, attribute_value|
if self.respond_to?("#{attribute_name}=")
self.send("#{attribute_name}=", hash.delete(attribute_name))
end
end
end
def set_attributes(hash) def set_attributes(hash)
attrs = remove_protected_attributes(hash) attrs = remove_protected_attributes(hash)
attrs.each do |attribute_name, attribute_value| directly_set_attributes(attrs)
if self.respond_to?("#{attribute_name}=")
self.send("#{attribute_name}=", attrs.delete(attribute_name))
end
end
end end
end end
end end

View file

@ -21,6 +21,17 @@ describe "ExtendedDocument", "no declarations" do
user.name.should == "will" user.name.should == "will"
user.phone.should == "555-5555" user.phone.should == "555-5555"
end end
it "should recreate from the database properly" do
user = NoProtection.new
user.name = "will"
user.phone = "555-5555"
user.save!
user = NoProtection.get(user.id)
user.name.should == "will"
user.phone.should == "555-5555"
end
end end
describe "ExtendedDocument", "accessible flag" do describe "ExtendedDocument", "accessible flag" do
@ -92,3 +103,48 @@ describe "ExtendedDocument", "protected flag" do
lambda { WithBoth.new }.should raise_error lambda { WithBoth.new }.should raise_error
end end
end end
describe "ExtendedDocument", "from database" do
class WithProtected < CouchRest::ExtendedDocument
use_database TEST_SERVER.default_database
property :name
property :admin, :default => false, :protected => true
view_by :name
end
before(:each) do
@user = WithProtected.new
@user.name = "will"
@user.admin = true
@user.save!
end
def verify_attrs(user)
user.name.should == "will"
user.admin.should == true
end
it "ExtendedDocument#get should not strip protected attributes" do
reloaded = WithProtected.get( @user.id )
verify_attrs reloaded
end
it "ExtendedDocument#get! should not strip protected attributes" do
reloaded = WithProtected.get!( @user.id )
verify_attrs reloaded
end
it "ExtendedDocument#all should not strip protected attributes" do
# all creates a CollectionProxy
docs = WithProtected.all(:key => @user.id)
docs.size.should == 1
reloaded = docs.first
verify_attrs reloaded
end
it "views should not strip protected attributes" do
docs = WithProtected.by_name(:startkey => "will", :endkey => "will")
reloaded = docs.first
verify_attrs reloaded
end
end