OSDN Git Service

t30350#:fix destroy
authoryasushiito <yas@pen-chan.jp>
Mon, 24 Dec 2012 00:49:38 +0000 (09:49 +0900)
committeryasushiito <yas@pen-chan.jp>
Mon, 24 Dec 2012 00:49:38 +0000 (09:49 +0900)
22 files changed:
app/controllers/comics_controller.rb
app/controllers/panels_controller.rb
app/controllers/resource_pictures_controller.rb
app/controllers/stories_controller.rb
app/models/author.rb
app/models/comic.rb
app/models/panel.rb
app/models/resource_picture.rb
app/models/story.rb
app/models/user.rb
app/views/home/comic.html.erb
app/views/home/panel.html.erb
app/views/stories/show.html.erb
config/routes.rb
spec/controllers/comics_controller_spec.rb
spec/controllers/panels_controller_spec.rb
spec/controllers/resource_pictures_controller_spec.rb
spec/controllers/stories_controller_spec.rb
spec/models/comic_spec.rb
spec/models/panel_spec.rb
spec/models/resource_picture_spec.rb
spec/models/story_spec.rb

index b68a578..d57a084 100644 (file)
@@ -15,8 +15,6 @@ class ComicsController < ApplicationController
     end
   end
   
-  # GET /comics
-  # GET /comics.json
   def index
     @page = Comic.page params[:page]
     @page_size = Comic.page_size params[:page_size]
@@ -27,8 +25,6 @@ class ComicsController < ApplicationController
     end
   end
 
-  # GET /comics/1
-  # GET /comics/1.json
   def show
     @comic = Comic.show(params[:id], @author)
 
@@ -63,8 +59,6 @@ class ComicsController < ApplicationController
     end
   end
   
-  # GET /comics/new
-  # GET /comics/new.js
   def new
     @comic = Comic.new
     @comic.supply_default
@@ -75,8 +69,6 @@ class ComicsController < ApplicationController
     end
   end
 
-  # GET /comics/1/edit
-  # GET /comics/1.js/edit
   def edit
     @comic = Comic.edit(params[:id], @author)
     respond_to do |format|
@@ -85,8 +77,6 @@ class ComicsController < ApplicationController
     end
   end
 
-  # POST /comics
-  # POST /comics.json
   def create
     @comic = Comic.new
     @comic.supply_default 
@@ -105,8 +95,6 @@ class ComicsController < ApplicationController
     end
   end
 
-  # PUT /comics/1
-  # PUT /comics/1.json
   def update
     @comic = Comic.edit(params[:id], @author)
     @comic.attributes = params[:comic]
@@ -123,14 +111,18 @@ class ComicsController < ApplicationController
     end
   end
 
-  # DELETE /comics/1
-  # DELETE /comics/1.json
   def destroy
     @comic = Comic.edit(params[:id], @author)
-    @comic.destroy
     respond_to do |format|
-      format.html { redirect_to comics_url }
-      format.json { head :ok }
+      if @comic.destroy_with_story
+        flash[:notice] = I18n.t('flash.notice.destroyed', :model => Comic.model_name.human)
+        format.html { redirect_to '/home/comic' }
+        format.json { head :ok }
+      else
+        flash[:notice] = I18n.t('flash.notice.not_destroyed', :model => Comic.model_name.human)
+        format.html { redirect_to @comic }
+        format.json { render json: @comic.errors, status: :unprocessable_entity }
+      end
     end
   end
 end
index c2bc788..7d5e4e6 100644 (file)
@@ -115,9 +115,15 @@ class PanelsController < ApplicationController
     @panel = Panel.edit(params[:id], @author)
     respond_to do |format|
       Panel.transaction do
