0
-# copy in the crap from will_paginate here
0
\ No newline at end of file
0
+require 'merb_paginate/finders/generic'
0
+ def self.included(base)
0
+ base.extend ClassMethods
0
+ alias_method_chain :method_missing, :paginate
0
+ # alias_method_chain :find_every, :paginate
0
+ define_method(:per_page) { 30 } unless respond_to?(:per_page)
0
+ # = Paginating finders for ActiveRecord models
0
+ # WillPaginate adds +paginate+ and +per_page+ methods to ActiveRecord::Base
0
+ # class methods and associations. It also hooks into +method_missing+ to
0
+ # intercept pagination calls to dynamic finders such as
0
+ # +paginate_by_user_id+ and translate them to ordinary finders
0
+ # (+find_all_by_user_id+ in this case).
0
+ # In short, paginating finders are equivalent to ActiveRecord finders; the
0
+ # only difference is that we start with "paginate" instead of "find" and
0
+ # that <tt>:page</tt> is required parameter:
0
+ # @posts = Post.paginate :all, :page => params[:page], :order => 'created_at DESC'
0
+ # In paginating finders, "all" is implicit. There is no sense in paginating
0
+ # a single record, right? So, you can drop the <tt>:all</tt> argument:
0
+ # Post.paginate(...) => Post.find :all
0
+ # Post.paginate_all_by_something => Post.find_all_by_something
0
+ # Post.paginate_by_something => Post.find_all_by_something
0
+ # == The importance of the <tt>:order</tt> parameter
0
+ # In ActiveRecord finders, <tt>:order</tt> parameter specifies columns for the
0
+ # <tt>ORDER BY</tt> clause in SQL. It is important to have it, since pagination only makes
0
+ # sense with ordered sets. Without the <tt>ORDER BY</tt> clause, databases aren't required
0
+ # to do consistent ordering when performing <tt>SELECT</tt> queries; this is especially true
0
+ include MerbPaginate::Finders::GenericOrmMethods # include the things that are shared
0
+ # This is the main paginating finder.
0
+ # == Special parameters for paginating finders
0
+ # * <tt>:page</tt> -- REQUIRED, but defaults to 1 if false or nil
0
+ # * <tt>:per_page</tt> -- defaults to <tt>CurrentModel.per_page</tt> (which is 30 if not overridden)
0
+ # * <tt>:total_entries</tt> -- use only if you manually count total entries
0
+ # * <tt>:count</tt> -- additional options that are passed on to +count+
0
+ # * <tt>:finder</tt> -- name of the ActiveRecord finder used (default: "find")
0
+ # All other options (+conditions+, +order+, ...) are forwarded to +find+
0
+ def paginate(*args, &block)
0
+ page, per_page, total_entries = wp_parse_options(options)
0
+ finder = (options[:finder] || 'find').to_s
0
+ # an array of IDs may have been given:
0
+ total_entries ||= (Array === args.first and args.first.size)
0
+ args.unshift(:all) if args.empty?
0
+ WillPaginate::Collection.create(page, per_page, total_entries) do |pager|
0
+ count_options = options.except :page, :per_page, :total_entries, :finder
0
+ find_options = count_options.except(:count).update(:offset => pager.offset, :limit => pager.per_page)
0
+ # @options_from_last_find = nil
0
+ pager.replace send(finder, *args, &block)
0
+ # magic counting for user convenience:
0
+ pager.total_entries = wp_count(count_options, args, finder) unless pager.total_entries
0
+ # Wraps +find_by_sql+ by simply adding LIMIT and OFFSET to your SQL string
0
+ # based on the params otherwise used by paginating finds: +page+ and
0
+ # @developers = Developer.paginate_by_sql ['select * from developers where salary > ?', 80000],
0
+ # :page => params[:page], :per_page => 3
0
+ # A query for counting rows will automatically be generated if you don't
0
+ # supply <tt>:total_entries</tt>. If you experience problems with this
0
+ # generated SQL, you might want to perform the count manually in your
0
+ def paginate_by_sql(sql, options)
0
+ WillPaginate::Collection.create(*wp_parse_options(options)) do |pager|
0
+ query = sanitize_sql(sql)
0
+ original_query = query.dup
0
+ add_limit! query, :offset => pager.offset, :limit => pager.per_page
0
+ pager.replace find_by_sql(query)
0
+ unless pager.total_entries
0
+ count_query = original_query.sub /\bORDER\s+BY\s+[\w`,\s]+$/mi, ''
0
+ count_query = "SELECT COUNT(*) FROM (#{count_query}) AS count_table"
0
+ # perform the count query
0
+ pager.total_entries = count_by_sql(count_query)
0
+ # def respond_to?(method, include_priv = false) #:nodoc:
0
+ # when :paginate, :paginate_by_sql
0
+ # super(method.to_s.sub(/^paginate/, 'find'), include_priv)
0
+ def method_missing_with_paginate(method, *args, &block) #:nodoc:
0
+ #did somebody tried to paginate? if not, let them be
0
+ unless method.to_s.index('paginate') == 0
0
+ return method_missing_without_paginate(method, *args, &block)
0
+ # paginate finders are really just find_* with limit and offset
0
+ finder = method.to_s.sub('paginate', 'find')
0
+ finder.sub!('find', 'find_all') if finder.index('find_by_') == 0
0
+ raise ArgumentError, 'parameter hash expected' unless options.respond_to? :symbolize_keys
0
+ options[:finder] = finder
0
+ paginate(*args, &block)
0
+ # Does the not-so-trivial job of finding out the total number of entries
0
+ # in the database. It relies on the ActiveRecord +count+ method.
0
+ def wp_count(options, args, finder)
0
+ excludees = [:count, :order, :limit, :offset, :readonly]
0
+ unless options[:select] and options[:select] =~ /^\s*DISTINCT\b/i
0
+ excludees << :select # only exclude the select param if it doesn't begin with DISTINCT
0
+ # count expects (almost) the same options as find
0
+ count_options = options.except *excludees
0
+ # merge the hash found in :count
0
+ # this allows you to specify :select, :order, or anything else just for the count query
0
+ count_options.update options[:count] if options[:count]
0
+ # we may have to scope ...
0
+ counter = Proc.new { count(count_options) }
0
+ # we may be in a model or an association proxy!
0
+ klass = (@owner and @reflection) ? @reflection.klass : self
0
+ count = if finder.index('find_') == 0 and klass.respond_to?(scoper = finder.sub('find', 'with'))
0
+ # scope_out adds a 'with_finder' method which acts like with_scope, if it's present
0
+ # then execute the count with the scoping provided by the with_finder
0
+ send(scoper, &counter)
0
+ elsif match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(finder)
0
+ # extract conditions from calls like "paginate_by_foo_and_bar"
0
+ attribute_names = extract_attribute_names_from_match(match)
0
+ conditions = construct_attributes_from_arguments(attribute_names, args)
0
+ with_scope(:find => { :conditions => conditions }, &counter)
0
+ count.respond_to?(:length) ? count.length : count
0
\ No newline at end of file
Comments
No one has commented yet.