major refactoring of post sets and pagination, incomplete

This commit is contained in:
albert
2011-06-03 19:47:16 -04:00
parent ce0695c606
commit ca3e9bb6db
21 changed files with 475 additions and 204 deletions

View File

@@ -4,7 +4,7 @@ class PostsController < ApplicationController
respond_to :html, :xml, :json respond_to :html, :xml, :json
def index def index
@post_set = PostSets::Post.new(params[:tags], :page => params[:page], :before_id => params[:before_id]) @post_set = PostSets::Post.new(params[:tags], params)
respond_with(@post_set) respond_with(@post_set)
end end

View File

@@ -0,0 +1,78 @@
module PaginationHelper
def smart_paginator(set, &block)
if set.page && set.page > 1000
sequential_paginator(set)
else
numbered_paginator(set, &block)
end
end
def sequential_paginator(set)
html = "<menu>"
unless set.first_page?
html << '<li>' + link_to("&laquo; Previous", params.merge(:after_id => set.first_id)) + '</li>'
end
unless set.last_page?
html << '<li>' + link_to("Next &raquo;", params.merge(:before_id => set.last_id)) + '</li>'
end
html << "</menu>"
html.html_safe
end
def numbered_paginator(set, &block)
html = "<menu>"
window = 3
if set.total_pages <= (window * 2) + 5
1.upto(set.total_pages) do |page|
html << numbered_paginator_item(page, set.current_page, &block)
end
elsif set.current_page <= window + 2
1.upto(set.current_page + window) do |page|
html << numbered_paginator_item(page, set.current_page, &block)
end
html << numbered_paginator_item("...", set.current_page, &block)
html << numbered_paginator_final_item(set.total_pages, set.current_page, &block)
elsif set.current_page >= set.total_pages - (window + 1)
html << numbered_paginator_item(1, set.current_page, &block)
html << numbered_paginator_item("...", set.current_page, &block)
(set.current_page - window).upto(set.total_pages) do |page|
html << numbered_paginator_item(page, set.current_page, &block)
end
else
html << numbered_paginator_item(1, set.current_page, &block)
html << numbered_paginator_item("...", set.current_page, &block)
(set.current_page - window).upto(set.current_page + window) do |page|
html << numbered_paginator_item(page, set.current_page, &block)
end
html << numbered_paginator_item("...", set.current_page, &block)
html << numbered_paginator_final_item(set.total_pages, set.current_page, &block)
end
html << "</menu>"
html.html_safe
end
def numbered_paginator_final_item(total_pages, current_page, &block)
if total_pages <= 1000
numbered_paginator_item(total_pages, current_page, &block)
else
""
end
end
def numbered_paginator_item(page, current_page, &block)
html = "<li>"
if page == "..."
html << "..."
elsif page == current_page
html << page.to_s
else
html << capture(page, &block)
end
html << "</li>"
html.html_safe
end
end

View File

