從修復 testerhome(rubychina)網站的一個 bug 學習 ruby&rails on ruby

前言

testerhome: http://testerhome.com/topics/1480html

對於一個差點脫離前沿技術人,想要學習ruby,就意味着要放棄熟悉的操做系統windows,熟悉的ide-eclipse,更重要的是要從java這種重量級編譯型語言的編程思想強行轉換爲ruby這種輕量級解釋執行語言編程思想。這個過程遠比我想象的要難,老是抱着之前以java編程思想,通吃vb,C#的傲慢,雖然js還算能夠,但js的編程思想與java也是很像的,通過此次打擊讓我意識到我掉隊了。但仍有一部分經驗能夠幫助我入手新的技術,這篇文章一方面是警醒本身,另外一方面也但願能將此次的學習過程分享給想要學習一門語言的同窗。java

正文

至於爲何選擇ruby,中間的選擇過程也費了一些時日,主要是在python和ruby之間比較,放棄python的重要理由是python的語法令我找不到北,還有那每一個包下的_init_.py文件,請原諒我思想過於老化,不管如何都接受不了。而ruby,給我感受就比較優雅易理解,雖然社區和資源不如python。過程曲折,就不贅述了。node

看清現狀

要學習一門新技術,首先要知道本身會什麼,新技術涉及到了什麼。python

linux&shell腳本 ruby最好仍是在linux下學習開發吧,我在windows下雖然也搭建成功了,但裝了例如 devkit 我也是醉了。
開發工具 工欲善事,必先利器。其實我是被eclipse慣的,實在不想像原來學習java同樣,從文本編輯器開始,編譯執行。。。我選擇了rubymine,是jetbrain出的,基於IntelliJ IDEA。其強大自沒必要說了。

對我來講上面這兩條知足就夠了,至於編程經驗什麼的,我認爲若是沒有編程經驗,反而還好一些,這樣不會被之前的思想幹擾。linux

看清須要什麼以後,就去熟悉他們吧,下載安裝blablabla....git

學習方法

萬事具有以後,就要考慮應該怎麼學習ruby,是去買本書?找網絡教學視頻找資料?。。。不管哪一種方法,要選擇合適本身的。對於有編程經驗的人,我建議先去看語法,練上幾個小例子,深層次的不須要太多考慮。而後就實踐,不管是本身編寫一個小程序仍是去修改bug均可以。沒有編程經驗的人,這裏就很差辦了,按照一般的作法,須要學習面向對象編程思想、數據結構、網絡通訊以及其餘一些必備的IT技能。固然這裏不是說要循序漸進的去學,若是對本身有信心能夠直接從視頻教程、ruby書籍開始學習。github

貼一個ruby的視頻教程:http://edu.51cto.com/lesson/id-10162.htmlweb

  1. 我是先去看語法:http://www.w3cschool.cc/ruby/ruby-tutorial.html
    w3cschool的語法雖然有一些已通過時了,但不影響了解ruby,看的過程當中就跟着例子上手實踐了。花了兩天時間~mongodb

  2. 接下來就要選擇是作一個小程序?仍是找個一個現成的去修改代碼修改bug。我選擇了後者,緣由就是由於在testerhome裏玩的時候發現了一個bug。這裏請沒有框架使用經驗的新手不要選擇後者,本身先作一些像計算器之類的小程序。由於通常的現成的程序中,會使用一些框架,裏面蘊含了框架的思想,若是不理解這個思想是找不到北的。shell

bug標題:testerhome論壇,社區帖子列表的分頁數量不正確
bug描述:進入「社區」菜單,下方的分頁欄,其頁數是100,但點擊100頁後,裏面沒有數據。這裏的分頁數量不是根據實際數據生成的,是錯誤的。
截圖:

修復bug過程

要想修復這個bug,首先要有源碼,還要知道論壇的架構。混罈子裏的確定都知道了,源碼在@lihuazhang羣主的github中就有,而論壇是使用的rubychina的源碼,架構是rails on ruby.

參考:http://www.cnblogs.com/likeyu/archive/2012/02/25/2367379.html

