開發新手最容易犯的50個 Ruby on Rails 錯誤(1)

【編者按】本文最先發布與 JETRuby 博客,主要介紹了開發新手最容易犯的 Ruby 錯誤。文章系國內 ITOM 管理平臺 OneAPM 編譯呈現。html

一年前,咱們創立了以 「Rubyboost」 爲名的 Ruby on Rails 課程。簡而言之,本課程的目標是使對編程瞭解很少的新手也能在兩個月內,提高技能、成爲初級開發者。在成功完成課程以後,學生會收到爲其兩個月的實習邀請,實習地點就在咱們公司。若是一切順利,就會獲得聘用。不得不說,這是一種相對公平且簡單的成爲職業開發者的道路,你以爲呢?redis

順帶說一句,你根本想不到,有多少人願意來參加並學習 Rails 編程!數據庫

在分析了全部受訓者編寫的代碼以後,咱們總結了50個最多見的錯誤!更糟糕的是,每一個小組所犯的錯誤與前一組的錯誤幾乎如出一轍。編程

如下是 Rails 新手經常忽略或作錯的地方。咱們還包含了「對「,」錯」兩個版本的代碼樣本,使得教程更爲清楚。ruby

一、他們不使用自動生成的方法

############
## WRONG ##
############  

if course.visible    
  # do something
  end
  
##############
##  RIGHT   ##
##############  

if course.visible?    
  # do something
  end

一般,Rails 和許多 gems 會爲它們使用的對象添加一些有用的幫助方法。例如,Rails 會自動爲布爾字段添加聲明。一般,這些方法的名字是以問號結尾的。請牢記這一點!服務器

二、他們不知道「N+1」查詢來自何處

#############
##  WRONG  ##
#############  

 @homeworks = lesson.homeworks

  - @homeworks.each do |homework|
    %p homework.user.email
    
#############
##  RIGHT  ##
#############  

  @homeworks = lesson.homeworks.includes(:user)

  - @homeworks.each do |homework|
    %p homework.user.email

瞭解 ORM 如何與數據庫交互是很是重要的。可是,新手每每沒有這種瞭解。所以,他們不多使用 「includes」、「preload」 與 「eager_load」 這類方法,而且對 「bullet」 gem 一無所知。架構

在第一個例子中,N+1 查詢會傳遞至數據庫。」N」 是已經完成的家庭做業數量。查詢數量多是十、20甚至100。而在第二個例子中,只有2個查詢!框架

三、他們不用 scopes(域)

############
## WRONG  ##
############  

def index    
  @lessons = Сourse.lessons.order(position: :asc)  
end

############
##  RIGHT ##
############  

class Lesson < ActiveRecord::Base
    belongs_to :course

    scope :by_position, -> { order(position: :asc) }  
 end  
 
 def index    
   @lessons = course.lessons.by_position  
 end

Scopes 容許你隱藏數據庫的實現,並將代碼惟一化(uniqualize)。並且,代碼的可讀性也會大幅提高,由於他們透露了開發者的意圖,而非數據庫的結構。less

四、他們不瞭解 「after_create」 與 「after_commit」 間的差異

模型的數據,包括其在 「after_create」 中的新 ID,能夠從內部,而非外部進行讀取,緣由是交易還沒有完成。ide

若是我在數據庫中建立了一條記錄,以後打算將其 ID 放入 redis 或任意的存儲中,會獲得如下結果:

  • 若是 ID 在交易完成以前使用,「after_create」 可能會致使無效數據。

  • 藉助 「Sidekiq」 或其餘任意後臺工做,我老是可使用 「after_commit」 確保數據的完整性。

五、他們老是使用 ORM