@@ -5,6 +5,20 @@ class Favorite
"favorites_#{user_id.to_i % 10}" "favorites_#{user_id.to_i % 10}"
end end
def self.sql_order_clause(post_ids, posts_table_alias = "posts")
if post_ids.empty?
return "#{posts_table_alias}.id desc"
end
conditions = []
post_ids.each_with_index do |post_id, n|
conditions << "when #{post_id} then #{n}"
end
"case #{posts_table_alias}.id " + conditions.join(" ") + " end"
end
def self.create(attributes) def self.create(attributes)
user_id = attributes[:user_id] user_id = attributes[:user_id]
post_id = attributes[:post_id] post_id = attributes[:post_id]
@@ -27,6 +41,19 @@ class Favorite
end end
end end
def self.find_post_ids(user_id, options)
limit = options[:limit] || 1 || Danbooru.config.posts_per_page
if options[:before_id]
select_values_sql("SELECT post_id FROM #{table_name_for(user_id)} WHERE id < ? ORDER BY id DESC LIMIT ?", options[:before_id], limit)
elsif options[:after_id]
select_values_sql("SELECT post_id FROM #{table_name_for(user_id)} WHERE id > ? ORDER BY id ASC LIMIT ?", options[:after_id], limit).reverse
elsif options[:offset]
select_values_sql("SELECT post_id FROM #{table_name_for(user_id)} ORDER BY id DESC LIMIT ? OFFSET ?", limit, options[:offset])
else
select_values_sql("SELECT post_id FROM #{table_name_for(user_id)} ORDER BY id DESC LIMIT ?", limit)
end
end
def self.exists?(conditions) def self.exists?(conditions)
if conditions[:user_id] && conditions[:post_id] if conditions[:user_id] && conditions[:post_id]
select_value_sql("SELECT 1 FROM #{table_name_for(conditions[:user_id])} WHERE user_id = ? AND post_id = ?", conditions[:user_id], conditions[:post_id]) select_value_sql("SELECT 1 FROM #{table_name_for(conditions[:user_id])} WHERE user_id = ? AND post_id = ?", conditions[:user_id], conditions[:post_id])
@@ -39,26 +66,30 @@ class Favorite
end end
end end
private def self.destroy_for_post_and_user(post_id, user_id)
def self.destroy_for_post_and_user(post_id, user_id) execute_sql("DELETE FROM #{table_name_for(user_id)} WHERE post_id = #{post_id} AND user_id = #{user_id}")
execute_sql("DELETE FROM #{table_name_for(user_id)} WHERE post_id = #{post_id} AND user_id = #{user_id}") end
end
def self.destroy_for_post(post) def self.destroy_for_post(post)
0.upto(9) do |i| 0.upto(9) do |i|
execute_sql("DELETE FROM favorites_#{i} WHERE post_id = #{post.id}") execute_sql("DELETE FROM favorites_#{i} WHERE post_id = #{post.id}")
end
end end
end
def self.destroy_for_user(user) def self.destroy_for_user(user)
execute_sql("DELETE FROM #{table_name_for(user)} WHERE user_id = #{user.id}") execute_sql("DELETE FROM #{table_name_for(user)} WHERE user_id = #{user.id}")
end end
def self.select_value_sql(sql, *params) def self.select_value_sql(sql, *params)
ActiveRecord::Base.select_value_sql(sql, *params) ActiveRecord::Base.select_value_sql(sql, *params)
end end
def self.execute_sql(sql, *params) def self.select_values_sql(sql, *params)
ActiveRecord::Base.execute_sql(sql, *params) ActiveRecord::Base.select_values_sql(sql, *params)
end end
def self.execute_sql(sql, *params)
ActiveRecord::Base.execute_sql(sql, *params)
end
end end

View File

@@ -1,45 +1,78 @@
# A PostSet represents a paginated slice of posts. It is used in conjunction
# with the helpers to render the paginator.
#
# Usage:
#
# @post_set = PostSets::Base.new(params)
# @post_set.extend(PostSets::Sequential)
# @post_set.extend(PostSets::Post)
module PostSets module PostSets
class Base class Base
attr_accessor :page, :before_id, :count, :posts attr_reader :params, :posts
delegate :to_xml, :to_json, :to => :posts
def initialize(options = {}) def initialize(params)
@page = options[:page] ? options[:page].to_i : 1 @params = params
@before_id = options[:before_id]
load_posts
end end
def has_wiki? # Should a return a paginated array of posts. This means it should have
false # at most <limit> elements.
end def posts
def use_sequential_paginator?
!use_numbered_paginator?
end
def use_numbered_paginator?
before_id.nil?
end
def load_posts
raise NotImplementedError raise NotImplementedError
end end
def to_xml # Does this post set have a valid wiki page representation?
posts.to_xml def has_wiki?
raise NotImplementedError
end end
def to_json # Should return an array of strings representing the tags.
posts.to_json def tags
raise NotImplementedError
end
# Given an ActiveRelation object, perform the necessary pagination to
# extract at most <limit> elements. Should return an array.
def slice(relation)
raise NotImplementedError
end
# For cases where we're not relying on the default pagination
# implementation (for example, if the ids are cached in a string)
# then pass in the offset/before_id/after_id parameters here.
def pagination_options
raise NotImplementedError
end
# This method should throw an exception if for whatever reason the query
# is invalid or forbidden.
def validate
end
# Clear out any memoized instance variables.
def reload
@posts = nil
@presenter = nil
@tag_string = nil
end
def tag_string
@tag_string ||= tags.join(" ")
end
def is_first_page?
raise NotImplementedError
end
def is_last_page?
posts.size == 0
end end
def presenter def presenter
@presenter ||= PostSetPresenter.new(self) @presenter ||= PostSetPresenter.new(self)
end end
def offset
((page < 1) ? 0 : (page - 1)) * count
end
def limit def limit
Danbooru.config.posts_per_page Danbooru.config.posts_per_page
end end

