2015-09-27 52 views
1

我試圖對一個字段進行條件驗證。這樣它只驗證其他字段是否是特定值。這裏的問題是,這個其他領域是一對多的關係,我似乎無法得到它的工作。 下面是相關代碼:Rails通過一對多的關係進行有條件的驗證

class CreateInvolvedPartyTypes < ActiveRecord::Migration 
    def change 
    create_table :involved_party_types do |t| 
     t.string :code 
     t.string :name 

     t.timestamps null: false 
    end 
    end 
end 

class CreateInvolvedParties < ActiveRecord::Migration 
    def change 
    create_table :involved_parties do |t| 
     t.string :first_name 
     t.string :last_name 
     t.references :involved_party_type 

     t.timestamps null: false 
    end 
    end 
end 

class InvolvedParty < ActiveRecord::Base 
    def ipt_cd? 
     self.involved_party_type.code == 'I' 
    end 

    validates :first_name, presence: { message: "Please insert first name" } 
    validates :last_name, presence: { message: "Please insert last name" }, :if => :ipt_cd? 
    validates :involved_party_type, presence: { message: "Please select involved party type" } 

    belongs_to :involved_party_type 
end 

上面的代碼失敗:

undefined method `code' for nil:NilClass

感謝您的幫助

+0

你可以在你創建/驗證有問題的對象的地方發佈代碼嗎? – panmari

回答

1

錯誤意味着InvolvedParty#ipt_cd self.involved_party_type?是零。在調用#code之前,你應該測試involved_pa​​rty_type的存在,或者使用#try。

def ipt_cd? 
    return false if involved_party.nil? 
    involved_party_type.code == 'I' 
end 

def ipt_cd? 
    self.involved_party_type.try(:code) == 'I' 
end 

或者,如果involved_pa​​rty_type存在,則只需調用驗證即可避免此問題。

validates :last_name, presence: { message: "Please insert last name" }, if: -> { involved_party_type && ipt_cd? } 
0

我認爲這個問題是,你感到困惑與調用instanceclass級別的數據。

  • "Instance" data is populated each time a class is invoked
  • "Class" data is static, always appending to the class

兩者之間的化妝品區別在於class數據通過(EG def self.method & self.attribute)通常稱爲,同時instance數據被稱爲以「裸露的」屬性(即,沒有self)。

你調用以下:

def ipt_cd? 
    self.involved_party_type.code == 'I' 
end 

的問題是,如果引用self,彷彿這是一件數據。你想要的是實例相當於:

def ipt_cd? 
    involved_party_type.code == 'I' 
end 

至於對方的回答狀態,你的錯誤是由一塊具有code沒有方法的數據引起的,這意味着它是零。

這樣做的casue是在這裏(解決以上 - IE刪除self):

involved_party_type.code == 'I' 

因此,如果你想確保你不會收到此錯誤,你必須確保那involved_party_type是存在的。這可以通過首先確保您參考數據的變體實例,然後確保它仍然存在。另一個答案提供了實現這一目標的最佳方式。


最後,我認爲你的結構可以改進。

在我看來,引用相關字段的實際數據表示形式是不好的做法。您正在嘗試創建一段新的數據,但是您正在引用一個關聯的屬性?

爲什麼不能做到以下幾點:

#app/models/party_type.rb 
class PartyType < ActiveRecord::Base 
    has_many :involved_parties 
end 

class InvolvedParty < ActiveRecord::Base 
    belongs_to :party_type 

    validates :first_name, :party_type, presence: true 
    validates :last_name, presence: { message: "Please insert last name" }, if: :cd? 

    private 

    def cd? 
     party_type == PartyType.find_by(code: "I").pluck(:id) 
    end 
end 

這將再次發送DB查詢它消除了對特定數據的依賴。您目前的設置不依賴於外鍵,而是依賴於可能改變的值。

雖然此建議也依賴於數據(IE code == I),但它將其用作ActiveRecord內的量詞。也就是說,你沒有比較數據,而是關係。

+0

我得到這個錯誤:未定義的方法'pluck'爲#。上述答案完美無缺。謝謝你的解釋。 – Fermin

+0

很抱歉,如果您收到來自我以前評論的多個通知。我認爲移除'self'什麼也不做,因爲實例方法中的'self'指的是實例。 'PartyType.find_by(code:「I」)。pluck(:id)'也不起作用,因爲find_by返回與條件匹配的第一條記錄作爲ActiveRecord實例。 – tyamagu2

+0

你可能是對的!感謝評論:) –