#############
##  WRONG  ##
#############

  Article.all.each { |article| article.delete }

  Article.all.map { |article| article.title }

  Course.all.select { |course| course.created_at < 5.years.ago }.each { |course| course.articles.delete_all }
  
  #############
  ##  RIGHT  ##
  #############

  Article.delete_all

  Article.pluck(:title)

  old_courses_ids = Course.where(‘created_at < ?’, 5.years.ago’).pluck(:id)
  Article.where(course_id: old_courses_ids).delete_all

儘管使用對象無疑很是方便,但整個過程卻很是緩慢,並且須要不少內存。新手們可能並不理解代碼的工做原理,以及如何提升其效率。

六、他們不瞭解 「dependent destroy」 與 「delete_all」 的區別

在被移除以前,「dependent destroy」 會選擇全部受限記錄,創建其對象,並調用各自的毀滅方法。此方法容許你移除全部受限數據。可是,當涉及大量數據時,這種方法就無論用了。

至於 「dependent delete_all」,它會經過一條 SQL 查詢移除本身。它效率很高,可是,在這種狀況下,你得本身考慮數據庫的完整性。

七、他們不用帶 bang 的方法

#############
##  WRONG  ##
#############

  class Article
    validates :body, length: { minimum: 200 }  
  end

  articles_data.each do |article_data|
    Article.create(article_data)  
  end
    
#############
##  RIGHT  ##
#############  

# There are 2 possible solutions

  articles_data.each do |article_data|
    Article.create!(article_data)  
  end  
  
  # In this case a developer will be able to see that data he was not expencting to receive will get on the input

  articles_data.each do |article_data|
    article = Article.new(article_data)

    unless article.save
      puts ‘Can not save article’      
      #process this situation    
     end   
   end  
# Give a user a choice.

根據協議,將 bang(!) 添加至方法名的狀況有以下兩種:

  • 若是某個方法修改了其訪問的對象

  • 若是某個方法在執行失敗後拋出了異常

新手們經常忽略第二種狀況。若是代碼出了問題,你必須儘快找到問題根源。例如,若是徹底不處理將記錄保存至數據庫的結果,最好仍是拋出異常以找到哪段代碼處理了無效數據。

在上例中,若是一個無效的物品傳給輸入,就會被忽視。

八、他們不在遷移中設置默認字段

#############
##  WRONG  ##
#############  

class Article
    after_initialize :set_default_status    
    
    def set_default_status      
      self.status = ‘pending’    
        end  
      end

      
#############
##  RIGHT  ##
#############  

class MyMigration    
   def up
      change_column :articles, status, :string, default: ‘pending’    
    end    
    
  def down
      change_column :articles, status, :string    
    end  
  end

若是字段中的某個模型必需要有一個默認值,應該經過數據庫進行安裝。

九、他們不在遷移中設置限制條件

#############
##  WRONG  ##
#############  

class MyMigration    
  def change
      add_column :profiles, user_id, :integer    
    end  
  end
  
  
#############
##  RIGHT  ##
#############  

class MyMigration    
def change
      add_column :profiles, user_id, :integer, null: false   
   end  
 end

對於基礎架構的限制條件越多,咱們的應用就會越可靠。此外,別忘記 「null:false」,用戶不能夠沒有簡介。

十、他們不在遷移中寫反向遷移

若是不能回滾,遷移的意義在哪兒?

以上是新手們最常犯的 Ruby on Rails 錯誤的第一部分,若是喜歡本文,請記得分享哦。

未完待續……

本文系 OneAPM 工程師編譯整理。OneAPM 能爲您提供端到端的 Ruby 應用性能解決方案,咱們支持全部常見的 Ruby 框架及應用服務器,助您快速發現系統瓶頸,定位異常根本緣由。分鐘級部署,即刻體驗,Ruby 監控歷來沒有如此簡單。想閱讀更多技術文章,請訪問 OneAPM 官方技術博客

本文轉自 OneAPM 官方博客

原文地址:http://jetruby.com/expertise/common-ruby-rails-mistakes-beginners-make-model-database/

相關文章
相關標籤/搜索