From: yasushiito Date: Mon, 16 Jul 2012 07:58:47 +0000 (+0900) Subject: add story X-Git-Url: http://git.osdn.net/view?p=pettanr%2Fpettanr.git;a=commitdiff_plain;h=23e207bfdfb2ec90bb81f382d4b0eaf28f96ea4b add story --- diff --git a/app/controllers/comics_controller.rb b/app/controllers/comics_controller.rb index 25b00eb3..7a033ee5 100644 --- a/app/controllers/comics_controller.rb +++ b/app/controllers/comics_controller.rb @@ -1,4 +1,5 @@ class ComicsController < ApplicationController + layout 'test' if Pettanr::TestLayout if Const.run_mode == 0 before_filter :authenticate_user!, :only => [:new, :create, :edit, :update, :destroy] else @@ -57,23 +58,6 @@ class ComicsController < ApplicationController end end - def play - c = Comic.show(params[:id], @author) - cnt = Panel.count(:conditions => ['comic_id = ?', c.id]).to_i - @offset = Comic.offset cnt, params[:offset] - @panel_count = Comic.panel_count cnt, params[:count] - @comic = Comic.play(params[:id]) - respond_to do |format| - format.html # index.html.erb - format.json { - render :json => @comic.to_json_play - } - format.jsonp { - render :json => "callback(" + @comic.to_json_play + ");" - } - end - end - def list @comics = Comic.all diff --git a/app/controllers/stories_controller.rb b/app/controllers/stories_controller.rb index 49799e09..376536e9 100644 --- a/app/controllers/stories_controller.rb +++ b/app/controllers/stories_controller.rb @@ -1,2 +1,120 @@ class StoriesController < ApplicationController + layout 'test' if Pettanr::TestLayout + if Const.run_mode == 0 + before_filter :authenticate_user!, :only => [:new, :create, :edit, :update, :destroy] + else + before_filter :authenticate_user!, :only => [:index, :show, :new, :create, :edit, :update, :destroy] + end + before_filter :authenticate_admin!, :only => [:list, :browse] + + def show + @comic = Comic.show(params[:id], @author) + cnt = Story.count(:conditions => ['comic_id = ?', @comic.id]).to_i + @offset = Story.offset cnt, params[:offset] + @panel_count = Story.panel_count cnt, params[:count] + @stories = Story.list(@comic, @author, @offset, @panel_count) + respond_to do |format| + format.html # index.html.erb + format.json { + render :json => @stories.to_json_list + } + format.jsonp { + render :json => "callback(" + @stories.to_json_list + ");" + } + end + end + + def list + @stories = Story.all + + respond_to do |format| + format.html { render layout: 'system' }# index.html.erb + format.json { render json: @stories } + end + end + + def browse + @story = Story.find(params[:id]) + + respond_to do |format| + format.html { render layout: 'system' } # show.html.erb + format.json { render json: @story } + end + end + + # GET /stories/new + # GET /stories/new.js + # GET /stories/new.json + def new + @story = Story.new + @story.supply_default @author + @form_opt = {} + respond_to do |format| + format.html # new.html.erb + format.js { @form_opt = {:remote => true} ; render action: "new" } + format.json { render json: @story } + end + end + + # GET /stories/1/edit + # GET /stories/1.js/edit + def edit + @story = Story.show(params[:id], @author) + respond_to do |format| + format.html + format.js + end + end + + # POST /stories + # POST /stories.js + # POST /stories.json + def create + @story = Story.new + @story.supply_default @author + @story.attributes = params[:story] + + respond_to do |format| + if @story.store + format.html { redirect_to action: :show, id: @story.comic_id } + format.js { redirect_to action: :show, id: @story.comic_id } + format.json { render json: @story.to_json() } + else + format.html { render action: "new" } + format.json { render json: @story.errors, status: :unprocessable_entity } + end + end + end + + # PUT /stories/1 + # PUT /stories/1.js + # PUT /stories/1.json + def update + @story = Story.show(params[:id], @author) + @story.author_id = @author.id + ot = @story.t + @story.attributes = params[:story] + respond_to do |format| + if @story.store ot + format.html { redirect_to action: :show, id: @story.comic_id } + format.js { redirect_to action: :show, id: @story.comic_id } + format.json { head :ok } + else + format.html { render action: "edit" } + format.json { render json: @story.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /stories/1 + # DELETE /stories/1.js + # DELETE /stories/1.json + def destroy + @story = Story.show(params[:id], @author) + @story.destroy_and_shorten + respond_to do |format| + format.html { redirect_to story_path(@story.comic) } + format.json { head :ok } + end + end end diff --git a/app/models/comic.rb b/app/models/comic.rb index e8cd7a5a..c036b786 100644 --- a/app/models/comic.rb +++ b/app/models/comic.rb @@ -102,20 +102,6 @@ class Comic < ActiveRecord::Base {:include => {:stories => {:panel => {}}, :author => {}}} end - def self.play cid, opt = {} - Comic.find(cid, include: [ - :author, - :panels => [ - :panel_pictures => :resource_picture, - :speech_balloons =>{:balloons => {}, :speeches => {}} - ] - ], order: 'panels.t') - end - - def to_json_play - self.to_json( :include => {:author => {}, :panels => {:methods => :panel_element}}) - end - def self.visible_count Comic.count 'visible > 0' end diff --git a/app/models/panel.rb b/app/models/panel.rb index cdd905f3..ecaa027a 100644 --- a/app/models/panel.rb +++ b/app/models/panel.rb @@ -193,6 +193,10 @@ class Panel < ActiveRecord::Base self.author_id == author.id end + def usable? au + own? au + end + def publish? self.publish > 0 end diff --git a/app/models/story.rb b/app/models/story.rb index 0f240aa1..7ae9f3aa 100644 --- a/app/models/story.rb +++ b/app/models/story.rb @@ -10,10 +10,24 @@ class Story < ActiveRecord::Base validates :t, :presence => true, :numericality => {:greater_than_or_equal_to => 0} def supply_default au + self.t = nil return false unless au self.author_id = au.id end + def own? author + return false unless author + self.author_id == author.id + end + + def self.show sid, au = nil + res = Story.find sid + if au + raise ActiveRecord::Forbidden unless res.own?(au) + end + res + end + def self.new_t comic_id r = Story.max_t(comic_id) r.blank? ? 0 : r.to_i + 1 @@ -84,36 +98,95 @@ class Story < ActiveRecord::Base end end + def allow? + c = self.comic + pl = self.panel + c and c.own?(self.author) and pl and pl.usable?(self.author) + end + def store old_t = nil res = false + raise ActiveRecord::Forbidden unless self.allow? Story.transaction do self.rotate old_t res = self.save - unless Story.validate_t(self) - res = false + raise ActiveRecord::Rollback unless res + res = Story.validate_t(self) + unless res + self.errors.add :t, 'unserialized' raise ActiveRecord::Rollback end end res end - def move_to new_t - return true if self.t == new_t - if self.t > new_t - Panel.update_all('t = t + 1', ['comic_id = ? and (t >= ? and t < ?)', self.comic_id, new_t, self.t]) - else - nf = Panel.find_t(self.comic_id, new_t) - max_t = Panel.max_t.to_i self.comic_id - new_t = max_t if new_t > max_t - Panel.update_all('t = t - 1', ['comic_id = ? and (t > ? and t <= ?)', self.comic_id, self.t, new_t]) + def destroy_and_shorten + Story.transaction do + Story.update_all('t = t - 1', ['comic_id = ? and (t > ?)', self.comic_id, self.t]) + raise ActiveRecord::Rollback unless self.destroy end - self.t = new_t - self.save end - def destroy_and_shorten - Panel.update_all('t = t - 1', ['comic_id = ? and (t > ?)', self.comic_id, self.t]) - self.destroy + def self.default_panel_size + 30 + end + + def self.max_panel_size + 200 end + def self.offset cnt, prm = nil + offset = prm.to_i + offset = cnt - 1 if offset >= cnt + offset = cnt - offset.abs if offset < 0 + offset = 0 if offset < 0 + offset + end + + def self.panel_count cnt, prm = self.default_panel_size + count = prm.to_i + count = self.max_panel_size if count > self.max_panel_size + count = self.default_panel_size if count < 1 + count + end + + def self.list comic, author, offset = 0, limit = Story.default_panel_size + opt = self.list_opt + opt.merge!({:conditions => ['stories.comic_id = ?', comic.id], :order => 'stories.t', :offset => offset, :limit => limit}) + Story.find(:all, opt) + end + + def self.list_opt + {:include => { + :author => {}, + :comic => { + :author => {} + }, + :panel => { + :author => {}, + :panel_pictures => {:resource_picture => {:artist => {}}}, + :speech_balloons =>{:balloons => {}, :speeches => {}} + } + }} + end + + def self.list_json_opt + {:include => { + :author => {}, + :comic => { + :author => {} + }, + :panel => { + :author => {}, + :panel_pictures => {:resource_picture => {:artist => {}}}, + :speech_balloons =>{:balloons => {}, :speeches => {}} + } + }} + end + + def to_json_list + self.to_json( :include => {:author => {}, :panels => {:methods => :panel_element}}) + end + + end diff --git a/app/views/comics/_form.html.erb b/app/views/comics/_form.html.erb index 62a9a0aa..c8e1fb64 100644 --- a/app/views/comics/_form.html.erb +++ b/app/views/comics/_form.html.erb @@ -27,10 +27,6 @@ <%= f.label :visible %>
<%= f.collection_select :visible, [['only me', 0], ['everyone', 3]], :last, :first, :html => {:selected => @comic.visible} %> -
- <%= f.label :editable %>
- <%= f.collection_select :editable, [['only me', 0], ['everyone', 3]], :last, :first, :html => {:selected => @comic.editable} %> -
<%= f.submit %> diff --git a/app/views/comics/browse.html.erb b/app/views/comics/browse.html.erb index f963352d..c9861b96 100644 --- a/app/views/comics/browse.html.erb +++ b/app/views/comics/browse.html.erb @@ -21,11 +21,6 @@