環境搭建什麼的就不贅述了,就從bug分析開始吧

  1. 這個bug的緣由不難想象,程序中計算分頁的代碼有問題。咱們要追到這部分代碼,就要先去找頁面。那接下來就觀察一下工程結構

    接下來就是個人初步猜想
  • app 論壇業務所在
  • bin 忽略,二進制對業務無影響
  • config 一些配置
  • db 數據庫相關
  • doc 裏面是readme,看一眼有沒有有用的,忽略
  • faye_server 不知道是什麼,實在找不到的時候纔去研究它
  • lib 引用的庫,忽略
  • log 日誌忽略
  • misc 存放了一些資源,忽略
  • public 裏面放了404.html等公用的錯誤頁、跳轉頁什麼的,忽略
  • script 就放了rails文件,忽略
  • spec 不知道什麼,rubymine將其顏色設置爲灰色,看來是沒什麼影響忽略
  1. 有了上面的分析,那麼入手點就找到了,咱們關注app中的內容,那麼就展開看看吧

    從這個目錄結構中,若是對web框架有所熟悉,必定會馬上找到切入點,views文件夾,由於視圖就是表現層,說白了就是組織web頁面,展開後觀察一下[社區列表]這個頁面在哪裏

    從中不難看出topics就是頁面所在了,展開topics文件夾,找可能頁面去觀察代碼,最終將頁面定位到index.html.erb。

  2. 問題頁面定位到了,咱們就開始觀察代碼吧

<div class="content">
  <div class="box box_gray">
    <div id="node_info">
      <%= render "topics/node_info", node: @node %>
    </div>
    <div class="topics">
      <% if @topics.current_page == 1 %>
        <% cache(@suggest_topics) do %>
          <%= render partial: "topics/topic", collection: @suggest_topics, locals: { suggest: true } %>
        <% end %>
      <% end %>
      <%= render partial: "topics/topic", collection: @topics, locals: { suggest: false } %>
    </div>
    <%= will_paginate @topics, inner_window: 2 %>
  </div>
 ......

注意這一行<%= will_paginate @topics, inner_window: 2 %>,說的很清楚,will_paginate分頁。好了,找到了邏輯處理部分的代碼,原本按照我老舊的思路,去找will_paginate方法,結果發現這個方法並非業務邏輯處理,只是一個rails通用方法,那麼誰纔是業務邏輯處理呢,若是使用過web框架的就會想到mvc,rails也是如此。好,這時候還記得目錄結構吧,上面app目錄下有一個controllers文件夾,業務處理就在這裏了,從中很容易猜到topics_controller.rb。來看下代碼

# coding: utf-8
class TopicsController < ApplicationController
  load_and_authorize_resource only: [:new, :edit, :create, :update, :destroy,
                                     :favorite, :unfavorite, :follow, :unfollow, :suggest, :unsuggest]
  caches_action :feed, :node_feed, expires_in: 1.hours

  def index
    @suggest_topics = Topic.without_hide_nodes.suggest.limit(3)
    suggest_topic_ids = @suggest_topics.map(&:id)

    @topics = Topic.last_actived.without_hide_nodes.where(:_id.nin => suggest_topic_ids) #去數據庫查詢有多少帖子
    @topics = @topics.fields_for_list.includes(:user) #這部不太明白,但不影響分析
    @topics = @topics.paginate(page: params[:page], per_page: 15, total_entries: 1500)#這個方法就是計算分頁了,能夠從參數看出每頁15個帖子,但total_entries這個參數卻給了一個固定值1500,那麼也就是說分100頁。。。。bug就在這裏

    set_seo_meta '', "#{Setting.app_name}#{t("menu.topics")}"
  end
  ... ...#代碼多,就看上面這部分吧

上面代碼中的註釋就是我對代碼的分析。咱們繼續跟到@topics.paginate方法中,

# coding: utf-8
require 'will_paginate'
require 'will_paginate/collection'

module Mongoid
  module WillPaginate
    extend ActiveSupport::Concern

    def paginate(options = {})
      options = base_options options

      ::WillPaginate::Collection.create(options[:page], options[:per_page]) do |pager| #從這裏讀到意思是根據傳入的分頁參數建立一個分頁集合而後遍歷每頁,將每頁的帖子展現
        items_count = options[:total_entries] || self.count #這塊就須要瞭解ruby的語法了,||相似於三目運算,意思是若`options[:total_entries]!=nil`則`items_count=options[:total_entries]`,若`options[:total_entries]=nil`,則`items_count=self.count',轉換爲業務說法就是,若傳入的總貼數爲nil則計算數據庫中查詢出的帖子數量,這裏顯然邏輯錯誤。不管什麼時候都應當使用數據庫中查詢出的帖子數量
        fill_pager_with self.skip(options[:offset]).limit(options[:per_page]), items_count, pager
      end
    end
  ......