View File

@@ -1,18 +1,29 @@
module PostSets module PostSets
class Favorite < Base module Favorite
attr_accessor :user def user
@user ||= User.find(params[:id])
def initialize(user)
@user = user
super()
end end
def tags def tags
"fav:#{user.name}" @tags ||= ["fav:#{user.name}"]
end end
def load_posts def has_wiki?
@posts = user.favorite_posts(:before_id => before_id) false
end
def reload
super
@user = nil
@count = nil
end
def count
@count ||= Favorite.count(user.id)
end
def posts
@posts ||= user.favorites(pagination_options)
end end
end end
end end

View File

@@ -0,0 +1,35 @@
module PostSets
module Numbered
attr_reader :page
def initialize(params)
super
@page = options[:page] ? options[:page].to_i : 1
end
def total_pages
@total_pages ||= (count / limit.to_f).ceil.to_i
end
def reload
super
@total_pages = nil
end
def slice(relation)
relation.offset(offset).all
end
def pagination_options
{:offset => offset}
end
def is_first_page?
offset == 0
end
def offset
((page < 1) ? 0 : (page - 1)) * limit
end
end
end

View File

@@ -1,33 +1,30 @@
# This only works with the numbered paginator because of the way
# the association is stored.
module PostSets module PostSets
class Pool < Base module Pool
attr_reader :pool def pool
@pool ||= Pool.find(params[:id])
def initialize(pool, options = {})
@pool = pool
@count = pool.post_id_array.size
super(options)
end end
def tags def tags
"pool:#{pool.name}" ["pool:#{pool.name}"]
end end
def load_posts def has_wiki?
@posts = pool.posts(:limit => limit, :offset => offset).order("posts.id") true
end end
def sorted_posts def count
sort_posts(@posts) pool.post_count
end end
private def posts
def sort_posts(posts) @posts ||= pool.posts(pagination_options)
posts_by_id = posts.inject({}) do |hash, post| end
hash[post.id] = post
hash
end
@pool.post_id_array.map {|x| posts_by_id[x]} def reload
super
@pool = nil
end end
end end
end end

View File

@@ -1,76 +1,54 @@
module PostSets module PostSets
class Post < Base module Post
class Error < Exception ; end class Error < Exception ; end
attr_accessor :tags, :errors, :count attr_accessor :tags, :count, :wiki_page, :artist, :suggestions
attr_accessor :wiki_page, :artist, :suggestions
def initialize(tags, options = {}) def tags
super(options) @tags ||= Tag.normalize(params[:tags])
@tags = Tag.normalize(tags) end
@errors = []
load_associations def count
load_suggestions @count ||= ::Post.fast_count(tag_string)
validate end
def posts
@posts ||= slice(::Post.tag_match(tags).limit(limit))
end
def reload
super
@tags = nil
@tag_string = nil
@count = nil
@wiki_page = nil
@artist = nil
end
def wiki_page
@wiki_page ||= ::WikiPage.titled(tag_string).first
end
def artist
@artist ||= ::Artist.find_by_name(tag_string)
end end
def has_wiki? def has_wiki?
is_single_tag? is_single_tag?
end end
def has_errors?
errors.any?
end
def offset
x = (page - 1) * limit
if x < 0
x = 0
end
x
end
def is_single_tag? def is_single_tag?
tag_array.size == 1 tag_array.size == 1
end end
def date_tag
tag_array.grep(/date:/).first
end
def load_associations
if is_single_tag?
@wiki_page = ::WikiPage.titled(tags).first
@artist = ::Artist.find_by_name(tags)
end
end
def load_posts
@count = ::Post.fast_count(tags)
@posts = ::Post.tag_match(tags).before_id(before_id).all(:order => "posts.id desc", :limit => limit, :offset => offset)
end
def load_suggestions
if count < limit && is_single_tag?
@suggestions = Tag.find_suggestions(tags)
else
@suggestions = []
end
end
def tag_array def tag_array
@tag_array ||= Tag.scan_query(tags) @tag_array ||= Tag.scan_query(tags)
end end
def tag
tag_array.first
end
def validate def validate
super
validate_page validate_page
validate_query_count validate_query_count
rescue Error => x
@errors << x.to_s
end end
def validate_page def validate_page

View File