-        @panel.destroy
-        format.html { redirect_to panels_url }
-        format.json { head :ok }
+        if @panel.destroy_with_elements
+          flash[:notice] = I18n.t('flash.notice.destroyed', :model => Panel.model_name.human)
+          format.html { redirect_to '/home/panel' }
+          format.json { head :ok }
+        else
+          flash[:notice] = I18n.t('flash.notice.not_destroyed', :model => Panel.model_name.human)
+          format.html { redirect_to @panel }
+          format.json { render json: @panel.errors, status: :unprocessable_entity }
+        end
       end
     end
   end
index 87ce3c7..3fd04cb 100644 (file)
@@ -95,7 +95,7 @@ class ResourcePicturesController < ApplicationController
         format.html { redirect_to resource_pictures_path }
         format.json { head :ok }
       else
-        format.html { render resource_picture_path(@resource_picture) }
+        format.html { redirect_to resource_picture_path(@resource_picture) }
         format.json { render json: @resource_picture.errors, status: :unprocessable_entity }
       end
     end
index e13a7d3..3832ea5 100644 (file)
@@ -119,12 +119,16 @@ class StoriesController < ApplicationController
 
   def destroy
     @story = Story.edit(params[:id], @author)
-    Story.transaction do
-      @story.destroy_and_shorten
-    end
     respond_to do |format|
-      format.html { redirect_to story_path(@story.comic) }
-      format.json { head :ok }
+      if @story.destroy_and_shorten
+        flash[:notice] = I18n.t('flash.notice.destroyed', :model => Story.model_name.human)
+        format.html { redirect_to :controller => 'stories', :action => :comic, :id => @story.comic_id }
+        format.json { head :ok }
+      else
+        flash[:notice] = I18n.t('flash.notice.not_destroyed', :model => Story.model_name.human)
+        format.html { redirect_to story_path(@story) }
+        format.json { render json: @story.errors, status: :unprocessable_entity }
+      end
     end
   end
 end
index 83db8dc..d574bae 100644 (file)
@@ -1,6 +1,8 @@
 class Author < ActiveRecord::Base
   has_one :artist
   belongs_to :user
+  has_many :comic
+  has_many :panel
   
   validates :name, :presence => true, :length => {:maximum => 30}
   validates :user_id, :numericality => true, :existence => {:both => false}
index f32b0bd..e9b1298 100644 (file)
@@ -112,4 +112,16 @@ class Comic < ActiveRecord::Base
     Comic.count 'visible > 0'
   end
   
+  def destroy_with_story
+    res = false
+    Comic.transaction do
+      self.stories.each do |story|
+        raise ActiveRecord::Rollback unless story.destroy
+      end
+      raise ActiveRecord::Rollback unless self.destroy
+      res = true
+    end
+    res
+  end
+  
 end
index 3e7e93c..1d87d74 100644 (file)
@@ -266,6 +266,18 @@ class Panel < ActiveRecord::Base
     res
   end
   
