I made a new pagination library for the NamedScope era. You can use will_paginate for ordinary case. It must be better than the young PaginationScope library. But if you want to paginate with complicated chained named_scopes, this is suitable.

Usage

At first, include the module into your model class.

   1  class Post
   2    include PaginationScope

By this, the scope named "paginate" is made.

And then, in the controller of which you want to use pagination, you can get the scope for pagination like this.

   1  class PostsController < ApplicationController
   2    def index
   3      @posts = Post.not_deleted.paginate(params[:page], 10)

Finally, the pagination links are generated by calling the view helper, like this.

   1  <%= paginate @posts %>

Have fun!

posted by Png takiuchi on Sat 16 Aug 2008 at 23:58

named_scopeによるPagination を行うためのGemを作りました。 通常はwill_paginateを利用するほうがいいと思いますが、 :joinsを含む複雑なnamed_scopeを介してpaginationを行いたい場合には、 利用すると便利かもしれません。

pagination_scope

使い方

まず、モデルクラスの中でincludeします。

   1  class Post
   2    include PaginationScope
   3  end

これによって、Postクラスにpaginateというnamed_scopeが作成されます。

続いて、Paginationを利用したいコントローラのアクションメソッド内で、

   1  class PostsController < ApplicationController
   2    def index
   3      @posts = Post.not_deleted.paginate(params[:page], 10)

のようにScopeを取得します。

続いて、Viewで以下のようにPagination用HTMLを生成します。

   1  <%= paginate @posts %>

paginateメソッドは PaginationScope によって導入されるViewヘルパーです。

posted by Png genki on Sat 16 Aug 2008 at 23:25

Railsアプリケーションでpaginationといえば、 will_paginate等のプラグインやGemを使うのが一般的だと思います。 しかし、named_scopeでjoinsを使った場合にうまく paginationができなかったので、 named_scopeだけを使ってpaginationする方法を考えてみました。

まずは以下のようなnamed_scopeを作ります。 以下の例はPostクラスで宣言される事を想定しています。

   1  named_scope :paginate, proc{|page, per_page|
   2    {:offset => per_page*((page || 1).to_i - 1),
   3     :limit => per_page}} do
   4      def count
   5        proxy_scope.count(:group => 'posts.id').size
   6      end
   7      def num_pages
   8        (count.to_f/proxy_options[:limit]).ceil
   9      end
  10      def page
  11        proxy_options[:offset]/proxy_options[:limit] + 1
  12      end
  13      def pages(window = 5, left = 2, right = 2)
  14        (1..num_pages).inject([]) do |result, i|
  15          i <= left || (num_pages - i) < right ||
  16            (i-page).abs < window ? result << i :
  17              (result.last.nil? ? result : result << nil)
  18        end
  19      end
  20    end

countを再定義しているのは、:joinsを含む別なnamed_scopeをチェーンした時に、正しいcountを求めるためです。

コントローラでは、以下のようにScopeを取得します。

   1  @posts = Post.paginate(params[:page], 5)

Viewでは以下のように記述します。

   1  <% if @posts.page > 1 %>
   2    <%= link_to '&laquo; Newer',
   3        url_for(:page => @posts.page - 1) %>
   4  <% else %>
   5    &laquo; Newer
   6  <% end %>
   7  <% @posts.pages.each do |i| %>
   8    <% if i.nil? %>
   9      ...
  10    <% elsif i == @posts.page %>
  11      <%= i %>
  12    <% else %>
  13      <%= link_to i, url_for(:page => i) %>
  14    <% end %>
  15  <% end %>
  16  <% if @posts.page < @posts.num_pages %>
  17    <%= link_to 'Older &raquo;',
  18        url_for(:page => @posts.page + 1) %>
  19  <% else %>
  20    Older &raquo;
  21  <% end %>

posted by Png genki on Sat 16 Aug 2008 at 21:10

昨日に引き続きIntegerに関して。 個人的に、Integerブームが起こってます。

Integerに関しては、http://www.ruby-doc.orgのClass: Integerを参照のこと。

今日は最大公約数と最小公倍数を同時に返してくれるInteger#gcdlcmについてです。

このInteger#gcdlcmの実装が気に入らない!!

どこが気に入らないのかという本題に入る前に、Integer#lcmについての実装を見てみよう!

   1  # File lib/rational.rb, line 457
   2    def lcm(other)
   3      if self.zero? or other.zero?
   4        0
   5      else
   6        (self.div(self.gcd(other)) * other).abs
   7      end
   8    end

オーソドックスなの最小公倍数の求め方。 ここではあまり問題にしない。

このコードをよーく覚えておいてください。

ここからが本題です。

Integer#gcdlcmの実装を見て見る。

   1  # File lib/rational.rb, line 473
   2    def gcdlcm(other)
   3      gcd = self.gcd(other)
   4      if self.zero? or other.zero?
   5        [gcd, 0]
   6      else
   7        [gcd, (self.div(gcd) * other).abs]
   8      end
   9    end

