From 3f6cecbfcf91613756128734d9bb115c68d92333 Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Tue, 15 Mar 2011 23:37:05 -0700 Subject: [PATCH] use Item.new instead of build_item for singleton resource so it doesn't mess up database - closes #304 --- lib/cancan/controller_resource.rb | 20 ++++++++++++-------- spec/cancan/controller_resource_spec.rb | 6 +++--- spec/spec_helper.rb | 1 + 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/cancan/controller_resource.rb b/lib/cancan/controller_resource.rb index 064e964..a437845 100644 --- a/lib/cancan/controller_resource.rb +++ b/lib/cancan/controller_resource.rb @@ -82,10 +82,10 @@ module CanCan end def build_resource - method_name = @options[:singleton] && resource_base.respond_to?("build_#{name}") ? "build_#{name}" : "new" - resource = resource_base.send(method_name, @params[name] || {}) - initial_attributes.each do |name, value| - resource.send("#{name}=", value) + resource = resource_base.new(@params[name] || {}) + resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource + initial_attributes.each do |attr_name, value| + resource.send("#{attr_name}=", value) end resource end @@ -97,8 +97,8 @@ module CanCan end def find_resource - if @options[:singleton] && resource_base.respond_to?(name) - resource_base.send(name) + if @options[:singleton] && parent_resource.respond_to?(name) + parent_resource.send(name) else @options[:find_by] ? resource_base.send("find_by_#{@options[:find_by]}!", id_param) : resource_base.find(id_param) end @@ -155,7 +155,7 @@ module CanCan def resource_base if @options[:through] if parent_resource - @options[:singleton] ? parent_resource : parent_resource.send(@options[:through_association] || name.to_s.pluralize) + @options[:singleton] ? resource_class : parent_resource.send(@options[:through_association] || name.to_s.pluralize) elsif @options[:shallow] resource_class else @@ -166,9 +166,13 @@ module CanCan end end + def parent_name + @options[:through] && [@options[:through]].flatten.detect { |i| fetch_parent(i) } + end + # The object to load this resource through. def parent_resource - @options[:through] && [@options[:through]].flatten.map { |i| fetch_parent(i) }.compact.first + parent_name && fetch_parent(parent_name) end def fetch_parent(name) diff --git a/spec/cancan/controller_resource_spec.rb b/spec/cancan/controller_resource_spec.rb index 2c40588..f09503e 100644 --- a/spec/cancan/controller_resource_spec.rb +++ b/spec/cancan/controller_resource_spec.rb @@ -268,14 +268,14 @@ describe CanCan::ControllerResource do @controller.instance_variable_get(:@project).should == :some_project end - it "should build record through has_one association with :singleton option" do + it "should not build record through has_one association with :singleton option because it can cause it to delete it in the database" do @params.merge!(:action => "create", :project => {:name => "foobar"}) - category = Object.new + category = Category.new @controller.instance_variable_set(:@category, category) - stub(category).build_project { |attributes| Project.new(attributes) } resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true) resource.load_resource @controller.instance_variable_get(:@project).name.should == "foobar" + @controller.instance_variable_get(:@project).category.should == category end it "should find record through has_one association with :singleton and :shallow options" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7e7a55e..f682c30 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -29,4 +29,5 @@ end class Project < SuperModel::Base belongs_to :category + attr_accessor :category # why doesn't SuperModel do this automatically? end