- editable: - <%= @comic.editable %> -

- -

author_id: <%= @comic.author_id %>

diff --git a/app/views/comics/index.html.erb b/app/views/comics/index.html.erb index 9302b797..5ea6d810 100644 --- a/app/views/comics/index.html.erb +++ b/app/views/comics/index.html.erb @@ -3,8 +3,7 @@ <% @comics.each do |comic| %>
- <%= link_to h(comic.title), :action => :play, :id => comic.id %> - 一般投稿:<%= comic.disp_editable %> + <%= link_to h(comic.title), :controller => 'stories', :action => :show, :id => comic.id %>
作家:<%= h comic.author.name %> diff --git a/app/views/comics/list.html.erb b/app/views/comics/list.html.erb index 80453818..189ada4f 100644 --- a/app/views/comics/list.html.erb +++ b/app/views/comics/list.html.erb @@ -7,7 +7,6 @@ width height visible - editable author_id created_at updated_at @@ -21,7 +20,6 @@ <%= comic.width %> <%= comic.height %> <%= comic.visible %> - <%= comic.editable %> <%= link_to comic.author_id, :controller => '/authors', :action => :browse, :id => comic.author_id %> <%= comic.created_at %> <%= comic.updated_at %> diff --git a/app/views/comics/show.html.erb b/app/views/comics/show.html.erb index fb358d2c..f77abc22 100644 --- a/app/views/comics/show.html.erb +++ b/app/views/comics/show.html.erb @@ -21,11 +21,6 @@

- editable: - <%= @comic.editable %> -

- -

author_id: <%= @comic.author_id %>

diff --git a/app/views/panels/_standard.html.erb b/app/views/panels/_standard.html.erb index e1ae5ad9..fff9389e 100644 --- a/app/views/panels/_standard.html.erb +++ b/app/views/panels/_standard.html.erb @@ -1,6 +1,3 @@ - -t:<%= @panel.t %> -
<% @panel.each_element do |elm| %> <% if elm.kind_of?(PanelPicture) %> @@ -21,20 +18,9 @@ t:<%= @panel.t %> <% end %>
-Comic:<%= @panel.comic_id %> - - -resource_picture:<%= @panel.resource_picture_id %> - - Width:<%= @panel.width %> Height:<%= @panel.height %> -<%= form_for(@panel) do |f| %> - <%= f.submit 'move to' %> - <%= f.number_field :t %> -<% end %> -<%= button_to 'Destroy', @panel, confirm: 'Are you sure?', method: :delete %> diff --git a/app/views/panels/index.html.erb b/app/views/panels/index.html.erb index 8b37c7ab..f209acad 100644 --- a/app/views/panels/index.html.erb +++ b/app/views/panels/index.html.erb @@ -1,7 +1,6 @@

