2016-08-01 15 views
8

Tôi có một mô hình mẫu đăng ký mà có những người sử dụng đầu vào trong quá trình đăng ký:đa tiết kiệm mô hình, làm thế nào để quấn trong giao dịch và báo cáo lỗi

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

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

end 

Trong quá trình đăng ký này, tôi có nhiều mô hình mà cần phải được tạo ra, và tôi không chắc chắn cách hiển thị đúng thông báo lỗi và cách bong bóng các thông báo lỗi mô hình trở lại giao diện người dùng.

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

Tài khoản.create! trông giống như:

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. Vì vậy, tôi đang bối rối như thế nào để hiển thị các thông báo lỗi cho tất cả các mô hình này được tiết kiệm
  2. làm thế nào để hiển thị hoặc không xác nhận nếu reg_form không có dữ liệu chính xác cho tất cả các mô hình khác.
  3. làm thế nào để đảm bảo điều này được bọc trong một giao dịch vì vậy tôi không lưu bất cứ điều gì nếu bất kỳ mô hình thất bại trong việc tiết kiệm trong đăng ký.

Trả lời

3

Hãy bắt đầu lại từ đầu.

Chúng tôi muốn đối tượng mẫu đăng ký của chúng tôi để có API giống như bất kỳ mô hình ActiveRecord khác:

// 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 

Để làm điều đó, chúng tôi tạo ra các đối tượng sau đây:

class RegForm 
    include ActiveModel::Model 

    attr_accessor :company_name, :email, :password 

    def save 
    # Save Location and Account here 
    end 
end 

Bây giờ, bằng cách bao gồm ActiveModel::Model , chúng tôi RegForm tăng một tấn các chức năng, bao gồm hiển thị lỗi và xác nhận các thuộc tính (có, đó là không cần thiết để bao gồm ActiveModel::Validations). Trong bước tiếp theo này, chúng tôi thêm một số kiểm chứng thực:

validates :email, :password, presence: true 

Và chúng ta thay đổi save để nó chạy những kiểm chứng thực:

def save 
    validate 
    # Save Location and Account here 
end 

validate lợi nhuận true nếu tất cả hợp lệ vượt qua và false khác.

validate cũng thêm errors vào @reg_form (Tất cả các mô hình ActiveRecord có mã số errors được điền khi xác thực không thành công). Điều này có nghĩa rằng trong giao diện chúng ta có thể làm được điều này:

@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"] 

Trong khi đó, chúng tôi RegistrationsController nên tìm một cái gì đó như thế này:

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 

Chúng ta có thể thấy rõ rằng khi @reg_form.save lợi nhuận false, quan điểm new được hiển thị lại.

Cuối cùng, chúng ta thay đổi save để mô hình của chúng tôi save cuộc gọi được gói bên trong một 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 

điểm đáng chú ý:

  1. create! được sử dụng thay vì create. Các transaction chỉ được cuộn lại nếu một ngoại lệ được nâng lên (mà phương pháp với một bang thường làm).

  2. validate is just an alias for valid?. Để tránh tất cả những gì thụt đầu dòng, chúng tôi thay vì có thể sử dụng một người bảo vệ ở phía trên cùng của phương pháp save:

    return if invalid? 
    
  3. Chúng tôi có thể biến một ngoại lệ cơ sở dữ liệu (like an email uniqueness constraint) vào một lỗi bằng cách làm một cái gì đó như:

    rescue ActiveRecord::RecordNotUnique 
        errors.add(:email, :taken) 
    end 
    
  4. Chúng ta có thể thêm một lỗi không liên quan trực tiếp với một thuộc tính bằng cách sử dụng các biểu tượng :base:

    errors.add(:base, 'Company and Email do not match') 
    
0

Tôi nghĩ rằng các giao dịch và xử lý lỗi sẽ giúp bạn giải quyết vấn đề của bạn.

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

Cảm ơn nhưng tôi không muốn hiển thị ngoại lệ, tôi muốn hiển thị lỗi xác thực từ các mô hình khác. – Blankman

Các vấn đề liên quan