Integer#lcmにそっくり!

・・・って、Integer#lcmのコードにInteger#gcdいれただけじゃないですか・・・。

せっかくこのコードの直前で、Integer#lcmを定義してるのに、何で使わないんやろうか・・・。

   1  def gcdlcm(other)
   2    return [self.gcd(other), self.lcm(other)]
   3  end

という風に書いても不都合はなさそうやけど・・?

むしろ、こういう風に書いてくれたほうが、気持ちいいんやけども。

ん~、Integerには謎がいっぱいや。

posted by Png y_tsuda on Fri 15 Aug 2008 at 04:06

今回はブログ左上に表示されるアイコンの設定の仕方について説明します。

ログインをしていただき、右上にあるsettingsをクリックします。

mihon1.PNG
Accountの画面の左側にある灰色の長方形の下にある「Upload」をクリックします。
「blog.s21g.comでアップロードするファイルを選択します」というウインドウが表示されるので、アイコンにしたい画像を選択します。
わずかな時間の後で、画像が表示されます。

これでアイコンが表示されるようになります。

posted by Png mari on Thu 14 Aug 2008 at 02:05

Rubyには、最大公約数を求めるInteger#gcd と Integer#gcd2がある。 「gcd"2"ってなんやねん!」と気になったので、実装を見てみた。

   1  # File lib/mathn.rb, line 19
   2    def gcd2(int)
   3      a = self.abs
   4      b = int.abs
   5      a, b = b, a if a < b
   6      
   7      pd_a = a.prime_division
   8      pd_b = b.prime_division
   9      
  10      gcd = 1
  11      for pair in pd_a
  12        as = pd_b.assoc(pair[0])
  13        if as
  14          gcd *= as[0] ** [as[1], pair[1]].min
  15        end
  16      end
  17      return gcd
  18    end

2数を因数分解し、どちらにもある数をかけていくと言う強引なものだった。

ついでにInteger#gcdのほうも見てみた。

   1  # File lib/rational.rb, line 438
   2    def gcd(other)
   3      min = self.abs
   4      max = other.abs
   5      while min > 0
   6        tmp = min
   7        min = max % min
   8        max = tmp
   9      end
  10      max
  11    end

コチラは、ユークリッドの互除法。 シンプルだ。

参考までに、この2つに関してベンチマークしてみた。

  • コード

       1  require 'mathn'
       2  require 'benchmark'
       3  
       4  Benchmark.bm do |x|
       5    x.report("Integer#gcd :"){ 12345.gcd(123456789) }
       6    x.report("Integer#gcd2:"){ 12345.gcd2(123456789) }
       7  end
    

  • 結果

       1        user     system      total        real
       2  Integer#gcd :  0.000000   0.000000   0.000000 (  0.000000)
       3  Integer#gcd2:  0.516000   0.000000   0.516000 (  0.516000)
    

結果は当たり前といったら当たり前なんやけども、Integer#gcd2のほうが遅かった。

何でInteger#gcdとInteger#gcd2の2つが存在するんやろ・・・。

というか、Integer#gcd2が何で存在しているのかが不思議!!

何かメリットでもあるんやろか・・・?

posted by Png y_tsuda on Thu 14 Aug 2008 at 00:14

以前一度紹介しましたが、本来入るべきでないcompadd が補完候補に出てしまっていたので、 xargsコマンドを使うように書き直しました。

   1  _cap () {
   2    compadd `cap -T | grep '^cap ' | sed 's/^cap //' | sed 's/ .*//' | xargs`
   3  }
   4  
   5  compdef _cap cap

posted by Png genki on Wed 13 Aug 2008 at 17:47

RSpecを使ってViewのスペックを書く時のメモ。

  • RSS Builder等を使っている場合も、renderでOk
       1  render 'articles/index.rss.builder'
    
  • renderはデフォルトではlayoutを伴わないので、必要に応じて明示的に指定する。
       1  render 'articles/index', :layout => 'application'
    
posted by Png genki on Wed 13 Aug 2008 at 15:25

   1  module Enumerable
   2    def take_while
   3      inject([]) do |xs, x|
   4        yield x or break xs
   5        xs << x
   6      end
   7    end
   8  end

posted by Png faerie on Tue 12 Aug 2008 at 20:34

サーバーを再起動したらmysqlが起動していなかった。 サービスとして登録するには以下。

   1  # chkconfig --list mysqld
   2  mysqld 0:off 1:off 2:off 3:off 4:off 5:off 6:off
   3  #chkconfig --level 345 mysqld on
   4  #chkconfig --list mysqld
   5  mysqld 0:off 1:off 2:off 3:on 4:on 5:on 6:off

posted by Face ysakaki on Tue 12 Aug 2008 at 17:22