+  def destroy_with_elements
+    res = false
+    Panel.transaction do
+      self.panel_elements.each do |element|
+        raise ActiveRecord::Rollback unless element.destroy
+      end
+      raise ActiveRecord::Rollback unless self.destroy
+      res = true
+    end
+    res
+  end
+  
 =begin
   def self.validate_id ary, pid
     ary.map {|v|
index c8bd3f7..757140a 100644 (file)
@@ -205,13 +205,20 @@ class ResourcePicture < ActiveRecord::Base
   end
   
   def unpublish
-    r = true
+    res = false
     ResourcePicture.transaction do
-      self.destroy
-      PictureIO.resource_picture_io.delete(self.filename)
-      PictureIO.resource_picture_io.delete(self.filename, 'full')
+      begin
+        if res = self.destroy
+          PictureIO.resource_picture_io.delete(self.filename)
+          PictureIO.resource_picture_io.delete(self.filename, 'full')
+          res = true
+        end
+      rescue PictureIO::Error
+        res = false
+        raise ActiveRecord::Rollback
+      end
     end
-    r
+    res
   end
   
   def self.visible_count
index d67ac9d..b4c609c 100644 (file)
@@ -280,10 +280,13 @@ class Story < ActiveRecord::Base
   end
   
   def destroy_and_shorten
+    res = false
     Story.transaction do
       Story.update_all('t = t - 1', ['comic_id = ? and (t > ?)', self.comic_id, self.t])
       raise ActiveRecord::Rollback unless self.destroy
+      res = true
     end
+    res
   end
   
   
index 90958af..54ee43d 100644 (file)
@@ -19,4 +19,20 @@ class User < ActiveRecord::Base
     self.save
   end
   
+  def destroy
+    res = false
+    User.transaction do
+      self.author.comics.each do |comic|
+        raise ActiveRecord::Rollback unless comic.destroy_with_story
+      end
+      self.author.panels.each do |panel|
+        raise ActiveRecord::Rollback unless panel.destroy_with_elements
+      end
+      raise ActiveRecord::Rollback unless self.author.destroy
+      raise ActiveRecord::Rollback unless self.destroy
+      res = true
+    end
+    res
+  end
+  
 end
index 3f90c92..c304a54 100644 (file)
@@ -1,4 +1,5 @@
 <h1><%= t '.title' -%></h1>
+<p id="notice"><%= notice %></p>
 
 <table>
   <% @comics.each do |comic| %>
index fb572ad..e95104b 100644 (file)
@@ -1,4 +1,5 @@
 <h1><%= t '.title' -%></h1>
+<p id="notice"><%= notice %></p>
 
 <% @panels.each do |panel| %>
   <div>
index 871fd95..fa0c3a0 100644 (file)
@@ -34,6 +34,7 @@
 </p>
 <% if @story.own? @author -%>
   <%= link_to t('link.edit'), edit_story_path(@story) %>
+  <%= link_to t('link.destroy'), story_path(@story), :method => :delete %>
 <% end %>
 
 <hr>
index 48a716e..e5c5ca4 100644 (file)
@@ -211,6 +211,7 @@ Pettanr::Application.routes.draw do
       get :list
     end
     member do
+      get :comic
       put :update
       delete :destroy
       get :browse
index 9efd0e0..80fd23e 100644 (file)
@@ -601,5 +601,108 @@ describe ComicsController do
     end\r
   end\r
 \r
+  describe '削除に於いて' do\r
+    before do\r
+      @comic = FactoryGirl.create :comic, :author => @author\r
+      sign_in @user\r
+    end\r
+    context '事前チェックしておく' do\r
+      before do\r
+        Comic.stub(:edit).with(any_args()).and_return @comic\r
+        Comic.any_instance.stub(:destroy_with_story).with(any_args()).and_return(true)\r
+      end\r
+      it 'コミックモデルに編集取得を問い合わせている' do\r
+        Comic.should_receive(:edit).exactly(1)\r
+        delete :destroy, :id => @comic.id\r
+      end\r
+      it 'モデルに削除を依頼する' do\r
+        Comic.any_instance.should_receive(:destroy_with_story).exactly(1)\r
+        delete :destroy, :id => @comic.id\r
+      end\r
+      it '@comicにアレを取得している' do\r
+        delete :destroy, :id => @comic.id\r
+        assigns(:comic).id.should eq(@comic.id)\r
+      end\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it '削除される' do\r
+        lambda {\r
+          delete :destroy, :id => @comic.id\r
+        }.should change Comic, :count\r
+      end\r
+      context 'html形式' do\r
+        before do\r
+          Comic.any_instance.stub(:destroy_with_story).with(any_args()).and_return(true)\r
+        end\r
+        it 'ステータスコード302 Foundを返す' do\r
+          delete :destroy, :id => @comic.id\r
+          response.status.should eq 302\r
+        end\r
+        it 'マイコミックの一覧ページへ遷移する' do\r
+          delete :destroy, :id => @comic.id\r
+          response.should redirect_to('/home/comic')\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        before do\r
+          Comic.any_instance.stub(:destroy_with_story).with(any_args()).and_return(true)\r
+        end\r
+        it 'ステータスコード200 OKを返す' do\r
+          delete :destroy, :id => @comic.id, :format => :json\r
+          response.should be_success \r
+        end\r
+        it 'ページ本体は特に返さない' do\r
+          delete :destroy, :id => @comic.id, :format => :json\r
+          response.body.should match /./\r
+        end\r
+      end\r
+    end\r
+    context '作家権限がないとき' do\r
+      before do\r
+        sign_out @user\r
+      end\r
+      it 'ステータスコード302 Foundを返す' do\r
+        delete :destroy, :id => @comic.id\r
+        response.status.should eq 302\r
+      end\r
+      context 'html形式' do\r
+        it 'サインインページへ遷移する' do\r
+          delete :destroy, :id => @comic.id\r
+          response.body.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          delete :destroy, :id => @comic.id, :format => :json\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
+    end\r
+    context '削除に失敗したとき' do\r
+      before do\r
+        Comic.any_instance.stub(:destroy_with_story).and_return(false)\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          delete :destroy, :id => @comic.id\r
+          response.status.should eq 302\r
+        end\r
+        it 'そのコミックの詳細ページへ遷移する' do\r
+          delete :destroy, :id => @comic.id\r
+          response.should redirect_to(comic_path(@comic))\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード422 unprocessable_entity を返す' do\r
+          delete :destroy, :id => @comic.id, :format => :json\r
+          response.status.should eq 422\r
+        end\r
+        it '応答メッセージUnprocessable Entityを返す' do\r
+          delete :destroy, :id => @comic.id, :format => :json\r
+          response.message.should match(/Unprocessable/)\r
+        end\r
+      end\r
+    end\r
+  end\r
 \r
 end\r
index f9bfacd..a75ad3f 100644 (file)
@@ -646,7 +646,7 @@ describe PanelsController do
         delete :destroy, :id => @panel.id\r
         assigns(:panel).id.should eq(@panel.id)\r
       end\r
-      it 'そのコマを一つのトランザクションで削除する' do\r
+      it 'そのコマを削除する' do\r
         lambda {\r
           delete :destroy, :id => @panel.id\r
         }.should change(Panel, :count)\r
@@ -656,9 +656,9 @@ describe PanelsController do
           delete :destroy, :id => @panel.id\r
           response.status.should eq 302\r
         end\r
-        it 'コマ一覧ページへ遷移する' do\r
+        it 'ã\83\9eã\82¤ã\82³ã\83\9eä¸\80覧ã\83\9aã\83¼ã\82¸ã\81¸é\81·ç§»ã\81\99ã\82\8b' do\r
           delete :destroy, :id => @panel.id\r
-          response.should redirect_to(panels_url)\r
+          response.should redirect_to('/home/panel')\r
         end\r
       end\r
       context 'json形式' do\r
@@ -693,6 +693,31 @@ describe PanelsController do
         end\r
       end\r
     end\r
+    context '削除に失敗したとき' do\r
+      before do\r
+        Panel.any_instance.stub(:destroy_with_elements).and_return(false)\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          delete :destroy, :id => @panel.id\r
+          response.status.should eq 302\r
+        end\r
+        it 'そのコマの詳細ページへ遷移する' do\r
+          delete :destroy, :id => @panel.id\r
+          response.should redirect_to(panel_path(@panel))\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード422 unprocessable_entity を返す' do\r
+          delete :destroy, :id => @panel.id, :format => :json\r
+          response.status.should eq 422\r
+        end\r
+        it '応答メッセージUnprocessable Entityを返す' do\r
+          delete :destroy, :id => @panel.id, :format => :json\r
+          response.message.should match(/Unprocessable/)\r
+        end\r
+      end\r
+    end\r
 =begin\r
     context '対象コマがないとき' do\r
     end\r
index 86ce8a1..09a0e25 100644 (file)
@@ -874,4 +874,109 @@ describe ResourcePicturesController do
     end
   end
   
+  describe '削除に於いて' do
+    before do
+      @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+      @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id
+      sign_in @user
+    end
+    context '事前チェックしておく' do
+      before do
+        ResourcePicture.stub(:edit).with(any_args()).and_return @rp
+        ResourcePicture.any_instance.stub(:unpublish).with(any_args()).and_return(true)
+      end
+      it '素材モデルに編集取得を問い合わせている' do
+        ResourcePicture.should_receive(:edit).exactly(1)
+        delete :destroy, :id => @rp.id
+      end
+      it 'モデルに削除を依頼する' do
+        ResourcePicture.any_instance.should_receive(:unpublish).exactly(1)
+        delete :destroy, :id => @rp.id
+      end
+      it '@resource_pictureにアレを取得している' do
+        delete :destroy, :id => @rp.id
+        assigns(:resource_picture).id.should eq(@rp.id)
+      end
+    end
+    context 'つつがなく終わるとき' do
+      it '削除される' do
+        lambda {
+          delete :destroy, :id => @rp.id
+        }.should change ResourcePicture, :count
+      end
+      context 'html形式' do
+        before do
+          ResourcePicture.any_instance.stub(:unpublish).with(any_args()).and_return(true)
+        end
+        it 'ステータスコード302 Foundを返す' do
+          delete :destroy, :id => @rp.id
+          response.status.should eq 302
+        end
+        it 'マイ素材の一覧ページへ遷移する' do
+          delete :destroy, :id => @rp.id
+          response.should redirect_to('/home/resource_picture')
+        end
+      end
+      context 'json形式' do
+        before do
+          ResourcePicture.any_instance.stub(:unpublish).with(any_args()).and_return(true)
+        end
+        it 'ステータスコード200 OKを返す' do
+          delete :destroy, :id => @rp.id, :format => :json
+          response.should be_success 
+        end
+        it 'ページ本体は特に返さない' do
+          delete :destroy, :id => @rp.id, :format => :json
+          response.body.should match /./
+        end
+      end
+    end
+    context '作家権限がないとき' do
+      before do
+        sign_out @user
+      end
+      it 'ステータスコード302 Foundを返す' do
+        delete :destroy, :id => @rp.id
+        response.status.should eq 302
+      end
+      context 'html形式' do
+        it 'サインインページへ遷移する' do
+          delete :destroy, :id => @rp.id
+          response.body.should redirect_to '/users/sign_in'
+        end
+      end
+      context 'json形式' do
+        it '応答メッセージにUnauthorizedを返す' do
+          delete :destroy, :id => @rp.id, :format => :json
+          response.message.should match(/Unauthorized/)
+        end
+      end
+    end
+    context '削除に失敗したとき' do
+      before do
+        ResourcePicture.any_instance.stub(:unpublish).and_return(false)
+      end
+      context 'html形式' do
+        it 'ステータスコード302 Foundを返す' do
+          delete :destroy, :id => @rp.id
+          response.status.should eq 302
+        end
+        it 'その素材の詳細ページへ遷移する' do
+          delete :destroy, :id => @rp.id
+          response.should redirect_to(resource_picture_path(@rp))
+        end
+      end
+      context 'json形式' do
+        it 'ステータスコード422 unprocessable_entity を返す' do
+          delete :destroy, :id => @rp.id, :format => :json
+          response.status.should eq 422
+        end
+        it '応答メッセージUnprocessable Entityを返す' do
+          delete :destroy, :id => @rp.id, :format => :json
+          response.message.should match(/Unprocessable/)
+        end
+      end
+    end
+  end
+
 end
index 2b325ed..974e0f9 100644 (file)
@@ -685,28 +685,36 @@ describe StoriesController do
       sign_in @user
       Story.stub(:edit).and_return(@story)
     end
-    context 'つつがなく終わるとき' do
+    context '事前チェックしておく' do
+      before do
+        Story.stub(:edit).with(any_args()).and_return @story
+        Story.any_instance.stub(:destroy_and_shorten).with(any_args()).and_return(true)
+      end
       it 'ストーリーモデルに編集取得を問い合わせている' do
         Story.should_receive(:edit).exactly(1)
         delete :destroy, :id => @story.id
       end
+      it 'モデルに削除を依頼する' do
+        Story.any_instance.should_receive(:destroy_and_shorten).exactly(1)
+        delete :destroy, :id => @story.id
+      end
       it '@storyにアレを取得している' do
         delete :destroy, :id => @story.id
         assigns(:story).id.should eq(@story.id)
       end
-      it 'そのストーリーを一つのトランザクションで削除する' do
-        lambda {
-          delete :destroy, :id => @story.id
-        }.should change(Story, :count)
+    end
+    context 'つつがなく終わるとき' do
+      before do
+        Story.any_instance.stub(:destroy_and_shorten).with(any_args()).and_return(true)
       end
       context 'html形式' do
         it 'ステータスコード302 Foundを返す' do
           delete :destroy, :id => @story.id
           response.status.should eq 302
         end
-        it 'ストーリー一覧ページへ遷移する' do
+        it '覧ページへ遷移する' do
           delete :destroy, :id => @story.id
-          response.should redirect_to(story_path(@story.comic_id))
+          response.should redirect_to(:controller => 'stories', :action => :comic, :id => @story.comic_id)
         end
       end
       context 'json形式' do
@@ -741,6 +749,31 @@ describe StoriesController do
         end
       end
     end
+    context '削除に失敗したとき' do
+      before do
+        Story.any_instance.stub(:destroy_and_shorten).with(any_args()).and_return(false)
+      end
+      context 'html形式' do
+        it 'ステータスコード302 Foundを返す' do
+          delete :destroy, :id => @story.id
+          response.status.should eq 302
+        end
+        it 'そのコミックの詳細ページへ遷移する' do
+          delete :destroy, :id => @story.id
+          response.should redirect_to(story_path(@story))
+        end
+      end
+      context 'json形式' do
+        it 'ステータスコード422 unprocessable_entity を返す' do
+          delete :destroy, :id => @story.id, :format => :json
+          response.status.should eq 422
+        end
+        it '応答メッセージUnprocessable Entityを返す' do
+          delete :destroy, :id => @story.id, :format => :json
+          response.message.should match(/Unprocessable/)
+        end
+      end
+    end
 =begin
     context '対象ストーリーがないとき' do
     end
index b0c740e..78a6f7a 100644 (file)
@@ -489,4 +489,53 @@ describe Comic do
       i.has_key?('author').should be_true
     end
   end
+  
+  describe '削除に於いて' do
+    before do
+      @comic = FactoryGirl.create :comic, :author_id => @author.id
+      @panel = FactoryGirl.create :panel, :author_id => @author.id, :publish => 1
+      @story = FactoryGirl.create :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+      @other_comic = FactoryGirl.create :comic, :author_id => @author.id
+      @other_story = FactoryGirl.create :story, :author_id => @author.id, :comic_id => @other_comic.id, :panel_id => @panel.id
+    end
+    context 'つつがなく終わるとき' do
+      it '自身を削除する' do
+        lambda {
+          r = @comic.destroy_with_story
+        }.should change(Comic, :count).by(-1)
+        lambda {
+          r = Comic.find @comic.id
+        }.should raise_error
+      end
+      it '自身にリンクしているストーリーをすべて削除する' do
+        lambda {
+          r = @comic.destroy_with_story
+        }.should change(Story, :count).by(-1)
+        lambda {
+          r = Story.find @story.id
+        }.should raise_error
+      end
+      it 'Trueを返す' do
+        r = @comic.destroy_with_story
+        r.should be_true
+      end
+    end
+    context '削除に失敗したとき' do
+      before do
+        Story.any_instance.stub(:destroy).with(any_args).and_return(false)
+      end
+      it 'Falseを返す' do
+        r = @comic.destroy_with_story
+        r.should be_false
+      end
+      it 'ロールバックしている' do
+        lambda {
+          r = @comic.destroy_with_story
+        }.should_not change(Comic, :count)
+        lambda {
+          r = @comic.destroy_with_story
+        }.should_not change(Story, :count)
+      end
+    end
+  end
 end
index ea6374b..b319970 100644 (file)
@@ -1163,6 +1163,73 @@ describe Panel do
       end\r
     end\r
   end\r
+  \r
+  describe '削除に於いて' do\r
+    before do\r
+      @comic = FactoryGirl.create :comic, :author_id => @author.id\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id, :publish => 1\r
+      @pp = FactoryGirl.create :panel_picture, :panel_id => @panel.id, :t => 1, :width => @p.width, :height => @p.height\r
+      @sb = @panel.speech_balloons.create(\r
+        FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 0)\r
+      )\r
+      @gc = @panel.ground_colors.create(\r
+        FactoryGirl.attributes_for(:ground_color, :panel_id => @panel.id, :color_id => @color.id)\r
+      )\r
+      @gp = @panel.ground_pictures.create(\r
+        FactoryGirl.attributes_for(:ground_picture, :panel_id => @panel.id, :picture_id => @p.id)\r
+      )\r
+      @pc = @panel.panel_colors.create(\r
+        FactoryGirl.attributes_for(:panel_color, :panel_id => @panel.id, :code => 0xff0000)\r
+      )\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it '自身を削除する' do\r
+        lambda {\r
+          r = @panel.destroy_with_elements\r
+        }.should change(Panel, :count).by(-1)\r
+        lambda {\r
+          r = Panel.find @panel.id\r
+        }.should raise_error\r
+      end\r
+      it '自身にリンクしているコマ要素をすべて削除する' do\r
+        lambda {\r
+          r = @panel.destroy_with_elements\r
+        }.should change(PanelPicture, :count).by(-1)\r
+        lambda {\r
+          r = PanelPicture.find @pp.id\r
+        }.should raise_error \r
+      end\r
+      it '自身にリンクしているコマ要素をすべて削除する' do\r
+        lambda {\r
+          r = @panel.destroy_with_elements\r
+        }.should change(GroundPicture, :count).by(-1)\r
+        lambda {\r
+          r = GroundPicture.find @gp.id\r
+        }.should raise_error \r
+      end\r
+      it 'Trueを返す' do\r
+        r = @panel.destroy_with_elements\r
+        r.should be_true\r
+      end\r
+    end\r
+    context '削除に失敗したとき' do\r
+      before do\r
+        PanelPicture.any_instance.stub(:destroy).with(any_args).and_return(false)\r
+      end\r
+      it 'Falseを返す' do\r
+        r = @panel.destroy_with_elements\r
+        r.should be_false\r
+      end\r
+      it 'ロールバックしている' do\r
+        lambda {\r
+          r = @panel.destroy_with_elements\r
+        }.should_not change(Panel, :count)\r
+        lambda {\r
+          r = @panel.destroy_with_elements\r
+        }.should_not change(PanelPicture, :count)\r
+      end\r
+    end\r
+  end\r
 =begin\r
   describe 'id挿げ替え防止確認に於いて' do\r
     before do\r