Listing panels 最近の投稿

<% @panels.each do |panel| %>
- <%= link_to h(panel.comic.title), panel.comic %>t:<%= panel.t %>
<% panel.panel_pictures.each do |panel_picture| %>
@@ -18,7 +17,7 @@ <%= h panel.author.name %> <%= panel.updated_at %>
<% end %> -<%= link_to 'open form', new_panel_path, :remote => true %> -
- uploader -
+<%= link_to 'open form', new_panel_path, :remote => true %> +
+ uploader +
diff --git a/app/views/panels/list.html.erb b/app/views/panels/list.html.erb index aaa0945d..ded452e4 100644 --- a/app/views/panels/list.html.erb +++ b/app/views/panels/list.html.erb @@ -1,20 +1,19 @@

Listing panels

-<%= link_to 'open form', new_panel_path, :remote => true %> -
- uploader -
+<%= link_to 'open form', new_panel_path, :remote => true %> +
+ uploader +
- - + @@ -24,14 +23,13 @@ <% @panels.each do |panel| %> - - + diff --git a/app/views/stories/_editform.html.erb b/app/views/stories/_editform.html.erb new file mode 100644 index 00000000..9cc6dd41 --- /dev/null +++ b/app/views/stories/_editform.html.erb @@ -0,0 +1,28 @@ +<%= form_for(@story) do |f| %> + <% if @story.errors.any? %> +
+

<%= pluralize(@story.errors.count, "error") %> prohibited this comic from being saved:

+ +
    + <% @story.errors.full_messages.each do |msg| %> +
  • <%= msg %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= f.hidden_field :comic_id %> +
+
+ <%= f.number_field :t %> +
+
+ <%= f.hidden_field :panel_id %> +
+ +
+ <%= f.submit %> +
+<% end %> +<%= button_to 'Destroy', @story.panel, confirm: 'Are you sure?', method: :delete %> diff --git a/app/views/stories/_newform.html.erb b/app/views/stories/_newform.html.erb new file mode 100644 index 00000000..cc401135 --- /dev/null +++ b/app/views/stories/_newform.html.erb @@ -0,0 +1,27 @@ +<%= form_for(@story, @form_opt) do |f| %> + <% if @story.errors.any? %> +
+

<%= pluralize(@story.errors.count, "error") %> prohibited this comic from being saved:

+ +
    + <% @story.errors.full_messages.each do |msg| %> +
  • <%= msg %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= f.number_field :comic_id %> +
+
+ <%= f.number_field :t %> +
+
+ <%= f.number_field :panel_id %> +
+ +
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/stories/browse.html.erb b/app/views/stories/browse.html.erb new file mode 100644 index 00000000..24a7a6ca --- /dev/null +++ b/app/views/stories/browse.html.erb @@ -0,0 +1,28 @@ +

<%= notice %>

+ +

+ comic_id: + <%= @story.comic_id %> +

+ +

+ panel_id: + <%= @story.panel_id %> +

+ +

+ t: + <%= @story.t %> +

+ +

+ author_id: + <%= @story.author_id %> +

+ +

+ updated_at: + <%= @story.updated_at %> +

+ +<%= link_to 'Back', :action => :list %> diff --git a/app/views/stories/edit.html.erb b/app/views/stories/edit.html.erb new file mode 100644 index 00000000..9f2b8426 --- /dev/null +++ b/app/views/stories/edit.html.erb @@ -0,0 +1 @@ +<%= render 'editform' %> diff --git a/app/views/stories/edit.js.erb b/app/views/stories/edit.js.erb new file mode 100644 index 00000000..29c687f7 --- /dev/null +++ b/app/views/stories/edit.js.erb @@ -0,0 +1 @@ +$("#story-update-<%= @story.id -%>").html("<%= escape_javascript(render('editform')) -%>"); diff --git a/app/views/stories/list.html.erb b/app/views/stories/list.html.erb new file mode 100644 index 00000000..6fae81c5 --- /dev/null +++ b/app/views/stories/list.html.erb @@ -0,0 +1,29 @@ +

Listing Story

+ +
idComic Width Height Border x y ztpublish author_id created_at updated_at
<%= link_to panel.id, :action => :browse, :id => panel.id %><%= link_to panel.comic_id, :controller => 'comics', :action => :browse, :id => panel.comic_id %> <%= panel.width %> <%= panel.height %> <%= panel.border %> <%= panel.x %> <%= panel.y %> <%= panel.z %><%= panel.t %><%= panel.publish %> <%= link_to panel.author_id, :controller => '/authors', :action => :browse, :id => panel.author_id %> <%= panel.created_at %> <%= panel.updated_at %>
+ + + + + + + + + + + +<% @stories.each do |story| %> + + + + + + + + + + +<% end %> +
idcomic_idpanel_idtauthor_idcreated_atupdated_at
<%= link_to story.id, :action => :browse, :id => story.id %><%= story.comic_id %><%= story.panel_id %><%= story.t %><%= link_to story.author_id, :controller => '/authors', :action => :browse, :id => story.author_id %><%= story.created_at %><%= story.updated_at %> +
+ diff --git a/app/views/stories/new.html.erb b/app/views/stories/new.html.erb new file mode 100644 index 00000000..47cd6d96 --- /dev/null +++ b/app/views/stories/new.html.erb @@ -0,0 +1 @@ +<%= render 'newform' %> diff --git a/app/views/stories/new.js.erb b/app/views/stories/new.js.erb new file mode 100644 index 00000000..e9f64871 --- /dev/null +++ b/app/views/stories/new.js.erb @@ -0,0 +1 @@ +$("#story-create").html("<%= escape_javascript(render('newform')) -%>"); diff --git a/app/views/stories/show.html.erb b/app/views/stories/show.html.erb new file mode 100644 index 00000000..dfa9effb --- /dev/null +++ b/app/views/stories/show.html.erb @@ -0,0 +1,25 @@ +

<%= h @comic.title %>