問題定位清楚了,就開始想怎麼改,已經說過了,不管什麼時候都應當使用數據庫中查詢出的帖子數量。按照這個思路,咱們先以調試模式啓動testerhome這個web應用,啓動後就能夠訪問本地調試環境的testerhome了

在調試以前,咱們須要取得管理員權限,具體的方法能夠查看http://www.cnblogs.com/likeyu/archive/2012/02/25/2367379.html這位同窗寫的。
咱們進入http://localhost:3000/cpanel添加分類和節點,這樣才能發帖。
接下來咱們就要動代碼了,首先咱們在app/controllers/topics_controller.rb文件中,將代碼修改成以下:

# coding: utf-8
class TopicsController < ApplicationController
  load_and_authorize_resource only: [:new, :edit, :create, :update, :destroy,
                                     :favorite, :unfavorite, :follow, :unfollow, :suggest, :unsuggest]
  caches_action :feed, :node_feed, expires_in: 1.hours

  def index
    @suggest_topics = Topic.without_hide_nodes.suggest.limit(3)
    suggest_topic_ids = @suggest_topics.map(&:id)

    @topics = Topic.last_actived.without_hide_nodes.where(:_id.nin => suggest_topic_ids) #去數據庫查詢有多少帖子
    @topics = @topics.fields_for_list.includes(:user) #這部不太明白,但不影響分析
    @topics = @topics.paginate(page: params[:page], per_page: 15)#去掉total_entries:1500這個參數,不能寫死帖子總數

    set_seo_meta '', "#{Setting.app_name}#{t("menu.topics")}"
  end
  ... ...#代碼多,就看上面這部分吧

同時要將app/models/mongoid/will_paginate.rb文件中的代碼修改以下:

# coding: utf-8
require 'will_paginate'
require 'will_paginate/collection'

module Mongoid
  module WillPaginate
    extend ActiveSupport::Concern

    def paginate(options = {})
      options = base_options options

      ::WillPaginate::Collection.create(options[:page], options[:per_page]) do |pager| #從這裏讀到意思是根據傳入的分頁參數建立一個分頁集合而後遍歷每頁,將每頁的帖子展現
        items_count = self.count #不須要total_entries參數,咱們使用從數據庫中查詢出的帖子數目
        fill_pager_with self.skip(options[:offset]).limit(options[:per_page]), items_count, pager
      end
    end
  ......

代碼修改完成,接着就去瀏覽器中訪問testerhome,進入社區帖子列表,新建16個帖子,由於咱們要看出效果,須要至少2頁。造完數據後,咱們能夠看到以下結果

從中能夠看到當前的分頁已經正常了,16條數據,分了2頁,同時也試試點擊第2頁,看看是否顯示正常。

至此這個bug就修復了。

最後

之因此想要修復這個bug,是由於咱們是testerhome,那麼看到bug就不能放過,同時也爲社區貢獻點東西,只是改完這個無法真實測試,這個須要@lihuazhang羣主幫忙了,話說我這古董技術,到如今對git還不熟。另外,在沒有看到rubychina那位仁兄寫的rubychina實踐以前,不知道管理員怎麼進,就去學了mongodb,好不容易學會了,去數據庫裏看到user裏有一個admin,但密碼是加密的,咋辦,,,只好本身註冊了一個用戶,而後將這個用戶的加密密碼替換了admin的密碼,結果發現仍然訪問不了後臺管理,最後才找到那篇文章,豁然開朗。此次解決問題的過程,其中有不少都是靠着經驗猜出來的,對與rails框架我還不熟悉,經過此次解決問題已經看清一點論輪廓了。但願能幫助到那些想學習開發的新手,同時也歡迎ruby大神給點建議!

最後的最後但願,testerhome能愈來愈好~各位tester事業生活一路順風~好不容易有時間寫點東西,又有點忙了,請新秀羣不要踢我啊 😱,我要學的東西還有不少,之後有時間寫東西必定會寫~ 😏

相關文章
相關標籤/搜索