\r
},\r
},\r
+ by_story: {\r
+ type: 'list',\r
+ },\r
+ by_author: {\r
+ type: 'list',\r
+ },\r
++ play: {\r
++ type: 'list',\r
++ args: {\r
++ item_name: 'comic_story',\r
++ list_name: 'play',\r
++ },\r
++ },\r
+ show: {\r
+ type: 'show',\r
+ },\r
+ count: {\r
+ type: 'count',\r
+ args: {\r
+ list_name: 'public',\r
+ },\r
+ },\r
+ count_by_story: {\r
+ type: 'count',\r
+ },\r
+ count_by_author: {\r
+ type: 'count',\r
+ },\r
+ new: {\r
+ type: 'new',\r
+ },\r
+ edit: {\r
+ type: 'edit',\r
+ },\r
+ },\r
+ },\r
+ comic_stories: {\r
+ actions: {\r
+ index: {\r
+ type: 'list',\r
+ args: {\r
+ list_name: 'public',\r
+ \r
+ },\r
+ },\r
+ by_comic: {\r
+ type: 'list',\r
+ },\r
+ by_story: {\r
+ type: 'list',\r
+ },\r
by_author: {\r
type: 'list',\r
},\r
list_name: 'public',\r
},\r
},\r
+ count_by_comic: {\r
+ type: 'count',\r
+ },\r
+ count_by_story: {\r
+ type: 'count',\r
+ },\r
count_by_author: {\r
type: 'count',\r
},\r
list_name: 'public',\r
},\r
},\r
- by_comic: {\r
+ count_by_comic: {\r
type: 'count',\r
},\r
- by_sheet: {\r
+ count_by_sheet: {\r
type: 'count',\r
},\r
count_by_author: {\r
\r
},\r
},\r
- scrolls: {\r
- type: 'list',\r
- args: {\r
- list_name: 'scrolls',\r
- },\r
- },\r
- comics: {\r
- type: 'list',\r
- args: {\r
- list_name: 'comics',\r
- },\r
- },\r
- stories: {\r
- type: 'list',\r
- args: {\r
- list_name: 'stories',\r
- },\r
- },\r
- sheets: {\r
- type: 'list',\r
- args: {\r
- list_name: 'sheets',\r
- },\r
- },\r
- panels: {\r
- type: 'list',\r
- args: {\r
- list_name: 'panels',\r
- },\r
- },\r
- panel_pictures: {\r
- type: 'list',\r
- args: {\r
- list_name: 'panel_pictures',\r
- },\r
- },\r
- speech_balloons: {\r
- type: 'list',\r
- args: {\r
- list_name: 'speech_balloons',\r
- },\r
- },\r
- ground_pictures: {\r
- type: 'list',\r
- args: {\r
- list_name: 'ground_pictures',\r
- },\r
- },\r
- ground_colors: {\r
- type: 'list',\r
- args: {\r
- list_name: 'ground_colors',\r
- },\r
- },\r
show: {\r
type: 'show',\r
},\r
\r
},\r
},\r
- resource_pictures: {\r
- type: 'list',\r
- args: {\r
- list_name: 'resource_pictures',\r
- },\r
- },\r
show: {\r
type: 'show',\r
},\r
by_author: {\r
type: 'filter',\r
},\r
+ by_story: {\r
+ type: 'through_filter',\r
+ args: {\r
+ through: 'comic_stories',\r
+ },\r
+ },\r
},\r
},\r
- story: {\r
+ comic_story: {\r
lists: {\r
public: {\r
type: 'public',\r
private: {\r
type: 'private',\r
},\r
+ play: {\r
+ type: 'play',\r
+ args: {\r
+ filter_item_name: 'comic',\r
+ filter_model_name: 'comic_story',\r
+ filter_key: 'comic_id',\r
+ },\r
+ },\r
by_comic: {\r
type: 'filter',\r
},\r
- by_sheet: {\r
- type: 'through_filter',\r
- args: {\r
- through: 'story_sheets',\r
- },\r
+ by_story: {\r
+ type: 'filter',\r
},\r
by_author: {\r
type: 'foreign_filter',\r
},\r
},\r
},\r
- play: {\r
- type: 'play',\r
+ },\r
+ },\r
+ story: {\r
+ lists: {\r
+ public: {\r
+ type: 'public',\r
+ },\r
+ private: {\r
+ type: 'private',\r
+ },\r
+ by_comic: {\r
+ type: 'through_filter',\r
+ args: {\r
+ through: 'comic_stories',\r
+ },\r
+ },\r
+ by_sheet: {\r
+ type: 'through_filter',\r
+ args: {\r
+ through: 'story_sheets',\r
+ },\r
+ },\r
+ by_author: {\r
+ type: 'filter',\r
},\r
},\r
},\r
by_speech_balloon: {\r
type: 'filter',\r
},\r
- by_writing_format: {\r
- type: 'filter',\r
- },\r
by_author: {\r
type: 'foreign_filter',\r
args: {\r
'author',\r
],\r
has_many: [\r
+ 'comic_stories.by_comic', \r
'stories.by_comic', \r
],\r
}, \r
},\r
- story: {\r
- columns: {\r
- visible: {\r
- type: 'source',\r
- }, \r
- },\r
+ comic_story: {\r
column_names: [\r
'comic_id', \r
+ 'story_id', \r
+ 't', \r
+ ],\r
+ associations: {\r
+ belongs_to: [\r
+ 'comic', \r
+ 'story'\r
+ ],\r
+ }, \r
+ },\r
+ story: {\r
+ column_names: [\r
'title', \r
'description', \r
't', \r
],\r
associations: {\r
belongs_to: [\r
- 'comic',\r
],\r
has_many: [\r
+ 'comic_stories.by_story', \r
+ 'comics.by_story',\r
'story_sheets.by_story', \r
'sheets.by_story'\r
],\r
}, \r
},\r
sheet: {\r
+ columns: {\r
+ visible: {\r
+ type: 'source',\r
+ }, \r
+ },\r
column_names: [\r
'caption', \r
'width', \r
}, \r
},\r
panel: {\r
+ columns: {\r
+ publish: {\r
+ type: 'source',\r
+ }, \r
+ },\r
column_names: [\r
'width', \r
'height', \r
'scrolls.by_author', \r
'scroll_panels.by_author', \r
'comics.by_author', \r
+ 'comic_stories.by_author', \r
'stories.by_author', \r
'sheets.by_author', \r
'sheet_panels.by_author', \r
--- /dev/null
- format.html { redirect_to play_comic_path(@comic) }
+class ComicStoriesController < ApplicationController
+ if Manifest.manifest.magic_numbers['run_mode'] == 0
+ before_filter :authenticate_user, :only => [:new, :create, :edit, :update, :destroy]
+ before_filter :authenticate_author, :only => [:new, :create, :edit, :update, :destroy]
+ else
+ before_filter :authenticate_reader, :only => [
+ :index, :show, :by_story, :by_comic, :by_author, :count, :count_by_story, :count_by_comic, :count_by_author
+ ]
+ before_filter :authenticate_user, :only => [:new, :create, :edit, :update, :destroy]
+ before_filter :authenticate_author, :only => [:new, :create, :edit, :update, :destroy]
+ end
+
+ def self.model
+ ComicStory
+ end
+
+ def index
+ filer_list
+ end
+
+ def by_story
+ filer_list
+ end
+
+ def by_comic
+ filer_list
+ end
+
+ def by_author
+ filer_list
+ end
+
+ def show
+ set_show
+ respond_to do |format|
+ show_prof_format format
+ format.json { render json: @item.comic_story_as_json(@operators.author) }
+ end
+ end
+
+ def count
+ list_count
+ end
+
+ def count_by_story
+ list_count
+ end
+
+ def count_by_comic
+ list_count
+ end
+
+ def count_by_author
+ list_count
+ end
+
+ def new
+ form_new
+ end
+
+ def edit
+ form_edit
+ end
+
+ def create
+ @comic_story = ComicStory.new
+ @comic_story.supply_default
+ @comic_story.attributes = params[:comic_story]
+ @comic_story.overwrite @operators
+ @comic = Comic.edit(@comic_story.comic_id, @operators) if @comic_story.comic_id
+ @story = Story.show(@comic_story.story_id, @operators) if @comic_story.story_id
+
+ respond_to do |format|
+ if @comic_story.store @operators
+ flash[:notice] = I18n.t('flash.notice.created', :model => ComicStory.model_name.human)
- format.html { redirect_to play_comic_path(@comic) }
++ format.html { redirect_to comic_path(@comic) }
+ format.json { render json: @comic_story.comic_story_as_json(@operators.author) }
+ else
+ flash[:notice] = I18n.t('flash.notice.not_created', :model => ComicStory.model_name.human)
+ format.html { render action: "new" }
+ format.json { render json: @comic_story.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ def update
+ @comic_story = ComicStory.edit(params[:id], @operators)
+ ot = @comic_story.t
+ @comic_story.attributes = params[:comic_story]
+ @comic_story.overwrite @operators
+ @comic = Comic.edit(@comic_story.comic_id, @operators) if @comic_story.comic_id
+ respond_to do |format|
+ if @comic_story.store @operators, ot
+ flash[:notice] = I18n.t('flash.notice.updated', :model => ComicStory.model_name.human)
++ format.html { redirect_to comic_path(@comic) }
+ format.json { head :ok }
+ else
+ flash[:notice] = I18n.t('flash.notice.not_updated', :model => ComicStory.model_name.human)
+ format.html { render action: "edit" }
+ format.json { render json: @comic_story.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ def destroy
+ @comic_story = ComicStory.edit(params[:id], @operators)
+ @comic = Comic.edit(@comic_story.comic_id, @operators) if @comic_story.comic_id
+ respond_to do |format|
+ if @comic_story.destroy_and_shorten
+ flash[:notice] = I18n.t('flash.notice.destroyed', :model => ComicStory.model_name.human)
+ format.html { redirect_to play_comic_path(@comic) }
+ format.json { head :ok }
+ else
+ flash[:notice] = I18n.t('flash.notice.not_destroyed', :model => ComicStory.model_name.human)
+ format.html { redirect_to comic_story_path(@comic_story) }
+ format.json { render json: @comic_story.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+end
before_filter :authenticate_user, :only => [:new, :create, :edit, :update, :destroy]
before_filter :authenticate_author, :only => [:new, :create, :edit, :update, :destroy]
else
- before_filter :authenticate_reader, :only => [:index, :show, :by_author, :count, :count_by_author]
+ before_filter :authenticate_reader, :only => [:index, :show, :by_story, :by_author, :count, :count_by_story, :count_by_author]
before_filter :authenticate_user, :only => [:new, :create, :edit, :update, :destroy]
before_filter :authenticate_author, :only => [:new, :create, :edit, :update, :destroy]
end
def index
filer_list
end
-
+
+ def by_story
+ filer_list
+ end
+
def by_author
filer_list
end
-
+
def show_html_format format
format.html {
++ @comic = @item
++ action = Manifest.manifest.controllers['comics'].actions['play']
++ list = Locmare::ListGroup.list action.item_name, action.list_name
++ list_result = list.open(@operators,
++ {:id => params[:id], :page => params[:page], :page_size => params[:page_size]}
++ )
++ @comic_stories = list_result.items
++ if @operators.author
++ @new_story_items = assist_items('story', 'private')
++ #@new_story_filer = assist_filer 'story', @new_story_items
++ end
}
end
format.rss
end
end
-
+
def count
list_count
end
+ def count_by_story
+ list_count
+ end
+
def count_by_author
list_count
end
def show_html_format format
format.html {
if @operators.author
++ @new_comic_items = assist_items('comic', 'private')
@new_sheet_items = assist_items('sheet', 'private')
#@new_sheet_filer = assist_filer 'sheet', @new_sheet_items
end
end
def create
- @story = Story.new
- @story.supply_default
- @story.attributes = params[:story]
- @story.overwrite
- @comic = Comic.edit(@story.comic_id, @operators) if @story.comic_id
+ @story = Story.new
+ @story.supply_default
+ jsn = nil
+ if params[:json]
+ jsn = JSON.parse_no_except(params[:json])
+ end
+ @prm = params[:story] || jsn
respond_to do |format|
- if @story.store @operators
+ if @story.store @prm, @operators
flash[:notice] = I18n.t('flash.notice.created', :model => Story.model_name.human)
- format.html { redirect_to play_story_path(@story, :page => @story.t.to_i + 1) }
- format.json { render json: @story.to_json(Story.show_json_opt) }
+ format.html { redirect_to @story }
+ format.json { render json: @story.to_json(Story.show_json_opt), status: :created, location: @story }
else
flash[:notice] = I18n.t('flash.notice.not_created', :model => Story.model_name.human)
format.html { render action: "new" }
def update
@story = Story.edit(params[:id], @operators)
- ot = @story.t
- @story.attributes = params[:story]
- @story.overwrite
+ jsn = nil
+ if params[:json]
+ jsn = JSON.parse(params[:json])
+ end
+ @prm = params[:story] || jsn
respond_to do |format|
- if @story.store @operators, ot
+ if @story.store @prm, @operators
flash[:notice] = I18n.t('flash.notice.updated', :model => Story.model_name.human)
- format.html { redirect_to play_story_path(@story, :page => @story.t.to_i + 1) }
+ format.html { redirect_to @story }
format.json { head :ok }
else
flash[:notice] = I18n.t('flash.notice.not_updated', :model => Story.model_name.human)
end
end
end
-
+
def destroy
@story = Story.edit(params[:id], @operators)
respond_to do |format|
- if @story.destroy_and_shorten
+ if @story.destroy_with_story_panel
flash[:notice] = I18n.t('flash.notice.destroyed', :model => Story.model_name.human)
- format.html { redirect_to comic_path(@story.comic)}
+ format.html { redirect_to '/home/stories' }
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.html { redirect_to @story }
format.json { render json: @story.errors, status: :unprocessable_entity }
end
end
end
+
end
--- /dev/null
- def self.new_t comic_id
- r = Story.max_t(comic_id)
- r.blank? ? 0 : r.to_i + 1
- end
-
- def self.max_t comic_id
- Story.maximum(:t, :conditions => ['comic_id = ?', comic_id])
- end
-
- def self.find_t comic_id, t
- Story.find(:first, :conditions => ['comic_id = ? and t = ?', comic_id, t])
- end
-
- def self.collect_t story
- r = Story.find(:all, :conditions => ['comic_id = ?', story.comic_id], :order => 't')
- r.map {|s| s.t}
- end
-
- def self.serial? ary
- i = 0
- ary.compact.sort.each do |t|
- break false unless t == i
- i += 1
- end
- ary.compact.size == i
- end
-
- def self.validate_t story
- Story.serial?(Story.collect_t(story))
- end
-
- def insert_shift
- Story.update_all('t = t + 1', ['comic_id = ? and t >= ?', self.comic_id, self.t])
- end
-
- def lesser_shift old_t
- self.t = 0 if self.t < 0
- Story.update_all('t = t + 1', ['comic_id = ? and (t >= ? and t < ?)', self.comic_id, self.t, old_t])
- end
-
- def higher_shift old_t
- nf = Story.find_t(self.comic_id, self.t)
- max_t = Story.max_t(self.comic_id).to_i
- self.t = max_t if self.t > max_t
- Story.update_all('t = t - 1', ['comic_id = ? and (t > ? and t <= ?)', self.comic_id, old_t, self.t])
- end
-
- def update_shift old_t
- if self.t > old_t
- higher_shift old_t
- else
- lesser_shift old_t
- end
- end
-
- def rotate old_t = nil
- if self.new_record?
- if self.t.blank?
- self.t = Story.new_t self.comic_id
- else
- self.insert_shift
- end
- else
- if self.t.blank?
- else
- self.update_shift old_t
- end
- end
- end
-
+class ComicStory < Peta::Leaf
+ load_manifest
+ belongs_to :author
+ belongs_to :comic
+ belongs_to :story
+
+ validates :comic_id, :presence => true, :numericality => true, :existence => {:both => false}
+ validates :story_id, :presence => true, :numericality => true, :existence => {:both => false}
+ validates :author_id, :presence => true, :numericality => true, :existence => {:both => false}
+ validates :t, :presence => true, :numericality => {:greater_than_or_equal_to => 0}
+
+ def supply_default
+ self.comic_id = nil
+ self.story_id = nil
+ self.t = nil
+ end
+
+ def overwrite operators
+ return false unless operators.author
+ self.author_id = operators.author.id
+ end
+
++ def disp_t
++ self.t + 1
++ end
++
++ def disp_t_by_text
++ I18n.t('comic_stories.show.t', :t => self.disp_t)
++ end
++
++ def title
++ self.disp_t_by_text + ':' + self.story.title
++ end
++
+ def self.public_list_order
+ 'comic_stories.updated_at desc'
+ end
+
+ def self.list_where
+ 'comics.visible > 0'
+ end
+
+ def self.by_author_list_includes
+ {
+ :comic => {
+ :author => {}
+ }
+ }
+ end
+
+ def self.play_list_where cid
+ ['comic_stories.comic_id = ?', cid]
+ end
+
+ def self.play_list scroll, author, offset = 0, limit = ScrollPanel.default_panel_size
+ ScrollPanel.where(self.play_list_where(scroll.id)).includes(ScrollPanel.list_opt).order('scroll_panels.t').offset(offset).limit(limit)
+ end
+
+ def self.list_opt
+ {
+ :comic => {
+ :author => {},
+ }
+ }
+ end
+
+ def self.list_json_opt
+ {:include => {
+ :comic => {
+ :author => {},
+ }
+ }}
+ end
+
+ def self.show_opt
+ {:include => {
+ :comic => {
+ }
+ }}
+ end
+
- self.comic.own?(operators) and self.comic.usable?(operators)
+ def allow? operators
+ return nil if self.story_id == nil or self.comic_id == nil
- ScrollPanel.transaction do
++ self.comic.own?(operators) and self.story.own?(operators)
+ end
+
+ def store operators, old_t = nil
+ res = false
- res = ScrollPanel.validate_t(self.comic_id)
++ self.class.transaction do
+ case self.allow? operators
+ when true
+ self.rotate old_t
+ when false
+ raise ActiveRecord::Forbidden
+ else
+ end
+ res = self.save
+ raise ActiveRecord::Rollback unless res
++ res = self.class.validate_t(self.comic_id)
+ unless res
+ self.errors.add :t, 'unserialized'
+ raise ActiveRecord::Rollback
+ end
+ end
+ res
+ end
+
+end
r
end
- def self.new_t scroll_id
- r = ScrollPanel.max_t(scroll_id)
- r.blank? ? 0 : r.to_i + 1
- end
-
- def self.max_t scroll_id
- ScrollPanel.maximum(:t, :conditions => ['scroll_id = ?', scroll_id])
- end
-
- def self.find_t scroll_id, t
- ScrollPanel.find(:first, :conditions => ['scroll_id = ? and t = ?', scroll_id, t])
- end
-
- def self.collect_t scroll_panel
- r = ScrollPanel.find(:all, :conditions => ['scroll_id = ?', scroll_panel.scroll_id], :order => 't')
- r.map {|sp| sp.t}
- end
-
- def self.serial? ary
- i = 0
- ary.compact.sort.each do |t|
- break false unless t == i
- i += 1
- end
- ary.compact.size == i
- end
-
- def self.validate_t scroll_panel
- ScrollPanel.serial?(ScrollPanel.collect_t(scroll_panel))
- end
-
- def insert_shift
- ScrollPanel.update_all('t = t + 1', ['scroll_id = ? and t >= ?', self.scroll_id, self.t])
- end
-
- def lesser_shift old_t
- self.t = 0 if self.t < 0
- ScrollPanel.update_all('t = t + 1', ['scroll_id = ? and (t >= ? and t < ?)', self.scroll_id, self.t, old_t])
- end
-
- def higher_shift old_t
- nf = ScrollPanel.find_t(self.scroll_id, self.t)
- max_t = ScrollPanel.max_t(self.scroll_id).to_i
- self.t = max_t if self.t > max_t
- ScrollPanel.update_all('t = t - 1', ['scroll_id = ? and (t > ? and t <= ?)', self.scroll_id, old_t, self.t])
- end
-
- def update_shift old_t
- if self.t > old_t
- higher_shift old_t
- else
- lesser_shift old_t
- end
- end
-
- def rotate old_t = nil
- if self.new_record?
- if self.t.blank?
- self.t = ScrollPanel.new_t self.scroll_id
- else
- self.insert_shift
- end
- else
- if self.t.blank?
- else
- self.update_shift old_t
- end
- end
- end
-
def allow? operators
return nil if self.scroll_id == nil or self.panel_id == nil
self.scroll.own?(operators) and self.panel.usable?(operators)
def store operators, old_t = nil
res = false
-- ScrollPanel.transaction do
++ self.class.transaction do
case self.allow? operators
when true
self.rotate old_t
end
res = self.save
raise ActiveRecord::Rollback unless res
- res = ScrollPanel.validate_t(self.scroll_id)
- res = ScrollPanel.validate_t(self)
++ res = self.class.validate_t(self.scroll_id)
unless res
self.errors.add :t, 'unserialized'
raise ActiveRecord::Rollback
res
end
- def destroy_and_shorten
- res = false
- ScrollPanel.transaction do
- ScrollPanel.update_all('t = t - 1', ['scroll_id = ? and (t > ?)', self.scroll_id, self.t])
- raise ActiveRecord::Rollback unless self.destroy
- res = true
- end
- res
- end
-
end
end
end
-- def self.new_t sheet_id
-- r = SheetPanel.max_t(sheet_id)
-- r.blank? ? 0 : r.to_i + 1
-- end
--
-- def self.max_t sheet_id
-- SheetPanel.maximum(:t, :conditions => ['sheet_id = ?', sheet_id])
-- end
--
-- def self.find_t sheet_id, t
-- SheetPanel.find(:first, :conditions => ['sheet_id = ? and t = ?', sheet_id, t])
-- end
--
-- def self.collect_t sheet_panel
-- r = SheetPanel.find(:all, :conditions => ['sheet_id = ?', sheet_panel.sheet_id], :order => 't')
-- r.map {|sp| sp.t}
-- end
--
-- def self.serial? ary
-- i = 0
-- ary.compact.sort.each do |t|
-- break false unless t == i
-- i += 1
-- end
-- ary.compact.size == i
-- end
--
-- def self.validate_t sheet_panel
-- SheetPanel.serial?(SheetPanel.collect_t(sheet_panel))
-- end
--
-- def insert_shift
-- SheetPanel.update_all('t = t + 1', ['sheet_id = ? and t >= ?', self.sheet_id, self.t])
-- end
--
-- def lesser_shift old_t
-- self.t = 0 if self.t < 0
-- SheetPanel.update_all('t = t + 1', ['sheet_id = ? and (t >= ? and t < ?)', self.sheet_id, self.t, old_t])
-- end
--
-- def higher_shift old_t
-- nf = SheetPanel.find_t(self.sheet_id, self.t)
-- max_t = SheetPanel.max_t(self.sheet_id).to_i
-- self.t = max_t if self.t > max_t
-- SheetPanel.update_all('t = t - 1', ['sheet_id = ? and (t > ? and t <= ?)', self.sheet_id, old_t, self.t])
-- end
--
-- def update_shift old_t
-- if self.t > old_t
-- higher_shift old_t
-- else
-- lesser_shift old_t
-- end
-- end
--
-- def rotate old_t = nil
-- if self.new_record?
-- if self.t.blank?
-- self.t = SheetPanel.new_t self.sheet_id
-- else
-- self.insert_shift
-- end
-- else
-- if self.t.blank?
-- else
-- self.update_shift old_t
-- end
-- end
-- end
--
def allow? operators
return nil if self.sheet_id == nil or self.panel_id == nil
self.sheet.own?(operators) and self.panel.usable?(operators)
def store operators, old_t = nil
res = false
-- SheetPanel.transaction do
++ self.class.transaction do
case self.allow? operators
when true
self.rotate old_t
end
res = self.save
raise ActiveRecord::Rollback unless res
-- res = SheetPanel.validate_t(self)
++ res = self.class.validate_t(self.sheet_id)
unless res
self.errors.add :t, 'unserialized'
raise ActiveRecord::Rollback
res
end
-- def destroy_and_shorten
-- res = false
-- SheetPanel.transaction do
-- SheetPanel.update_all('t = t - 1', ['sheet_id = ? and (t > ?)', self.sheet_id, self.t])
-- raise ActiveRecord::Rollback unless self.destroy
-- res = true
-- end
-- res
-- end
--
end
'[' + ary.map {|i| i.story_sheet_as_json(au) }.join(',') + ']'
end
-- def self.new_t story_id
-- r = StorySheet.max_t(story_id)
-- r.blank? ? 0 : r.to_i + 1
-- end
--
def self.top_sheet story, author
StorySheet.play_list(story, author).first
end
-- def self.max_t story_id
-- StorySheet.maximum(:t, :conditions => ['story_id = ?', story_id])
-- end
--
-- def self.find_t story_id, t
-- StorySheet.find(:first, :conditions => ['story_id = ? and t = ?', story_id, t])
-- end
--
-- def self.collect_t story_sheet
-- r = StorySheet.find(:all, :conditions => ['story_id = ?', story_sheet.story_id], :order => 't')
-- r.map {|sp| sp.t}
-- end
--
-- def self.serial? ary
-- i = 0
-- ary.compact.sort.each do |t|
-- break false unless t == i
-- i += 1
-- end
-- ary.compact.size == i
-- end
--
-- def self.validate_t story_sheet
-- StorySheet.serial?(StorySheet.collect_t(story_sheet))
-- end
--
-- def insert_shift
-- StorySheet.update_all('t = t + 1', ['story_id = ? and t >= ?', self.story_id, self.t])
-- end
--
-- def lesser_shift old_t
-- self.t = 0 if self.t < 0
-- StorySheet.update_all('t = t + 1', ['story_id = ? and (t >= ? and t < ?)', self.story_id, self.t, old_t])
-- end
--
-- def higher_shift old_t
-- nf = StorySheet.find_t(self.story_id, self.t)
-- max_t = StorySheet.max_t(self.story_id).to_i
-- self.t = max_t if self.t > max_t
-- StorySheet.update_all('t = t - 1', ['story_id = ? and (t > ? and t <= ?)', self.story_id, old_t, self.t])
-- end
--
-- def update_shift old_t
-- if self.t > old_t
-- higher_shift old_t
-- else
-- lesser_shift old_t
-- end
-- end
--
-- def rotate old_t = nil
-- if self.new_record?
-- if self.t.blank?
-- self.t = StorySheet.new_t self.story_id
-- else
-- self.insert_shift
-- end
-- else
-- if self.t.blank?
-- else
-- self.update_shift old_t
-- end
-- end
-- end
--
def allow? operators
return nil if self.story_id == nil or self.sheet_id == nil
self.story.own?(operators) and self.sheet.usable?(operators)
def store operators, old_t = nil
res = false
-- StorySheet.transaction do
++ self.class.transaction do
case self.allow? operators
when true
self.rotate old_t
end
res = self.save
raise ActiveRecord::Rollback unless res
-- res = StorySheet.validate_t(self)
++ res = self.class.validate_t(self.story_id)
unless res
self.errors.add :t, 'unserialized'
raise ActiveRecord::Rollback
res
end
-- def destroy_and_shorten
-- res = false
-- StorySheet.transaction do
-- StorySheet.update_all('t = t - 1', ['story_id = ? and (t > ?)', self.story_id, self.t])
-- raise ActiveRecord::Rollback unless self.destroy
-- res = true
-- end
-- res
-- end
--
end
--- /dev/null
--- /dev/null
++<tr>
++ <td>
++ <%= link_to comic_icon(:object => comic, :size => 25), comic_path(comic) %>
++ <%= link_to h(truncate(comic.title, :length => 40)), play_comic_path(comic) %>
++ (<%= comic.comic_stories.size -%>)
++ </td>
++ <td>
++ <%= distance_of_time_in_words_to_now comic.updated_at %>
++ </td>
++ <td>
++ <%= link_to author_icon(:object => comic.author, :size => 25), author_path(comic.author) %>
++ <%= link_to h(truncate(comic.author.name, :length => 12)), author_path(comic.author) %>
++ </td>
++ <td>
++ <% if comic.own? operators %>
++ <% @comic_story = ComicStory.new :comic_id => comic.id, :story_id => story.id %>
++ <%= form_for(@comic_story) do |f| %>
++ <%= f.hidden_field :comic_id %>
++ <%= f.hidden_field :t %>
++ <%= f.hidden_field :story_id %>
++ <div class="actions">
++ <%= f.submit t('comic_stories.append.comic') %>
++ </div>
++ <% end %>
++ <% end %>
++ </td>
++</tr>
++<tr>
++ <td colspan="4">
++ <%= h(truncate(comic.description, :length => 40)) %>
++ </td>
++</tr>
--- /dev/null
--- /dev/null
++<tr>
++ <td>
++ <%= link_to story_icon(:object => story, :size => 25), story_path(story) %>
++ <%= link_to author_icon(:object => story.author, :size => 17), author_path(story.author) %>
++ </td>
++ <td>
++ <%= link_to h(truncate(h(story.title), :length => 40)), story_path(story) %>
++ </td>
++ <td>
++ <%= l story.updated_at %>
++ </td>
++ <td>
++ <% @comic_story = ComicStory.new :comic_id => comic.id, :story_id => story.id -%>
++ <%= form_for(@comic_story) do |f| %>
++ <%= f.hidden_field :comic_id %>
++ <%= f.hidden_field :t %>
++ <%= f.hidden_field :story_id %>
++ <%= f.submit t('comic_stories.append.story') %>
++ <% end %>
++ </td>
++</tr>
<% @page_title = t('.title') + ':' + @item.title %>
--<h1><%= t('.title') %></h1>
--<p id="notice"><%= notice %></p>
--
++<h1><%= @item.title %></h1>
<p>
-- <b><%= t_m 'Comic.title' -%>:</b>
-- <%= link_to h(@item.title), comic_path(@item) %>
++ <b><%= t_m 'Comic.author_id' -%>:</b>
++ <%= link_to h(@item.author.name), author_path(@item.author) %>
++ <b><%= t_m 'Comic.updated_at' -%>:</b>
++ <%= l @item.updated_at %>
</p>
++<p id="notice"><%= notice %></p>
++
<p>
<b><%= t_m 'Comic.description' -%>:</b>
<%= h(@item.description) %>
</p>
--<p>
-- <b><%= t_m 'Comic.visible' -%>:</b>
-- <%= t_selected_item('comic_visible_items', @item.visible) %>
--</p>
--
--<p>
-- <b><%= t_m 'Comic.author_id' -%>:</b>
-- <%= link_to h(@item.author.name), author_path(@item.author) %>
--</p>
--
--<% @item.stories.each do |story| %>
-- <% if story.visible? @operators -%>
-- <div>
-- <%= link_to t('stories.show.t', :t => story.disp_t), story_path(story) %>
-- <%= link_to h(story.title), play_story_path(story) %>
-- </div>
++<div>
++ <% @comic_stories.each do |comic_story| %>
++ <% if comic_story.story -%>
++ <%= link_to comic_story.title, play_story_path(comic_story.story) %>
++ <% end %>
<% end %>
--<% end %>
--<p>
-- <b><%= t_m 'Comic.created_at' -%>:</b>
-- <%= l @item.created_at %>
--</p>
++</div>
++<% if @item.own? @operators -%>
<p>
-- <b><%= t_m 'Comic.updated_at' -%>:</b>
-- <%= l @item.updated_at %>
++ <b><%= t_m 'Comic.visible' -%>:</b>
++ <%= t_selected_item('comic_visible_items', @item.visible) %>
</p>
--<% if @item.own? @operators -%>
<%= link_to t('link.edit'), edit_comic_path(@item) %>
<%= link_to t('link.destroy'), comic_path(@item), :method => :delete %>
--
-- <h2>
-- <%= t('stories.index.new') %>
-- </h2>
-- <% @story = Story.new -%>
-- <% @story.supply_default -%>
-- <% @story.attributes = {:comic_id => @item.id} -%>
-- <%= render 'stories/form' %>
++ <h3><%= t('comic_stories.append.new_stories') -%></h3>
++ <table>
++ <% @new_story_items.each do |story| %>
++ <%= render 'comic_stories/append_story', :story => story, :comic => @item, :operators => @operators %>
++ <% end %>
++ </table>
<% end %>
<% else %>
<h2><%= t('stories.play.empty') %></h2>
<% end %>
--<%= render 'stories/play_footer', :story => @item, :operators => @operators %>
++<%# render 'stories/play_footer', :story => @item, :operators => @operators %>
<% if @item.own? @operators -%>
<h3><%= t('story_sheets.append.new_sheets') -%></h3>
<h1><%= t('.title') %></h1>
<p id="notice"><%= notice %></p>
-<p>
- <b><%= t_m 'Story.comic_id' -%>:</b>
- <%= link_to comic_icon(:object => @item.comic), comic_path(@item.comic) %>
- <%= link_to h(@item.comic.title), comic_path(@item.comic) %>
-</p>
-
<div>
- <%= link_to t('stories.show.t', :t => @item.disp_t), story_path(@item) %>
+ <%= link_to @item.title, story_path(@item) %>
<%= link_to_if @item, h(@item.title), play_story_path(@item) %>
</div>
<%= link_to t('link.edit'), edit_story_path(@item) %>
<%= link_to t('link.destroy'), story_path(@item), :method => :delete %>
++ <h3><%= t('comic_stories.append.new_comics') -%></h3>
++ <table>
++ <% @new_comic_items.each do |comic| %>
++ <%= render 'comic_stories/append_comic', :story => @item, :comic => comic, :operators => @operators %>
++ <% end %>
++ </table>
++
<h3><%= t('story_sheets.append.new_sheets') -%></h3>
<table>
<% @new_sheet_items.each do |sheet| %>
scroll: スクロール
scroll_panel: スクコマ
comic: コミック
+ comic_story: コミスト
story: ストーリー
story_sheet: スト紙
sheet: 用紙
scroll_panel:
scroll_id: スクロール
panel_id: コマ
- author_id: 編集者
t: No.
created_at: 作成
updated_at: 更新
author_id: 作家
created_at: 更新
updated_at: 作成
+ comic_story:
+ comic_id: コミック
+ story_id: ストーリー
+ t: No.
+ created_at: 作成
+ updated_at: 更新
story:
comic_id: コミック
title: タイトル
story_sheet:
story_id: ストーリー
sheet_id: 用紙
- author_id: 編集者
t: No.
created_at: 作成
updated_at: 更新
title: 最近更新したスクコマ
comics:
title: 最近更新したコミック
+ comic_stories:
+ title: 最近更新したコミスト
stories:
title: 最近更新したストーリー
story_sheets:
submit:
new: コミック作成
edit: コミック変更
+ comic_stories:
+ index:
+ title: コミスト一覧
+ by_comic:
+ title: コミックのコミスト一覧
+ by_story:
+ title: ストーリーのコミスト一覧
+ by_author:
+ title: 作家のコミスト一覧
+ show:
+ title: コミスト詳細
++ t: 第%{t}話
+ new:
+ title: コミスト追加
+ edit:
+ title: 並び替え
+ create:
+ title: コミスト追加
+ update:
+ title: 並び替え
+ destroy:
+ title: コミスト削除
+ submit:
+ new: コミスト作成
+ edit: コミスト変更
+ move: 移動
+ append:
+ story: このストーリーを追加する
+ comic: このコミックに追加する
+ new_stories: 最近作成したストーリー
+ new_comics: 最近作成したコミック
+ fresh_comics: 最近更新したコミック
stories:
story_sheets_count: '%{c}P'
index:
new: 新ストーリー
show:
title: ストーリー詳細
-- t: 第%{t}話
play:
title: ストーリーを読む
empty: 用紙はありません
to_scrolls: 最近更新したスクロール
to_scroll_panels: 最近更新したスクコマ
to_comics: 最近更新したコミック
+ to_comic_stories: 最近更新したコミスト
to_stories: 最近更新したストーリー
to_story_sheets: 最近更新したスト紙
to_sheets: 最近更新した用紙
post :create
end
member do
- get :scroll_panels
- get :panels
get :by_author
get :by_panel
- get :scroll_panels_count
- get :panels_count
get :count_by_author
get :count_by_panel
get :play
collection do
get :index
get :show
+ get :count
post :create
end
member do
post :create
end
member do
- get :stories
get :by_author
- get :by_me
- get :stories_count
+ get :by_story
get :count_by_author
- get :count_by_me
+ get :count_by_story
get :play
get :edit
put :update
delete :destroy
end
end
+ resources :comic_stories do
+ new do
+ get :new
+ end
+ collection do
+ get :index
+ get :show
+ get :count
+ post :create
+ end
+ member do
+ get :by_comic
+ get :by_story
+ get :by_author
+ get :count_by_comic
+ get :count_by_story
+ get :count_by_author
+ get :edit
+ put :update
+ delete :destroy
+ end
+ end
resources :stories do
new do
get :new
collection do
get :index
get :show
+ get :count
post :create
end
member do
- get :story_sheets
- get :sheets
get :by_comic
get :by_sheet
get :by_author
- get :story_sheets_count
- get :sheets_count
get :count_by_comic
get :count_by_sheet
get :count_by_author
collection do
get :index
get :show
+ get :count
post :create
end
member do
collection do
get :index
get :show
+ get :count
post :create
end
member do
collection do
get :index
get :show
+ get :count
post :create
end
member do
collection do
get :index
get :show
+ get :count
get :credit
get :search
get :list
collection do
get :index
get :show
+ get :count
get :new
post :create
get :count
collection do
get :index
get :show
+ get :count
end
member do
get :speech_balloons
collection do
get :index
get :show
+ get :count
end
member do
get :speeches
collection do
get :index
get :show
+ get :count
end
member do
get :licenses
post :create
end
member do
- get :scrolls
- get :scroll_panels
- get :comics
- get :comic_stories
- get :stories
- get :story_sheets
- get :sheets
- get :sheet_panels
- get :panels
- get :panel_pictures
- get :speech_balloons
- get :ground_pictures
- get :ground_colors
- get :scrolls_count
- get :scroll_panels_count
- get :comics_count
- get :stories_count
- get :story_sheets_count
- get :sheets_count
- get :sheet_panels_count
- get :panels_count
- get :panel_pictures_count
- get :speech_balloons_count
- get :ground_pictures_count
- get :ground_colors_count
get :edit
put :update
delete :destroy
post :create
end
member do
- get :resource_pictures
- get :resource_pictures_count
get :edit
put :update
delete :destroy
collection do
get :index
get :show
+ get :count
end
member do
#get :balloons
},\r
"by_author": {\r
"type": "filter"\r
+ },\r
+ "by_story": {\r
+ "type": "through_filter",\r
+ "args": {\r
+ "through": "comic_stories"\r
+ }\r
}\r
}\r
},\r
- "story": {\r
+ "comic_story": {\r
"lists": {\r
"public": {\r
"type": "public"\r
"private": {\r
"type": "private"\r
},\r
+ "play": {\r
+ "type": "play",\r
+ "args": {\r
+ "filter_item_name": "comic",\r
+ "filter_model_name": "comic_story",\r
+ "filter_key": "comic_id"\r
+ }\r
+ },\r
"by_comic": {\r
"type": "filter"\r
},\r
- "by_sheet": {\r
- "type": "through_filter",\r
- "args": {\r
- "through": "story_sheets"\r
- }\r
+ "by_story": {\r
+ "type": "filter"\r
},\r
"by_author": {\r
"type": "foreign_filter",\r
"type": "method"\r
}\r
}\r
+ }\r
+ }\r
+ },\r
+ "story": {\r
+ "lists": {\r
+ "public": {\r
+ "type": "public"\r
},\r
- "play": {\r
- "type": "play"\r
+ "private": {\r
+ "type": "private"\r
+ },\r
+ "by_comic": {\r
+ "type": "through_filter",\r
+ "args": {\r
+ "through": "comic_stories"\r
+ }\r
+ },\r
+ "by_sheet": {\r
+ "type": "through_filter",\r
+ "args": {\r
+ "through": "story_sheets"\r
+ }\r
+ },\r
+ "by_author": {\r
+ "type": "filter"\r
}\r
}\r
},\r
"by_speech_balloon": {\r
"type": "filter"\r
},\r
-- "by_writing_format": {\r
-- "type": "filter"\r
-- },\r
"by_author": {\r
"type": "foreign_filter",\r
"args": {\r
"author"\r
],\r
"has_many": [\r
+ "comic_stories.by_comic",\r
"stories.by_comic"\r
]\r
}\r
},\r
- "story": {\r
+ "comic_story": {\r
"column_names": [\r
"comic_id",\r
+ "story_id",\r
+ "t"\r
+ ],\r
+ "associations": {\r
+ "belongs_to": [\r
+ "comic",\r
+ "story"\r
+ ]\r
+ }\r
+ },\r
+ "story": {\r
+ "column_names": [\r
"title",\r
"description",\r
"t",\r
"visible"\r
],\r
"associations": {\r
- "belongs_to": [\r
- "comic"\r
- ],\r
+ "belongs_to": [],\r
"has_many": [\r
+ "comic_stories.by_story",\r
+ "comics.by_story",\r
"story_sheets.by_story",\r
"sheets.by_story"\r
]\r
}\r
},\r
"sheet": {\r
++ "columns": {\r
++ "visible": {\r
++ "type": "source"\r
++ }\r
++ },\r
"column_names": [\r
"caption",\r
"width",\r
}\r
},\r
"panel": {\r
++ "columns": {\r
++ "publish": {\r
++ "type": "source"\r
++ }\r
++ },\r
"column_names": [\r
"width",\r
"height",\r
"scrolls.by_author",\r
"scroll_panels.by_author",\r
"comics.by_author",\r
+ "comic_stories.by_author",\r
"stories.by_author",\r
"sheets.by_author",\r
"sheet_panels.by_author",\r
"summary": {},\r
"edit": {}\r
},\r
+ "comic_story": {\r
+ "symbol": {\r
+ "type": "default",\r
+ "args": {\r
+ "link": {\r
+ "type": "none"\r
+ }\r
+ }\r
+ },\r
+ "caption": {\r
+ "type": "none"\r
+ },\r
+ "summary": {},\r
+ "edit": {\r
+ "type": "none"\r
+ }\r
+ },\r
"story": {\r
"symbol": {},\r
"caption": {\r
"type": "default",\r
"args": {\r
"face": {\r
- "type": "method",\r
+ "type": "column",\r
"args": {\r
- "method_name": "title_with_t"\r
+ "column_name": "title"\r
}\r
},\r
"link": {\r
"author_id"\r
]\r
},\r
- "story": {\r
+ "comic_story": {\r
"fields": {\r
"comic_id": {\r
+ "tag": {\r
+ "type": "number"\r
+ }\r
+ },\r
+ "story_id": {\r
+ "tag": {\r
+ "type": "number"\r
+ }\r
+ },\r
+ "t": {\r
+ "tag": {\r
+ "type": "number"\r
+ }\r
+ },\r
+ "id": {\r
"label": {\r
"type": "none"\r
},\r
"tag": {\r
"type": "hidden"\r
}\r
- },\r
+ }\r
+ },\r
+ "field_names": [\r
+ "comic_id",\r
+ "story_id",\r
+ "t",\r
+ "id"\r
+ ]\r
+ },\r
+ "story": {\r
+ "fields": {\r
"title": {\r
"label": {\r
"args": {\r
},\r
"row_break": true\r
},\r
- "t": {\r
- "tag": {\r
- "type": "number"\r
- }\r
- },\r
"id": {\r
"label": {\r
"type": "none"\r
}\r
},\r
"field_names": [\r
- "comic_id",\r
"title",\r
"description",\r
"visible",\r
- "t",\r
"id",\r
"author_id"\r
]\r
"type": "binder",\r
"args": {}\r
},\r
+ "comic_story": {\r
+ "type": "leaf",\r
+ "args": {\r
+ "parent_model_name": "comic"\r
+ }\r
+ },\r
"story": {\r
"type": "binder",\r
"args": {}\r
"list_name": "public"\r
}\r
},\r
+ "by_story": {\r
+ "type": "list"\r
+ },\r
"by_author": {\r
"type": "list"\r
},\r
++ "play": {\r
++ "type": "list",\r
++ "args": {\r
++ "item_name": "comic_story",\r
++ "list_name": "play"\r
++ }\r
++ },\r
"show": {\r
"type": "show"\r
},\r
"list_name": "public"\r
}\r
},\r
+ "count_by_story": {\r
+ "type": "count"\r
+ },\r
"count_by_author": {\r
"type": "count"\r
},\r
}\r
}\r
},\r
- "stories": {\r
+ "comic_stories": {\r
"actions": {\r
"index": {\r
"type": "list",\r
}\r
},\r
"by_comic": {\r
+ "type": "list"\r
+ },\r
+ "by_story": {\r
+ "type": "list"\r
+ },\r
+ "by_author": {\r
+ "type": "list"\r
+ },\r
+ "show": {\r
+ "type": "show"\r
+ },\r
+ "count": {\r
+ "type": "count",\r
+ "args": {\r
+ "list_name": "public"\r
+ }\r
+ },\r
+ "count_by_comic": {\r
"type": "count"\r
},\r
- "by_sheet": {\r
+ "count_by_story": {\r
+ "type": "count"\r
+ },\r
+ "count_by_author": {\r
"type": "count"\r
},\r
+ "new": {\r
+ "type": "new"\r
+ },\r
+ "edit": {\r
+ "type": "edit"\r
+ }\r
+ }\r
+ },\r
+ "stories": {\r
+ "actions": {\r
+ "index": {\r
+ "type": "list",\r
+ "args": {\r
+ "list_name": "public"\r
+ }\r
+ },\r
+ "by_comic": {\r
+ "type": "list"\r
+ },\r
+ "by_sheet": {\r
+ "type": "list"\r
+ },\r
"by_author": {\r
"type": "list"\r
},\r
"list_name": "public"\r
}\r
},\r
+ "count_by_comic": {\r
+ "type": "count"\r
+ },\r
+ "count_by_sheet": {\r
+ "type": "count"\r
+ },\r
"count_by_author": {\r
"type": "count"\r
},\r
"list_name": "public"\r
}\r
},\r
-- "scrolls": {\r
-- "type": "list",\r
-- "args": {\r
-- "list_name": "scrolls"\r
-- }\r
-- },\r
-- "comics": {\r
-- "type": "list",\r
-- "args": {\r
-- "list_name": "comics"\r
-- }\r
-- },\r
-- "stories": {\r
-- "type": "list",\r
-- "args": {\r
-- "list_name": "stories"\r
-- }\r
-- },\r
-- "sheets": {\r
-- "type": "list",\r
-- "args": {\r
-- "list_name": "sheets"\r
-- }\r
-- },\r
-- "panels": {\r
-- "type": "list",\r
-- "args": {\r
-- "list_name": "panels"\r
-- }\r
-- },\r
-- "panel_pictures": {\r
-- "type": "list",\r
-- "args": {\r
-- "list_name": "panel_pictures"\r
-- }\r
-- },\r
-- "speech_balloons": {\r
-- "type": "list",\r
-- "args": {\r
-- "list_name": "speech_balloons"\r
-- }\r
-- },\r
-- "ground_pictures": {\r
-- "type": "list",\r
-- "args": {\r
-- "list_name": "ground_pictures"\r
-- }\r
-- },\r
-- "ground_colors": {\r
-- "type": "list",\r
-- "args": {\r
-- "list_name": "ground_colors"\r
-- }\r
-- },\r
"show": {\r
"type": "show"\r
},\r
"list_name": "public"\r
}\r
},\r
-- "resource_pictures": {\r
-- "type": "list",\r
-- "args": {\r
-- "list_name": "resource_pictures"\r
-- }\r
-- },\r
"show": {\r
"type": "show"\r
},\r
"has_many": {\r
"scroll_panels": {},\r
"panels": {\r
- "through": "scroll_panel"\r
+ "through": "scroll_panels"\r
}\r
}\r
},\r
"author": {}\r
},\r
"has_many": {\r
- "stories": {}\r
+ "comic_stories": {},\r
+ "stories": {\r
+ "through": "comic_stories"\r
+ }\r
}\r
},\r
"attributes": {\r
}\r
}\r
},\r
- "story": {\r
+ "comic_story": {\r
"associations": {\r
"belongs_to": {\r
- "comic": {}\r
+ "comic": {},\r
+ "story": {}\r
},\r
- "has_many": {\r
- "story_sheets": {},\r
- "sheets": {\r
- "through": "story_sheets"\r
- }\r
- }\r
+ "has_many": {}\r
},\r
"attributes": {\r
"comic_id": {\r
"type": "number",\r
"rules": {\r
+ "required": true,\r
+ "number": true\r
+ }\r
+ },\r
+ "story_id": {\r
+ "type": "number",\r
+ "rules": {\r
+ "required": true,\r
"number": true\r
}\r
},\r
+ "t": {\r
+ "type": "number",\r
+ "rules": {\r
+ "required": true,\r
+ "number": true,\r
+ "min": 0\r
+ }\r
+ },\r
+ "author_id": {\r
+ "type": "number",\r
+ "rules": {\r
+ "required": true,\r
+ "number": true\r
+ }\r
+ }\r
+ }\r
+ },\r
+ "story": {\r
+ "associations": {\r
+ "belongs_to": {},\r
+ "has_many": {\r
+ "comic_stories": {},\r
+ "comics": {\r
+ "through": "comic_stories"\r
+ },\r
+ "story_sheets": {},\r
+ "sheets": {\r
+ "through": "story_sheets"\r
+ }\r
+ }\r
+ },\r
+ "attributes": {\r
"title": {\r
"type": "text",\r
"rules": {}\r
"select_item_name": "story_visible_items"\r
}\r
}\r
+ },\r
+ "author_id": {\r
+ "type": "number",\r
+ "rules": {\r
+ "required": true,\r
+ "number": true\r
+ }\r
}\r
}\r
},\r