2016-08-01 20 views
8

我有一個登記表模型,在註冊過程中需要用戶輸入:多模式儲蓄,如何在交易包和報告錯誤

class RegForm 
    include ActiveModel::Model 
    include ActiveModel::Validations 

    attr_accessor :company_name, :email, :password 
    validates_presence_of # ... 

end 

在這一註冊過程中我有需要創建多個模型,我不確定如何正確顯示錯誤消息以及如何將模型錯誤消息回傳到UI。

if @reg_form.valid? 
    account = Account.create!(@reg_form) 
else 
... 

Account.create!看起來像:

def self.create!(reg_form) 
    account = Account.create_from_reg!(reg_form) 
    location = location.create_from_reg!(account, reg_form) 
    .. 
    .. 
    account.location = location 
    .. 
    account.save! 

    account 
end 
  1. 所以我很困惑,如何顯示所有這些模型被保存
  2. 如何顯示或驗證失敗,如果reg_form不具有所有正確的數據錯誤信息其他型號。
  3. 如何確保將其包含在事務中,以便在註冊期間任何模型無法保存時不保存任何內容。

回答

3

讓我們從頭開始。

我們希望我們的註冊表單對象具有相同的API與任何其他的ActiveRecord模型:

// view.html 
<%= form_for(@book) do |f| %> 
<% end %> 

# controller.rb 
def create 
    @book = Book.new(book_params) 

    if @book.save 
    redirect_to @book, notice: 'Book was successfully created.' 
    else 
    render :new 
    end 
end 

爲了做到這一點,我們創建了以下對象:

class RegForm 
    include ActiveModel::Model 

    attr_accessor :company_name, :email, :password 

    def save 
    # Save Location and Account here 
    end 
end 

現在,包括ActiveModel::Model ,我們的RegForm獲得了大量的功能,包括顯示錯誤和驗證屬性(是的,沒有必要包含ActiveModel::Validations)。在這一步我們添加一些驗證:

validates :email, :password, presence: true 

我們改變save使其運行的驗證:

def save 
    validate 
    # Save Location and Account here 
end 

validate回報true如果所有驗證通過,否則false

validate還增加了errors@reg_form(所有ActiveRecord的型號有errors哈希當驗證失敗被填充)。這意味着,在視圖中我們可以做這些:

@reg_form.errors.messages 
#=> { email: ["can't be blank"], password: ["can't be blank"] } 

@reg_form.errors.full_messages 
#=> ["Email can't be blank", "Password can't be blank"] 

@reg_form.errors[:email] 
#=> ["can't be blank"] 

@reg_form.errors.full_messages_for(:email) 
#=> ["Email can't be blank"] 

同時,我們RegistrationsController應該是這個樣子:

def create 
    @reg_form = RegForm.new(reg_params) 

    if @reg_form.save 
    redirect_to @reg_form, notice: 'Registration was successful' 
    else 
    render :new 
    end 
end 

我們可以清楚地看到,當@reg_form.save回報false,該new視圖被重新渲染。

最後,我們改變save使我們的模型save調用一個包裹裏面transaction

def save 
    if valid? 
    ActiveRecord::Base.transaction do 
     location = Location.create!(location_params) 
     account = location.create_account!(account_params) 
    end 
    true 
    end 
rescue ActiveRecord::StatementInvalid => e 
    # Handle database exceptions not covered by validations. 
    # e.message and e.cause.message can help you figure out what happened 
end 

點值得注意:

  1. create!代替createtransaction只有在引發異常時纔會回滾(通常使用哪種方法)。

  2. validate is just an alias for valid?。通過執行類似

    return if invalid? 
    
  3. 我們可以把數據庫異常(like an email uniqueness constraint)到一個錯誤:

    rescue ActiveRecord::RecordNotUnique 
        errors.add(:email, :taken) 
    end 
    
  4. 爲了避免所有的壓痕,我們反而可以使用一個守在 save方法的頂部

    errors.add(:base, 'Company and Email do not match') 
    
  5. 我們可以用符號:base添加不直接與屬性相關聯的錯誤

0

我認爲交易和錯誤處理將幫助您解決您的問題。

def save_or_rescue 
    ActiveRecord::Base.transaction do 
    account = Account.create_from_reg!(reg_form) 
    location = location.create_from_reg!(account, reg_form) 
    ... 
    end 

rescue ActiveRecord::RecordInvalid => exception 
    puts exception 
end 
+0

謝謝,但我不想顯示異常,我想顯示來自其他模型的驗證錯誤。 – Blankman