@@ -0,0 +1,29 @@
module PostSets
module Sequential
attr_reader :before_id, :after_id
def initialize(params)
super
@before_id = params[:before_id]
@after_id = params[:after_id]
end
def slice(relation)
if before_id
relation.where("id < ?", before_id).all
elsif after_id
relation.where("id > ?", after_id).order("id asc").all.reverse
else
relation.all
end
end
def pagination_options
{:before_id => before_id, :after_id => after_id}
end
def is_first_page?
before_id.nil?
end
end
end

View File

@@ -1,34 +1,29 @@
module PostSets module PostSets
class WikiPage < Base module WikiPage
attr_reader :tag_name def wiki_page
@wiki_page ||= begin
def initialize(tag_name) if params[:id]
@tag_name = tag_name ::WikiPage.find(params[:id])
super() elsif params[:tags]
::WikiPage.titled(params[:tags]).first
end
end
end end
def load_posts def has_wiki?
@posts = ::Post.tag_match(tag_name).all(:order => "posts.id desc", :limit => limit, :offset => offset) true
end
def limit
8
end
def offset
0
end end
def tags def tags
[@tag_name] @tags ||= Tag.normalize(wiki_page.title)
end end
def use_sequential_paginator? def posts
false @posts ||= slice(::Post.tag_match(tag_string))
end end
def use_numbered_paginator? def count
false @count ||= ::Post.fast_count(tag_string)
end end
end end
end end

View File

@@ -72,9 +72,9 @@ class Pool < ActiveRecord::Base
def posts(options = {}) def posts(options = {})
offset = options[:offset] || 0 offset = options[:offset] || 0
limit = options[:limit] || 20 limit = options[:limit] || Danbooru.config.posts_per_page
ids = post_id_array[offset, limit] ids = post_id_array[offset, limit]
Post.where(["id IN (?)", ids]) Post.where(["id IN (?)", ids]).order(Favorite.sql_order_clause(ids))
end end
def post_id_array def post_id_array

View File