+ +<% @stories.each do |story| %> + <% @story = story %> + <% @panel = story.panel %> + <%= render 'panels/standard' %> + <% if story.author.id == @author.id -%> + + t:<%= story.t %> + +<%= button_to 'Destroy', @story, confirm: 'Are you sure?', method: :delete %> + <%= render 'editform' %> + <%= link_to 'open js', edit_story_path(story), :remote => true %> +
+ t +
+ <% end -%> +<% end %> +<% if @comic.author.id == @author.id -%> + <%= link_to 'add panel', new_story_path, :remote => true %> +
+ t +
+<% end %> +<%= link_to 'Back', comics_path %> diff --git a/app/views/system/browse.html.erb b/app/views/system/browse.html.erb index 836bacd3..f05ec077 100644 --- a/app/views/system/browse.html.erb +++ b/app/views/system/browse.html.erb @@ -15,6 +15,11 @@ + <%= link_to 'stories', :controller => 'stories', :action => :list %> + + + + <%= link_to 'original_pictures', :controller => 'original_pictures', :action => :list %> diff --git a/config/routes.rb b/config/routes.rb index 0eb6117c..7761f237 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -90,10 +90,12 @@ Pettanr::Application.routes.draw do end end resources :original_pictures do + new do + get :new + end collection do get :index get :show - get :new post :create get :list get :browse @@ -118,7 +120,25 @@ Pettanr::Application.routes.draw do delete :destroy end end + resources :stories do + new do + get :new + end + collection do + post :create + get :list + get :browse + end + member do + get :show + put :update + delete :destroy + end + end resources :comics do #, except: [:new, :edit] + new do + get :new + end collection do get :index get :show diff --git a/spec/cli/create.rb b/spec/cli/create.rb new file mode 100644 index 00000000..7a1588ca --- /dev/null +++ b/spec/cli/create.rb @@ -0,0 +1,14 @@ +if ARGV.size < 2 + puts 'create.rb subdir controller {filename=create.json}' + exit +end +domain = 'http://localhost:3000' +user = ARGV[0].to_s +ctl = ARGV[1] +f = ARGV[2] ? ARGV[2].to_s+'_create' : 'create' +path = File.expand_path(File.dirname(__FILE__)) +filename = path + "/#{user}/#{ctl}/#{f}.json" + +cmd = "curl -d @#{filename} #{domain}/#{ctl}.json -X POST -H \"Content-Type: application/json\"" +puts cmd +exec cmd diff --git a/spec/cli/reauth.rb b/spec/cli/reauth.rb new file mode 100644 index 00000000..84060c29 --- /dev/null +++ b/spec/cli/reauth.rb @@ -0,0 +1,31 @@ +if ARGV.size < 2 + puts 'reauth.rb subdir new_auth_token' + exit +end +require 'json' +path = File.expand_path(File.dirname(__FILE__)) + '/' + (ARGV[0].to_s + '/' + '*') +puts 'path:' +puts path +Dir.glob path do |filename| + if File.directory?(filename) + puts 'search dir:' + puts filename + Dir.glob filename + '/*' do |filename2| + d = nil + puts 'replace:' + puts filename2 + File.open(filename2, 'rb') do |f| + d = f.read + end + j = JSON.parse d + ot = j["auth_token"] + b = d.gsub /#{ot}/, ARGV[1].to_s + File.open(filename2, 'wb') do |f| + f.write b + end + end + else + puts 'ignore file:' + puts filename + end +end diff --git a/spec/cli/u/comics/create.json b/spec/cli/u/comics/create.json new file mode 100644 index 00000000..7b8fabea --- /dev/null +++ b/spec/cli/u/comics/create.json @@ -0,0 +1,9 @@ +{ + "comic": { + "title": "コミック作るテスト", + "width": 400, + "height": 200, + "visible": 3 + }, + "auth_token": "Qr2cveaLKqMHA8dME7CN" +} \ No newline at end of file diff --git a/spec/cli/u/original_pictures/create.json b/spec/cli/u/original_pictures/create.json new file mode 100644 index 00000000..b5f7c8bf --- /dev/null +++ b/spec/cli/u/original_pictures/create.json @@ -0,0 +1,6 @@ +{ + "original_picture": { + "file": +"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" }, + "auth_token": "Qr2cveaLKqMHA8dME7CN" +} \ No newline at end of file diff --git a/spec/cli/u/panels/create.json b/spec/cli/u/panels/create.json new file mode 100644 index 00000000..9eba8b65 --- /dev/null +++ b/spec/cli/u/panels/create.json @@ -0,0 +1,23 @@ +{ + "panel": { + "width": 400, + "height": 200, + "border": 1, + "x": 0, + "y": 0, + "z": 1, + "publish": 1, + "panel_pictures_attributes": { + "new1": { + "resource_picture_id": 3, + "x": 10, + "y": 135, + "z": 3, + "t": 0, + "width": 100, + "height": 103 + } + } + }, + "auth_token": "Qr2cveaLKqMHA8dME7CN" +} \ No newline at end of file diff --git a/spec/cli/u/stories/create.json b/spec/cli/u/stories/create.json new file mode 100644 index 00000000..577fff47 --- /dev/null +++ b/spec/cli/u/stories/create.json @@ -0,0 +1,7 @@ +{ + "story": { + "comic_id": 1, + "panel_id": 1 + }, + "auth_token": "Qr2cveaLKqMHA8dME7CN" +} \ No newline at end of file diff --git a/spec/cli/update.rb b/spec/cli/update.rb new file mode 100644 index 00000000..8e19b43c --- /dev/null +++ b/spec/cli/update.rb @@ -0,0 +1,14 @@ +if ARGV.size < 2 + puts 'update.rb subdir controller {filename=update.json}' + exit +end +domain = 'http://localhost:3000' +user = ARGV[0].to_s +ctl = ARGV[1] +f = ARGV[2] ? ARGV[2].to_s+'_update' : 'update' +path = File.expand_path(File.dirname(__FILE__)) +filename = path + "/#{user}/#{ctl}/#{f}.json" + +cmd = "curl -d @#{filename} #{domain}/#{ctl}.json -X PUT -H \"Content-Type: application/json\"" +puts cmd +exec cmd diff --git a/spec/controllers/stories_controller_spec.rb b/spec/controllers/stories_controller_spec.rb index 23611f15..33e15b09 100644 --- a/spec/controllers/stories_controller_spec.rb +++ b/spec/controllers/stories_controller_spec.rb @@ -2,82 +2,296 @@ require 'spec_helper' #ストーリー describe StoriesController do + before do + Factory :admin + @license = Factory :license + @user = Factory :user_yas + @author = @user.author #ユーザ作成時に連動して作成される + @comic = Factory :comic, :author_id => @user.author.id + @panel = Factory :panel, :author_id => @author.id + end + describe '閲覧に於いて' do before do - @comic = Factory :comic, :author_id => @user.author.id + @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id Comic.stub(:show).and_return(@comic) sign_in @user end context '事前チェックする' do + end + context 'つつがなく終わるとき' do + end + context '作家権限がないとき' do + end + end + + describe '新規作成フォーム表示に於いて' do + before do + sign_in @user + end + context 'つつがなく終わるとき' do + it 'ステータスコード200 OKを返す' do + get :new + response.should be_success + end + it '@storyに新規データを用意している' do + get :new + assigns(:story).should be_a_new(Story) + end + it 'コマモデルにデフォルト値補充を依頼している' do + Story.any_instance.should_receive(:supply_default).exactly(1) + get :new + end + context 'html形式' do + it 'newテンプレートを描画する' do + get :new + response.should render_template("new") + end + end + context 'js形式' do + it 'new.jsテンプレートを描画する' do + get :new, :format => :js + response.should render_template("new") + end + end + end + context '作家権限がないとき' do before do - Panel.stub(:count).and_return(10) + sign_out @user end - it '与えられたoffsetがセットされている' do - get :play, :id => @comic.id, :offset => 7 - assigns(:offset).should eq 7 + context 'html形式' do + it 'ステータスコード302 Foundを返す' do + get :new + response.status.should eq 302 + end + it 'サインインページへ遷移する' do + get :new + response.body.should redirect_to '/users/sign_in' + end end - it '省略されると@offsetに0値が入る' do - get :play, :id => @comic.id - assigns(:offset).should eq 0 + context 'js形式' do + it 'ステータスコード401 Unauthorizedを返す' do + get :new, :format => :js + response.status.should eq 401 + end + it '応答メッセージにUnauthorizedを返す' do + get :new, :format => :js + response.message.should match(/Unauthorized/) + end end - it 'コマ数以上が与えられるとコマ数-1が入る' do - get :play, :id => @comic.id, :offset => 10 - assigns(:offset).should eq 9 + end + end + + describe '新規作成に於いて' do + before do + @attr = Factory.attributes_for(:story, :t => nil, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id) + sign_in @user + end + context 'つつがなく終わるとき' do + it 'モデルに保存依頼する' do + Story.any_instance.should_receive(:store).exactly(1) + post :create, :story => @attr end - it '負の値が与えられると末尾(コマ数)からさかのぼった値が入る' do - get :play, :id => @comic.id, :offset => -3 - assigns(:offset).should eq 7 + it "@storyに作成されたコマを保持していて、それがDBにある" do + post :create, :story => @attr + assigns(:story).should be_a(Story) + assigns(:story).should be_persisted end - it 'コマ数以上の負の値が与えられると計算できないので0値が入る' do - get :play, :id => @comic.id, :offset => -13 - assigns(:offset).should eq 0 + context 'html形式' do + it 'ステータスコード302 Foundを返す' do + Story.any_instance.stub(:store).and_return(true) + post :create, :story => @attr + response.status.should eq 302 + end + it 'コミックのストーリー表示へ遷移する' do +# Story.any_instance.stub(:store).and_return(true) + post :create, :story => @attr + response.should redirect_to(:action => :show, :id => @attr[:comic_id]) + end end - it '与えられたcountがセットされている' do - get :play, :id => @comic.id, :count => 18 - assigns(:panel_count).should eq 18 + context 'js形式' do + it 'ステータスコード302 Foundを返す' do + Story.any_instance.stub(:store).and_return(true) + post :create, :story => @attr, :format => :js + response.status.should eq 302 + end + it 'コミックのストーリー表示へ遷移する' do +# Story.any_instance.stub(:store).and_return(true) + post :create, :story => @attr, :format => :js + response.should redirect_to(:action => :show, :id => @attr[:comic_id]) + end end - it '省略されると@countにデフォルト値が入る' do - get :play, :id => @comic.id - assigns(:panel_count).should eq Comic.default_panel_size + context 'json形式' do + it 'ステータスコード200 OKを返す' do +# Story.any_instance.stub(:store).and_return(true) + post :create, :story => @attr, :format => :json + response.should be_success + end + it '作成されたコマをjsonデータで返す' do + post :create, :story => @attr, :format => :json + lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError) + end + it 'データがアレになっている' do + post :create, :story => @attr, :format => :json + json = JSON.parse response.body + json["t"].should eq @story.t + end end - it '最大を超えると@countにデフォルト最大値が入る' do - get :play, :id => @comic.id, :count => 1500 - assigns(:panel_count).should eq Comic.max_panel_size + end + context '作家権限がないとき' do + before do + sign_out @user end - it '不正な値が入ると@countにデフォルト最大値が入る' do - get :play, :id => @comic.id, :page_size => 0 - assigns(:panel_count).should eq Comic.default_panel_size + context 'html形式' do + it 'ステータスコード302 Foundを返す' do + post :create, :story => @attr + response.status.should eq 302 + end + it 'サインインページへ遷移する' do + post :create, :story => @attr + response.body.should redirect_to '/users/sign_in' + end + end + context 'json形式' do + it 'ステータスコード401 Unauthorizedを返す' do + post :create, :story => @attr, :format => :json + response.status.should eq 401 + end + it '応答メッセージにUnauthorizedを返す' do + post :create, :story => @attr, :format => :json + response.message.should match(/Unauthorized/) + end end end + context '検証、保存に失敗した' do + before do + Story.any_instance.stub(:store).and_return(false) + end + it "未保存のコマを保持している" do + post :create, :story => @attr + assigns(:story).should be_a_new(Story) + end + context 'html形式' do + it 'ステータスコード200 OKを返す' do + post :create, :story => @attr + response.status.should eq 200 + end + it '新規ページを描画する' do + post :create, :story => @attr + response.should render_template("new") + end + end + context 'json形式' do + it 'ステータスコード422 unprocessable_entity を返す' do + post :create, :story => @attr, :format => :json + response.status.should eq 422 + end + it '応答メッセージUnprocessable Entityを返す' do + post :create, :story => @attr, :format => :json + response.message.should match(/Unprocessable/) + end + end + end + end + + describe '編集フォーム表示に於いて' do + before do + @story = Factory :story, :author_id => @author.id + sign_in @user + Story.stub(:show).and_return(@story) + end context 'つつがなく終わるとき' do it 'ステータスコード200 OKを返す' do - get :play, :id => @comic.id - response.should be_success + get :edit, :id => @story.id + response.should be_success end - it 'コミックモデルに単体取得を問い合わせている' do - Comic.should_receive(:show).exactly(1) - get :play, :id => @comic.id + it 'コマモデルに単体取得を問い合わせている' do + Story.should_receive(:show).exactly(1) + get :edit, :id => @story.id end - it '@comicにアレを取得している' do - get :play, :id => @comic.id - assigns(:comic).id.should eq(@comic.id) + it '@storyにデータを用意している' do + get :edit, :id => @story.id + assigns(:story).should eq @story end context 'html形式' do - it 'playテンプレートを描画する' do - get :play, :id => @comic.id - response.should render_template("play") + it 'editテンプレートを描画する' do + get :edit, :id => @story.id + response.should render_template("edit") end end - context 'json形式' do - it 'jsonデータを返す' do - get :play, :id => @comic.id, :format => :json - lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError) + context 'js形式' do + it 'edit.jsテンプレートを描画する' do + get :edit, :id => @story.id, :format => :js + response.should render_template("edit") end - it 'データがアレになっている' do - get :play, :id => @comic.id, :format => :json - json = JSON.parse response.body - json["title"].should match(/normal/) + end + end + context '作家権限がないとき' do + before do + sign_out @user + end + context 'html形式' do + it 'ステータスコード302 Foundを返す' do + get :edit, :id => @story.id + response.status.should eq 302 + end + it 'サインインページへ遷移する' do + get :edit, :id => @story.id + response.body.should redirect_to '/users/sign_in' + end + end + context 'js形式' do + it 'ステータスコード401 Unauthorizedを返す' do + get :edit, :id => @story.id, :format => :js + response.status.should eq 401 + end + it '応答メッセージにUnauthorizedを返す' do + get :edit, :id => @story.id, :format => :js + response.message.should match(/Unauthorized/) + end + end + end + end + + describe '更新に於いて' do + before do + @story = Factory :story, :author_id => @user.author.id + @attr = Factory.attributes_for(:story, :author_id => @author.id) + sign_in @user + end + context 'つつがなく終わるとき' do + it 'モデルに取得依頼する' do + Story.stub(:show).with(any_args).and_return(@story) + Story.should_receive(:show).exactly(1) + put :update, :id => @story.id, :story => @attr + end + it 'モデルに保存依頼する' do + Story.any_instance.should_receive(:store).exactly(1) + put :update, :id => @story.id, :story => @attr + end + it "@storyに作成されたストーリーを保持していて、それがDBにある" do + put :update, :id => @story.id, :story => @attr + assigns(:story).should be_a(Story) + assigns(:story).should be_persisted + end + context 'html形式' do + it 'ステータスコード302 Foundを返す' do + Story.any_instance.stub(:store).and_return(true) + put :update, :id => @story.id, :story => @attr + response.status.should eq 302 + end + it 'コミックのストーリー表示へ遷移する' do +# Story.any_instance.stub(:store).and_return(true) + put :update, :id => @story.id, :story => @attr + response.should redirect_to(:action => :show, :id => @attr[:comic_id]) + end + end + context 'json形式' do + it 'ステータスコード200 OKを返す' do +# Story.any_instance.stub(:store).and_return(true) + put :update, :id => @story.id, :story => @attr, :format => :json + response.should be_success end end end @@ -87,25 +301,54 @@ describe StoriesController do end context 'html形式' do it 'ステータスコード302 Foundを返す' do - get :play, :id => @comic.id + put :update, :id => @story.id, :story => @attr response.status.should eq 302 end it 'サインインページへ遷移する' do - get :play, :id => @comic.id + put :update, :id => @story.id, :story => @attr response.body.should redirect_to '/users/sign_in' end end context 'json形式' do it 'ステータスコード401 Unauthorizedを返す' do - get :play, :id => @comic.id, :format => :json + put :update, :id => @story.id, :story => @attr, :format => :json response.status.should eq 401 end it '応答メッセージにUnauthorizedを返す' do - get :play, :id => @comic.id, :format => :json + put :update, :id => @story.id, :story => @attr, :format => :json response.message.should match(/Unauthorized/) end end end + context '検証、保存に失敗した' do + before do + Story.any_instance.stub(:store).and_return(false) + end + it "指定のコマを保持している" do + put :update, :id => @story.id, :story => @attr + assigns(:story).should eq @story + end + context 'html形式' do + it 'ステータスコード200 OKを返す' do + put :update, :id => @story.id, :story => @attr + response.status.should eq 200 + end + it '編集ページを描画する' do + put :update, :id => @story.id, :story => @attr + response.should render_template("edit") + end + end + context 'json形式' do + it 'ステータスコード422 unprocessable_entity を返す' do + put :update, :id => @story.id, :story => @attr, :format => :json + response.status.should eq 422 + end + it '応答メッセージUnprocessable Entityを返す' do + put :update, :id => @story.id, :story => @attr, :format => :json + response.message.should match(/Unprocessable/) + end + end + end end end diff --git a/spec/models/story_spec.rb b/spec/models/story_spec.rb index 8bca75c8..2d3a769e 100644 --- a/spec/models/story_spec.rb +++ b/spec/models/story_spec.rb @@ -8,6 +8,8 @@ describe Story do @user = Factory( :user_yas) @author = @user.author @artist = Factory :artist_yas, :author_id => @author.id + @other_user = Factory( :user_yas) + @other_author = @other_user.author end describe '検証に於いて' do @@ -121,6 +123,216 @@ describe Story do end end + + describe '作者判定に於いて' do + before do + @comic = Factory :comic, :author_id => @author.id + @panel = Factory :panel, :author_id => @author.id + @story = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id + @comico = Factory :comic, :author_id => @other_author.id + @panelo = Factory :panel, :author_id => @other_author.id + @storyo = Factory :story, :author_id => @other_author.id, :comic_id => @comico.id, :panel_id => @panelo.id + end + it '自分のストーリーならyes' do + @story.own?(@author).should == true + end + it '他人のストーリーならno' do + @storyo.own?(@author).should == false + end + it '作家が不明ならno' do + @story.own?(nil).should == false + end + end + describe '単体取得に於いて' do + before do + @comic = Factory :comic, :author_id => @author.id + @panel = Factory :panel, :author_id => @author.id + @story = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id + end + context 'オーナー指定がないとき' do + it '指定のストーリーを返す' do + l = Story.show @story.id, @author + l.should eq @story + end + end + context 'オーナー指定のとき' do + it '指定のストーリーが自分のものならそれを返す' do + l = Story.show @story.id, @author + l.should eq @story + end + context '他人のストーリーを開こうとしたとき' do + it '403Forbidden例外を返す' do + Story.any_instance.stub(:own?).and_return(false) + lambda{ + Story.show @story.id, @author + }.should raise_error(ActiveRecord::Forbidden) + end + end + end + context '存在しないストーリーを開こうとしたとき' do + it '404RecordNotFound例外を返す' do + lambda{ + Story.show 110, @author + }.should raise_error(ActiveRecord::RecordNotFound) + end + end + end + + describe '一覧取得に於いて' do + before do + @comic = Factory :comic, :author_id => @author.id + @panel = Factory :panel, :author_id => @author.id + @story = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id + end + context 'offset補正について' do + it '文字列から数値に変換される' do + Story.offset(100, '8').should eq 8 + end + it 'nilの場合は0になる' do + Story.offset(100).should eq 0 + end + #投稿されたコマ数以上の値が指定されたときは、最後のコマだけになる + #最後のコマとは、コマ数‐1. + it '1件のときオフセット1なら0になる' do + Story.offset(1, '1').should eq 0 + end + it '5件のときオフセット5なら4になる' do + Story.offset(5, '5').should eq 4 + end + # 負の値が指定されたときは、最後のコマから数えてコマを飛ばして表示する。 + #-4のときは、最後から4つのコマを表示する。 + it '2件のときオフセット-1なら1になる' do + Story.offset(2, '-1').should eq 1 + end + it '5件のときオフセット-2なら3になる' do + Story.offset(5, '-2').should eq 3 + end + # 最終的なが負になるなど、不正な値が入ったときは0となる。 + it '2件のときオフセット-5なら0になる' do + Story.offset(2, '-5').should eq 0 + end + end + context 'panel_count補正について' do + it '文字列から数値に変換される' do + Story.panel_count(100, '7').should eq 7 + end + it 'nilの場合はStory.default_panel_sizeになる' do + Story.panel_count(100).should eq Story.default_panel_size + end + it '0以下の場合はStory.default_panel_sizeになる' do + Story.panel_count(100, '0').should eq Story.default_panel_size + end + it 'Story.max_panel_sizeを超えた場合はStory.max_panel_sizeになる' do + Story.panel_count(100, '1000').should eq Story.max_panel_size + end + end + it 'リストを返す' do + c = Story.list @comic, @author + c.should eq [@story] + end + it 't順で並んでいる' do + v = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 1 + c = Story.list @comic, @author + c.should eq [ @story, v] + end + context 'DBに5件あって1ページの件数を2件に変えたとして' do + before do + @story2 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 1 + @story3 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 2 + @story4 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 3 + @story5 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 4 + end + it 'offset=0なら末尾2件を返す' do + #時系列で並んでいる + c = Story.list( @comic, @author, 0, 2) + c.should eq [@story, @story2] + end + it 'offset=2なら中間2件を返す' do + c = Story.list(@comic, @author, 2, 2) + c.should eq [@story3, @story4] + end + it 'offset=4なら先頭1件を返す' do + c = Story.list(@comic, @author, 4, 2) + c.should eq [@story5] + end + end + end + describe 'list関連テーブルプションに於いて' do + it 'includeキーを含んでいる' do + r = Story.list_opt + r.has_key?(:include).should be_true + end + it '3つの項目を含んでいる' do + r = Story.list_opt[:include] + r.should have(3).items + end + it 'コミックを含んでいる' do + r = Story.list_opt[:include] + r.has_key?(:comic).should be_true + end + it 'コミックは作家を含んでいる' do + r = Story.list_opt[:include] + r[:comic].has_key?(:author).should be_true + end + it '作家を含んでいる' do + r = Story.list_opt[:include] + r.has_key?(:author).should be_true + end + it 'コマを含んでいる' do + r = Story.list_opt[:include] + r.has_key?(:panel).should be_true + end + it 'コマは作家を含んでいる' do + r = Story.list_opt[:include] + r[:panel].has_key?(:author).should be_true + end + it 'コマはコマ絵を含んでいる' do + r = Story.list_opt[:include] + r[:panel].has_key?(:panel_pictures).should be_true + end + it 'コマはフキダシを含んでいる' do + r = Story.list_opt[:include] + r[:panel].has_key?(:speech_balloons).should be_true + end + end + describe 'json一覧出力オプションに於いて' do + it 'includeキーを含んでいる' do + r = Story.list_json_opt + r.has_key?(:include).should be_true + end + it '3つの項目を含んでいる' do + r = Story.list_json_opt[:include] + r.should have(3).items + end + it 'コミックを含んでいる' do + r = Story.list_json_opt[:include] + r.has_key?(:comic).should be_true + end + it 'コミックは作家を含んでいる' do + r = Story.list_json_opt[:include] + r[:comic].has_key?(:author).should be_true + end + it '作家を含んでいる' do + r = Story.list_json_opt[:include] + r.has_key?(:author).should be_true + end + it 'コマを含んでいる' do + r = Story.list_json_opt[:include] + r.has_key?(:panel).should be_true + end + it 'コマは作家を含んでいる' do + r = Story.list_json_opt[:include] + r[:panel].has_key?(:author).should be_true + end + it 'コマはコマ絵を含んでいる' do + r = Story.list_json_opt[:include] + r[:panel].has_key?(:panel_pictures).should be_true + end + it 'コマはフキダシを含んでいる' do + r = Story.list_json_opt[:include] + r[:panel].has_key?(:speech_balloons).should be_true + end + end describe 't補充値に於いて' do before do @comic = Factory :comic, :author_id => @author.id @@ -679,6 +891,43 @@ describe Story do end end end + describe '編集許可に於いて' do + before do + @comic = Factory :comic, :author_id => @author.id + @panel = Factory :panel, :author_id => @author.id + @story = Factory.build :story, :t => nil, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + end + context 'つつがなく終わるとき' do + it 'trueを返す' do + r = @story.allow? + r.should be_true + end + end + context 'コミックで引っかかるとき' do + it 'falseを返す' do + @story.comic_id = nil + r = @story.allow? + r.should be_false + end + it 'falseを返す' do + Comic.any_instance.stub(:own?).with(any_args).and_return(false) + r = @story.allow? + r.should be_false + end + end + context 'コマで引っかかるとき' do + it 'falseを返す' do + @story.panel_id = nil + r = @story.allow? + r.should be_false + end + it 'falseを返す' do + Panel.any_instance.stub(:usable?).with(any_args).and_return(false) + r = @story.allow? + r.should be_false + end + end + end describe '保存に於いて' do before do @comic = Factory :comic, :author_id => @author.id @@ -686,6 +935,11 @@ describe Story do @story = Factory.build :story, :t => nil, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id end context 'つつがなく終わるとき' do + it '編集許可チェックを依頼している' do + Story.any_instance.stub(:allow?).with(any_args).and_return(true) + Story.any_instance.should_receive(:allow?).with(any_args).exactly(1) + r = @story.store + end it '順序入れ替えを依頼している' do Story.any_instance.stub(:rotate).with(any_args).and_return(0) Story.any_instance.should_receive(:rotate).with(any_args).exactly(1) @@ -720,10 +974,41 @@ describe Story do @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id @story6 = Factory.build :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id end + it '既存のt0には変化がない' do + @story6.store + @story.reload + @story.t.should eq 0 + end + it '既存のt1には変化がない' do + @story6.store + @story2.reload + @story2.t.should eq 1 + end + it '既存のt2を3にシフトしている' do + @story6.store + @story3.reload + @story3.t.should eq 3 + end + it '既存のt3を4にシフトしている' do + @story6.store + @story4.reload + @story4.t.should eq 4 + end + it '既存のt5を5にシフトしている' do + @story6.store + @story5.reload + @story5.t.should eq 5 + end + it '新規のt2が作成されている' do + @story6.store + @story6.reload + @story6.t.should eq 2 + end it '他のコミックに影響がない' do + @ot = @storyc2.t @story6.store @storyc2.reload - @storyc2.t.should eq ot + @storyc2.t.should eq @ot end end context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で3を1に移動したとき' do @@ -812,5 +1097,190 @@ describe Story do @storyc2.t.should eq 0 end end + #ロールバックテスト。入れ替えが直接DBをいじるので、すべてのケースで確実にロールバックを確認する + context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で2に挿入したが保存に失敗したとき' do + before do + Story.any_instance.stub(:save).with(any_args).and_return(false) + @comic2 = Factory :comic, :author_id => @author.id + @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id + @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story6 = Factory.build :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + end + it '既存のtに変化がない' do + @story6.store + @story.reload + @story.t.should eq 0 + @story2.reload + @story2.t.should eq 1 + @story3.reload + @story3.t.should eq 2 + @story4.reload + @story4.t.should eq 3 + @story5.reload + @story5.t.should eq 4 + @storyc2.reload + @storyc2.t.should eq 0 + end + it 'falseを返す' do + r = @story6.store + r.should be_false + end + end + context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で3を1に移動したがシリアルチェックに失敗したとき' do + before do + Story.stub(:validate_t).with(any_args).and_return(false) + @comic2 = Factory :comic, :author_id => @author.id + @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id + @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @ot = @story4.t + @story4.t = 1 + end + it '既存のtに変化がない' do + @story4.store @ot + @story.reload + @story.t.should eq 0 + @story2.reload + @story2.t.should eq 1 + @story3.reload + @story3.t.should eq 2 + @story4.reload + @story4.t.should eq 3 + @story5.reload + @story5.t.should eq 4 + @storyc2.reload + @storyc2.t.should eq 0 + end + it 'falseを返す' do + r = @story4.store @ot + r.should be_false + end + it 'tにエラーメッセージが入っている' do + @story4.store @ot + @story4.errors[:t].should_not be_empty + @story4.valid?.should be_true + end + end + context '編集不可だったとき' do + before do + @story = Factory.build :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + Story.any_instance.stub(:allow?).and_return(false) + end + it '403Forbidden例外を返す' do + lambda{ + @story.store + }.should raise_error(ActiveRecord::Forbidden) + end + end + end + describe '切り詰め処理つき削除に於いて' do + before do + @comic = Factory :comic, :author_id => @author.id + @panel = Factory :panel, :author_id => @author.id + @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + end + context 'つつがなく終わるとき' do + it '削除される' do + lambda{ + @story.destroy_and_shorten + }.should change(Story, :count ).by(-1) + end + end + #連携テスト。切り詰めが直接DBをいじる + context '2件で先頭を削除したとき' do + before do + @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + end + it '行が削除される' do + lambda{ + @story.destroy_and_shorten + }.should change(Story, :count ).by(-1) + end + it '先頭は削除される' do + @story.destroy_and_shorten + lambda{ + Story.find @story.id + }.should raise_error(ActiveRecord::RecordNotFound) + end + it '2件目は前に詰められる' do + @story.destroy_and_shorten + @story2.reload + @story2.t.should eq 0 + end + end + context '3件で先頭を削除したとき' do + before do + @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + end + it '行が削除される' do + lambda{ + @story.destroy_and_shorten + }.should change(Story, :count ).by(-1) + end + it '先頭は削除される' do + @story.destroy_and_shorten + lambda{ + Story.find @story.id + }.should raise_error(ActiveRecord::RecordNotFound) + end + it '2件目は前に詰められる' do + @story.destroy_and_shorten + @story2.reload + @story2.t.should eq 0 + end + it '3件目は前に詰められる' do + @story.destroy_and_shorten + @story3.reload + @story3.t.should eq 1 + end + end + context '5件で3件目を削除したとき' do + before do + @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id + end + it '行が削除される' do + lambda{ + @story3.destroy_and_shorten + }.should change(Story, :count ).by(-1) + end + it '1件目は変化がない' do + @story3.destroy_and_shorten + @story.reload + @story.t.should eq 0 + end + it '2件目は変化がない' do + @story3.destroy_and_shorten + @story2.reload + @story2.t.should eq 1 + end + it '3件目は削除される' do + @story3.destroy_and_shorten + lambda{ + Story.find @story3.id + }.should raise_error(ActiveRecord::RecordNotFound) + end + it '4件目は前に詰められる' do + @story3.destroy_and_shorten + @story4.reload + @story4.t.should eq 2 + end + it '5件目は前に詰められる' do + @story3.destroy_and_shorten + @story5.reload + @story5.t.should eq 3 + end + end + #ロールバックテスト。切り詰めが直接DBをいじるので、すべてのケースで確実にロールバックを確認する end end