Rails kaminariにモンキーパッチをあててmetaタグをいい感じにする。
Railsでページネーションを実装するライブラリ、kaminariに対してモンキーパッチを当てました。
人生初のモンキーパッチでもあったのでやったことをまとめておこうと思います。
なにをやるのか?
環境は、
Ruby 2.3.0
Rails 5.0.0
kaminari 0.17.0
今回モンキーパッチを当てたのはRailsでよく用いられるGemのkaminariです。
kaminariに実装してあるrel_next_prev_link_tagsというメソッドの動きを変えて課題を解決しました。
どうやったのか?
kaminariにはページネーションを実装した際に次ページリンクのmetaタグを簡単に実装してくれるメソッドrel_next_prev_link_tagsがあります。
このメソッドの引数にオブジェクトを渡せば簡単に実装できるため非常に便利です。
# Somewhere in body: # <% content_for :head do %> # <%= rel_next_prev_link_tags @items %> # <% end %> # # #-> <link rel="next" href="/items/page/3" /><link rel="prev" href="/items/page/1" /> # def rel_next_prev_link_tags(scope, options = {}) next_page = Kaminari::Helpers::NextPage.new self, options.reverse_merge(:current_page => scope.current_page) prev_page = Kaminari::Helpers::PrevPage.new self, options.reverse_merge(:current_page => scope.current_page) output = String.new output << tag(:link, :rel => "next", :href => next_page.url) if scope.next_page.present? output << tag(:link, :rel => "prev", :href => prev_page.url) if scope.prev_page.present? output.html_safe end
<%= rel_next_prev_link_tags @items %> <link rel="next" href="/items?page=3" /> <link rel="prev" href="/items?page=1" />
上記のlinkが生成されます。楽チンですね
しかしこのリンクではGoogle検索エンジン側ではあまり良しとはされていないようで、ドメインなども含めたリンクを生成したいという課題にぶつかりました。
rel="next"とrel="prev" の使い方
Google、ページネーション問題を解決するrel=“next”タグとrel=“prev”タグをサポート開始 | 海外SEO情報ブログ
課題
生成されるlinkをドメインも含めたものにしたい。
現状
<link rel="next" href="/items?page=3" /> <link rel="prev" href="/items?page=1" />
これを、
GOAL
<link rel="next" href="http://hoge.js/items?page=3"> <link rel="prev" href="http://hoge.js/itemspage=1">
にしたいと思います。
方法
/config/initializers/kaminari_config.rb
Kaminari.configure do |config| config.default_per_page = 15 # config.max_per_page = nil # config.window = 4 # config.outer_window = 0 # config.left = 0 # config.right = 0 # config.page_method_name = :page # config.param_name = :page end module KaminariPatch def rel_next_prev_link_tags(scope, options = {}) url = root_url query_hash = build_next_prev_query url << "?#{query_hash.to_query}" if query_hash.present? output = "" output << '<link rel="next" href="' + url + "&page=#{scope.next_page}" + '"/>' if scope.next_page output << '<link rel="prev" href="' + url + "&page=#{scope.prev_page}" + '"/>' if scope.prev_page output.html_safe end end ::ActionView::Base.prepend(KaminariPatch)
initializers以下にあるkaminari_config.rbはRails起動時に必ず最初に呼び出されるファイルです。
ここに処理を変更するメソッドを定義し、ActionView::Baseクラスにprependして動きを変えます。
上記では、build_next_prev_queryが定義されていますが。
これはシステム側の動きをこのメソッドでまとめて汲み取っているだけなのであまり気にしなくても大丈夫です。
この辺りは各々の環境でいい感じにしてください。
なぜモンキーパッチを当てたのか?
なぜモンキーパッチを当てたのかというそもそもの話をすると、モンキーパッチを当てて課題解決したほうが良い感じに落ち着きそうだったからです。
本来、モンキーパッチ自体はあまり好まれたテクニックではありません。
なぜなら、モンキーパッチをあてることによって本来の動きを変えてしまうことによって起きる弊害があるからです。
この弊害の話は技術書などでも口酸っぱく書かれていたりもします。
はじめは別メソッドに定義して解決することも考えましたが、なるべく無駄なコードは作りたくなかったのと、
kaminari側で処理が存在しているならばその処理に対して修正を加えて利用するほうがシンプルに収まるだろうと考えたからです。
おわり
今回が初のモンキーパッチを当てて課題を解決する経験でとても学びが多かったです。
・別メソッドを定義する考えからモンキーパッチで解決する方向への切り替え
・kaminari本来の動きを追うためのソースコードを読むこと
・PRの意図を探ること
・オープンクラス、メソッド探索、メソッドのオーバーライド、prepend、クラス継承などなどメタプログラミングRuby 第2版で学んだ知識が所々に現れてきました
・モンキーパッチの良し悪しを決めるライン
・実際に課題を解決する経験
kaminariのGitHubにちょっと気になるissueがありました。
rel_next_prev_link_tags ignores host option · Issue #496 · amatsuda/kaminari · GitHub