@@ -1,6 +1,7 @@
class Post < ActiveRecord::Base class Post < ActiveRecord::Base
class ApprovalError < Exception ; end class ApprovalError < Exception ; end
class DisapprovalError < Exception ; end class DisapprovalError < Exception ; end
class SearchError < Exception ; end
attr_accessor :old_tag_string, :old_parent_id attr_accessor :old_tag_string, :old_parent_id
after_destroy :delete_files after_destroy :delete_files
@@ -39,6 +40,7 @@ class Post < ActiveRecord::Base
scope :available_for_moderation, lambda {where(["id NOT IN (SELECT pd.post_id FROM post_disapprovals pd WHERE pd.user_id = ?)", CurrentUser.id])} scope :available_for_moderation, lambda {where(["id NOT IN (SELECT pd.post_id FROM post_disapprovals pd WHERE pd.user_id = ?)", CurrentUser.id])}
scope :hidden_from_moderation, lambda {where(["id IN (SELECT pd.post_id FROM post_disapprovals pd WHERE pd.user_id = ?)", CurrentUser.id])} scope :hidden_from_moderation, lambda {where(["id IN (SELECT pd.post_id FROM post_disapprovals pd WHERE pd.user_id = ?)", CurrentUser.id])}
scope :before_id, lambda {|id| id.present? ? where(["posts.id < ?", id]) : where("TRUE")} scope :before_id, lambda {|id| id.present? ? where(["posts.id < ?", id]) : where("TRUE")}
scope :after_id, lambda {|id| id.present? ? where("posts.id > ?", id) : where("true")}
scope :tag_match, lambda {|query| Post.tag_match_helper(query)} scope :tag_match, lambda {|query| Post.tag_match_helper(query)}
search_methods :tag_match search_methods :tag_match
@@ -374,36 +376,33 @@ class Post < ActiveRecord::Base
Favorite.destroy_for_post(self) Favorite.destroy_for_post(self)
end end
def add_favorite(user) def favorited_by?(user_id)
if user.is_a?(ActiveRecord::Base) fav_string =~ /(?:\A| )fav:#{user_id}(?:\Z| )/
user_id = user.id end
else
user_id = user def add_favorite(user_id)
if user_id.is_a?(ActiveRecord::Base)
user_id = user_id.id
end
if favorited_by?(user_id)
return false
end end
return false if fav_string =~ /(?:\A| )fav:#{user_id}(?:\Z| )/
self.fav_string += " fav:#{user_id}" self.fav_string += " fav:#{user_id}"
self.fav_string.strip! self.fav_string.strip!
update_attribute(:fav_string, fav_string)
# in order to avoid rerunning the callbacks, just update through raw sql
execute_sql("UPDATE posts SET fav_string = ? WHERE id = ?", fav_string, id)
Favorite.create(:user_id => user_id, :post_id => id) Favorite.create(:user_id => user_id, :post_id => id)
end end
def remove_favorite(user) def remove_favorite(user_id)
if user.is_a?(ActiveRecord::Base) if user_id.is_a?(ActiveRecord::Base)
user_id = user.id user_id = user_id.id
else
user_id = user
end end
self.fav_string.gsub!(/(?:\A| )fav:#{user_id}(?:\Z| )/, " ") self.fav_string.gsub!(/(?:\A| )fav:#{user_id}(?:\Z| )/, " ")
self.fav_string.strip! self.fav_string.strip!
update_attribute(:fav_string, fav_string)
# in order to avoid rerunning the callbacks, just update through raw sql
execute_sql("UPDATE posts SET fav_string = ? WHERE id = ?", fav_string, id)
Favorite.destroy(:user_id => user_id, :post_id => id) Favorite.destroy(:user_id => user_id, :post_id => id)
end end
@@ -413,9 +412,9 @@ class Post < ActiveRecord::Base
end end
module SearchMethods module SearchMethods
class SearchError < Exception ; end
def add_range_relation(arr, field, relation) def add_range_relation(arr, field, relation)
return relation if arr.nil?
case arr[0] case arr[0]
when :eq when :eq
relation.where(["#{field} = ?", arr[1]]) relation.where(["#{field} = ?", arr[1]])
@@ -513,7 +512,7 @@ class Post < ActiveRecord::Base
relation = add_range_relation(q[:character_tag_count], "posts.tag_count_character", relation) relation = add_range_relation(q[:character_tag_count], "posts.tag_count_character", relation)
relation = add_range_relation(q[:tag_count], "posts.tag_count", relation) relation = add_range_relation(q[:tag_count], "posts.tag_count", relation)
if q[:md5].any? if q[:md5]
relation = relation.where(["posts.md5 IN (?)", q[:md5]]) relation = relation.where(["posts.md5 IN (?)", q[:md5]])
end end
@@ -525,11 +524,11 @@ class Post < ActiveRecord::Base
relation = relation.where("posts.is_deleted = TRUE") relation = relation.where("posts.is_deleted = TRUE")
end end
if q[:source].is_a?(String) if q[:source]
relation = relation.where(["posts.source LIKE ? ESCAPE E'\\\\'", q[:source]]) relation = relation.where(["posts.source LIKE ? ESCAPE E'\\\\'", q[:source]])
end end
if q[:subscriptions].any? if q[:subscriptions]
relation = add_tag_subscription_relation(q[:subscriptions], relation) relation = add_tag_subscription_relation(q[:subscriptions], relation)
end end

View File

@@ -208,7 +208,7 @@ class Tag < ActiveRecord::Base
end end
def parse_query(query, options = {}) def parse_query(query, options = {})
q = Hash.new {|h, k| h[k] = []} q = {}
q[:tags] = { q[:tags] = {
:related => [], :related => [],
:include => [], :include => [],
@@ -237,6 +237,7 @@ class Tag < ActiveRecord::Base
q[:tags][:related] << "fav:#{User.name_to_id($2)}" q[:tags][:related] << "fav:#{User.name_to_id($2)}"
when "sub" when "sub"
q[:subscriptions] ||= []
q[:subscriptions] << $2 q[:subscriptions] << $2
when "md5" when "md5"

View File

@@ -117,16 +117,13 @@ class User < ActiveRecord::Base
end end
module FavoriteMethods module FavoriteMethods
def favorite_posts(options = {}) def favorites(options = {})
favorites_table = Favorite.table_name_for(id) post_ids = Favorite.find_post_ids(id, options)
if options[:before_id] if post_ids.any?
before_id_sql_fragment = ["favorites.id < ?", options[:before_id]] Post.where("id in (?)", post_ids).order(Favorite.sql_order_clause(post_ids))
else else
before_id_sql_fragment = "TRUE" Post.where("false")
end end
limit = options[:limit] || 20
Post.joins("JOIN #{favorites_table} AS favorites ON favorites.post_id = posts.id").where("favorites.user_id = ?", id).where(before_id_sql_fragment).order("favorite_id DESC").limit(limit).select("posts.*, favorites.id AS favorite_id")
end end
end end

View File

@@ -0,0 +1,58 @@
module Paginators
class Numbered
attr_reader :template, :source
delegate :url, :total_pages, :current_page, :to => :source
def initialize(template, source)
@template = template
@source = source
end
def pagination_html
html = "<menu>"
window = 3
if total_pages <= (window * 2) + 5
1.upto(total_pages) do |page|
html << pagination_item(page, current_page)
end
elsif current_page <= window + 2
1.upto(current_page + window) do |page|
html << pagination_item(page, current_page)
end
html << pagination_item("...", current_page)
html << pagination_item(total_pages, current_page)
elsif current_page >= total_pages - (window + 1)
html << pagination_item(1, current_page)
html << pagination_item("...", current_page)
(current_page - window).upto(total_pages) do |page|
html << pagination_item(page, current_page)
end
else
html << pagination_item(1, current_page)
html << pagination_item("...", current_page)
(current_page - window).upto(current_page + window) do |page|
html << pagination_item(page, current_page)
end
html << pagination_item("...", current_page)
html << pagination_item(total_pages, current_page)
end
html << "</menu>"
html.html_safe
end
protected
def pagination_item(page, current_page)
html = "<li>"
if page == "..."
html << "..."
elsif page == current_page
html << page.to_s
else
html << template.link_to(page, url(template, :page => page))
end
html << "</li>"
html.html_safe
end
end
end

View File

@@ -15,6 +15,7 @@ module Paginators
[1, post_set.page].max [1, post_set.page].max
end end
# TODO: this is not compatible with paginating favorites
def sequential_link(template) def sequential_link(template)
template.posts_path(:tags => template.params[:tags], before_id => post_set.posts[-1].id, :page => nil) template.posts_path(:tags => template.params[:tags], before_id => post_set.posts[-1].id, :page => nil)
end end

View File

@@ -0,0 +1,29 @@
module Paginators
class Sequential
attr_reader :template, :source
delegate :url, :to => :source
def initialize(template, source)
@template = template
@source = source
end
def pagination_html
html = "<menu>"
html << '<li>' + template.link_to("&laquo; Previous", prev_url) + '</li>'
if next_url
html << '<li>' + template.link_to("Next &raquo;", next_url) + '</li>'
end
html << "</menu>"
html.html_safe
end
def prev_url
template.request.env["HTTP_REFERER"]
end
def next_url
@next_url ||= url(template)
end
end
end

View File

@@ -1,11 +1,5 @@
<div id="c-posts"> <div id="c-posts">
<div id="a-index"> <div id="a-index">
<% if @post_set.suggestions.any? %>
<div class="notice">
Maybe you meant: <%= @post_set.suggestions.map {|x| link_to(x, posts_path(:tags => x), :class => "tag-type-#{Tag.type_name(x)}" )}.to_sentence(:last_word_connector => ", or ", :two_words_connector => " or ") %>
</div>
<% end %>
<aside id="sidebar"> <aside id="sidebar">
<section id="search-box"> <section id="search-box">
<h1>Search</h1> <h1>Search</h1>

View File

@@ -5,5 +5,7 @@
<div class="clearfix"></div> <div class="clearfix"></div>
<div class="paginator"> <div class="paginator">
<%= post_set.presenter.pagination_html(self) %> <%= smart_paginator(post_set) do |page| %>
<%= link_to(page, posts_path(:page => page, :tags => params[:tags])) %>
<% end %>
</div> </div>

View File

@@ -1,5 +1,7 @@
<div id="c-uploads"> <div id="c-uploads">
<div id="a-new"> <div id="a-new">
<h1>Upload Post</h1>
<div id="upload-guide-notice"> <div id="upload-guide-notice">
<p>Before uploading, please read the <%= link_to "how to upload guide", wiki_pages_path(:title => "howto:upload") %>.</p> <p>Before uploading, please read the <%= link_to "how to upload guide", wiki_pages_path(:title => "howto:upload") %>.</p>
</div> </div>

View File

@@ -6,6 +6,7 @@ class CreatePools < ActiveRecord::Migration
t.column :description, :text t.column :description, :text
t.column :is_active, :boolean, :null => false, :default => true t.column :is_active, :boolean, :null => false, :default => true
t.column :post_ids, :text, :null => false, :default => "" t.column :post_ids, :text, :null => false, :default => ""
t.column :post_count, :integer, :null => false, :default => 0
t.timestamps t.timestamps
end end