2013-04-11 42 views
15

可能做一些愚蠢的在這裏,但這裏是我的基本俗套類故障:軌道4個強的參數在軌控制檯創建實例時

class League < ActiveRecord::Base 

    private 
     def league_params 
     params.require(:full_name).permit! 
     end 

end 

,創造聯賽的新實例時:

2.0.0-p0 :001 > l = League.new(full_name: 'foo', short_name: 'bar') 
WARNING: Can't mass-assign protected attributes for League: full_name, short_name 

我在這裏做錯了什麼?這是Rails 4.0.0.beta1構建+紅寶石2.0

**更新**

我現在認識到,強大的參數在控制器執行的,而不是現在的模型。原來的問題依然存在。如果它們在控制器級別上被允許,如果我在Rails控制檯中創建實例,如何正確地將白名單屬性設置爲白名單?在這種情況下,我是否也需要使用attr_accessible,從而完全複製哪些強參數試圖「修復」?

+0

你可以發佈你的Gemfile嗎?還有你的模型中的代碼? – Agis

+0

@randombits你是否從rails3升級你的項目? – AKovtunov

回答

14

兩件事。 league_params定義進入控制器,而不是模型。並且params.require()應該包含需要出現在參數中的模型的名稱,而不是屬性。屬性存在檢查仍應在模型驗證中。在使用permit!之前,請確保您確實想要允許訪問聯盟模型中的所有屬性。因此,它應該是這樣的:

class LeaguesController < ApplicationController 

    private 
    def league_params 
     params.require(:league).permit! 
    end 

end 

更新:

是的,如果你想直接訪問模型時的屬性加以限制,則需要切換回在模型中使用的attr_accessible 。該功能已被轉移到這個寶石:https://github.com/rails/protected_attributes

我認爲假設您是直接在控制檯中使用模型,您不需要保護屬性,因爲您確切知道輸入內容。由於控制檯可以完全訪問您的應用程序,因此軟件整個數據庫就像惡意分配屬性一樣簡單。

+1

如果聯盟沒有在控制器中創建,該怎麼辦?我在這個特殊情況下在控制檯中創建它。 – randombits

+0

然後你不需要使用允許的參數。允許的參數用於防止用戶輸入的數據。 – spullen

+3

那麼我需要回到attr_accessible呢? – randombits

7

基本安全原因都強參數的存在和attr_accessible是,有在模型中的某些屬性不應該被允許改變,除非它是你的代碼的明確意圖。

它們之間的細微差別是他們完成工作的觀點。

StrongParameters重點關注用例:考慮到任何條件,可以對每個控制器的動作進行微調以允許或禁止某些參數。總體靈活性。

attr_accessible採取不同的觀點。它不專注於用例,而是專注於角色。因此,例如,根據用戶的角色,某些屬性可以更改或不更改。


使用StrongParameters的方法是應用在帕拉姆哈希requirepermit關鍵字。

require指出密鑰必須存在於參數散列中。如果沒有這樣的密鑰,require將引發異常。

permit指出允許一個字段。任何不允許的密鑰都將從散列中刪除,因此不會通過批量分配傳遞給模型。

型號

class League 
    attr_protected :final_price # Nobody can mass-assign the final price 
    attr_accessible :winner_name, :as => :jury 
end 

而且控制器

class LeaguesController < ApplicationController 

這兩個動作使用StrongParameters

# A common user can create a league 
    def create 
    league = League.new(league_params) 
    league.final_price = 1000 
    league.save 
    redirect_to(league) 
    end 

    # But only the admin can publish a league 
    def publish_league 
    league = League.find(params[:id] 
    league.update_attributes(league_params_as_admin) 
    end 

這一次使用attr_accessible

def publish_the_winner 
    league = League.find(params[:id] 
    # We would expect the current_user.role to return :jury. 
    league.assign_attributes(params[:league], :as => current_user.role) 
    end 

    private 
    def league_params 
     params.require(:league).permit(:name) 
    end 

    def league_params_as_admin 
     params.require(:league).permit(:name, :status) 
    end 

end 

以我的經驗:

使用強參數的微調的靈活性,什麼屬性可大量分配在每個控制器。

使用無處不在的attr_accesible來確保某些屬性無論如何都不能被批量分配。例如,在Resque Task中,您可以將用戶輸入作爲參數傳遞。您將檢查某些屬性是否使用attr_accesible進行批量分配。

更多信息:

http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html

https://github.com/rails/strong_parameters

1

看來白名單是活動的,即使你正在運行的Rails 4.你從一個Rails應用程序3升級到Rails的4?你在config/application.rb有這個嗎?

config.active_record.whitelist_attributes = true 

仔細檢查所有模型上的強參數是否有效。如果是,則可以將此設置更改爲false

另外,仔細檢查模型中是否有attr_accessible

+0

我不是該主題的作者,但謝謝。當我將我的項目從Rails3升級到Rails4時,顯示此消息。但是,如果我使用相同的代碼創建Rails 4項目(即使在配置中),也不會顯示消息。我不知道爲什麼,好像是一個小錯誤。 – AKovtunov

+0

這是不可能的透明升級,開發人員的援助是必要的。我相信原來的海報必須添加'protected_attributes' gem,否則會出現錯誤。 (也許錯誤告訴你安裝那個寶石,我沒有正確的電腦在我面前檢查)。升級到Rails 4的最好方法是首先使用strong_parameters gem,然後通過所有控制器和模型以新方式工作,只有在升級Rails gem之後。 – clacke

+0

您的Rails 4項目中的配置是否真的相同?我猜測所提到的配置行缺失或設置爲false。 – clacke