index f614348..2dd12d7 100644 (file)
@@ -968,6 +968,91 @@ describe ResourcePicture do
     \r
   end\r
   \r
+  describe '公開停止に於いて' do\r
+    before do\r
+      @op = FactoryGirl.create :original_picture, :artist_id => @artist.id\r
+      @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id\r
+      @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id\r
+    end\r
+    context '事前チェックしておく' do\r
+      before do\r
+        ResourcePicture.any_instance.stub(:destroy).and_return(true)\r
+        PictureIO.resource_picture_io.stub(:delete).with(@rp.filename).and_return(true)\r
+        PictureIO.resource_picture_io.stub(:delete).with(@rp.filename, 'full').and_return(true)\r
+      end\r
+      it '素材モデルに削除を依頼している' do\r
+        ResourcePicture.any_instance.should_receive(:destroy).exactly(1)\r
+        r = @rp.unpublish\r
+      end\r
+      it '保管庫にサムネイルの画像データ削除を依頼している' do\r
+        PictureIO.resource_picture_io.should_receive(:delete).with(@rp.filename).exactly(1)\r
+        r = @rp.unpublish\r
+      end\r
+      it '保管庫にフルサイズの画像データ削除を依頼している' do\r
+        PictureIO.resource_picture_io.should_receive(:delete).with(@rp.filename, 'full').exactly(1)\r
+        r = @rp.unpublish\r
+      end\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it '自身を削除する' do\r
+        lambda {\r
+          r = @rp.unpublish\r
+        }.should change(ResourcePicture, :count).by(-1)\r
+        lambda {\r
+          r = ResourcePicture.find @rp.id\r
+        }.should raise_error\r
+      end\r
+      it 'Trueを返す' do\r
+        r = @rp.unpublish\r
+        r.should be_true\r
+      end\r
+    end\r
+    context '自身の削除に失敗したとき' do\r
+      before do\r
+        ResourcePicture.any_instance.stub(:destroy).with(any_args).and_return(false)\r
+      end\r
+      it 'Falseを返す' do\r
+        r = @rp.unpublish\r
+        r.should be_false\r
+      end\r
+      it 'ロールバックしている' do\r
+        lambda {\r
+          r = @rp.unpublish\r
+        }.should_not change(ResourcePicture, :count)\r
+      end\r
+    end\r
+    context 'サムネイル画像の削除に失敗したとき' do\r
+      before do\r
+        PictureIO.resource_picture_io.stub(:delete).with(@rp.filename).and_raise(PictureIO::Error)\r
+        PictureIO.resource_picture_io.stub(:delete).with(@rp.filename, 'full').and_return(true)\r
+      end\r
+      it 'Falseを返す' do\r
+        r = @rp.unpublish\r
+        r.should be_false\r
+      end\r
+      it 'ロールバックしている' do\r
+        lambda {\r
+          r = @rp.unpublish\r
+        }.should_not change(ResourcePicture, :count)\r
+      end\r
+    end\r
+    context 'フルサイズ画像の削除に失敗したとき' do\r
+      before do\r
+        PictureIO.resource_picture_io.stub(:delete).with(@rp.filename).and_return(true)\r
+        PictureIO.resource_picture_io.stub(:delete).with(@rp.filename, 'full').and_raise(PictureIO::Error)\r
+      end\r
+      it 'Falseを返す' do\r
+        r = @rp.unpublish\r
+        r.should be_false\r
+      end\r
+      it 'ロールバックしている' do\r
+        lambda {\r
+          r = @rp.unpublish\r
+        }.should_not change(ResourcePicture, :count)\r
+      end\r
+    end\r
+  end\r
+  \r
   describe 'クレジットデータに於いて' do\r
     before do\r
       @op = FactoryGirl.create :original_picture, :artist_id => @artist.id\r
index f1a1646..06a8f84 100644 (file)
@@ -1697,6 +1697,24 @@ describe Story do
           @story.destroy_and_shorten
         }.should change(Story, :count ).by(-1)
       end
+      it 'Trueを返す' do
+        r = @story.destroy_and_shorten
+        r.should be_true 
+      end
+    end
+    context '削除に失敗したとき' do
+      before do
+        Story.any_instance.stub(:destroy).and_return(false)
+      end
+      it 'ロールバックされる' do
+        lambda{
+          @story.destroy_and_shorten
+        }.should_not change(Story, :count )
+      end
+      it 'Falseを返す' do
+        r = @story.destroy_and_shorten
+        r.should be_false
+      end
     end
     #連携テスト。切り詰めが直接DBをいじる
     context '2件で先頭を削除したとき' do