2009-07-23 39 views
9

Tôi gặp vấn đề với ruby ​​của tôi trên ứng dụng đường ray. Tôi có hai mô hình - 'bệnh nhân' và 'địa chỉ', một bệnh nhân có một địa chỉ, và một địa chỉ thuộc về một bệnh nhân.Lỗi AssociationTypeMismatch trên ứng dụng Ruby on Rails

Patient.rb

class Patient < ActiveRecord::Base 
    has_many :charge_slips 
    has_one :address 

    validates_presence_of :last_name 
    validates_presence_of :first_name 
    validates_presence_of :middle_name 

end 

Address.rb

class Address < ActiveRecord::Base 
    belongs_to :patient 
    validates_associated :patient 
end 

Bệnh nhân-controller.rb

class PatientController < ApplicationController 
    def index 
    @title = "Outpatient Services - Patient" 
    @today = Date.today.to_formatted_s(:long) 
    @patients = Patient.find(:all) 
    end 

    def new 
    @patient = Patient.new 
    @address = Address.new 
    end 

    def create 
    @patient = Patient.new(params[:patient]) 
    @patient.created_on = Date.today.to_formatted_s(:long) 

    if @patient.save 
     @address = Address.new(params[:address]) 
     @address.patient_id = @patient.id 
     if @address.save 
     redirect_to :action => 'index' 
     else 
     redirect_to :action => 'new' 
     end 
     redirect_to :action => 'index' 
    else 
     redirect_to :action => 'new' 
    end 
    end 
end 

new.html.rb

<%= content_tag('h3', 'Create New Patient') %> 
<hr> 
<% form_for @patient, :url => { :action => "create" } do |patient_form| -%> 
    <%= error_messages_for :patient %> 
    <%= patient_form.label :last_name, 'Last Name:' %> <%= patient_form.text_field :last_name, :size => 30 %><br> 
    <%= patient_form.label :first_name, 'First Name:' %> <%= patient_form.text_field :first_name, :size => 30 %><br> 
    <%= patient_form.label :middle_name, 'Middle Name:' %> <%= patient_form.text_field :middle_name, :size => 30 %><br> 

    <fieldset> 
     <legend>Patient's Permanent Address</legend> 
     <%= error_messages_for :address %> 
     <% patient_form.fields_for @address do |address_fields| -%> 
      <%= address_fields.label :street_name, 'Street Name:' %> <%= address_fields.text_field :street_name %><br> 
      <%= address_fields.label :barangay, 'Barangay:' %> <%= address_fields.text_field :barangay %><br> 
      <%= address_fields.label :city_municipality, 'City/Municipality:' %> <%= address_fields.text_field :city_municipality %><br> 
      <%= address_fields.label :country, 'Country:' %> <%= address_fields.text_field :country %><br> 
      <%= address_fields.label :zip_cide, 'Zip Code:' %> <%= address_fields.text_field :zip_code %><br> 
     <% end -%> 
    </fieldset> 

    <%= submit_tag "Add Patient" %> 
<% end -%> 

Mỗi lần tôi thêm một bệnh nhân mới, một lỗi được ném. Đây là một phần của lỗi:

ActiveRecord::AssociationTypeMismatch in PatientController#create 

Address(#31360520) expected, got HashWithIndifferentAccess(#23815500) 

RAILS_ROOT: C:/www/Outpatient Application Trace | Framework Trace | Full Trace 

C:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations/association_proxy.rb:263:in `raise_on_type_mismatch' 
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations/has_one_association.rb:52:in `replace' 
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations.rb:1246:in `address=' 
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2740:in `send' 
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2740:in `attributes=' 
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2736:in `each' 
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2736:in `attributes=' 
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2434:in `initialize' 
C:/www/Outpatient/app/controllers/patient_controller.rb:14:in `new' 
C:/www/Outpatient/app/controllers/patient_controller.rb:14:in `create' 

Tôi mới tham gia RoR và muốn học ngôn ngữ thông qua thực hành. Tôi muốn biết điều gì có thể sai với mã. Cảm ơn!

Trả lời

28

đầu tiên mô hình Patient của bạn cần một accepts_nested_attributes_for

class Patient < ActiveRecord::Base 
    has_many :charge_slips 
    has_one :address 

    validates_presence_of :last_name 
    validates_presence_of :first_name 
    validates_presence_of :middle_name 

    accepts_nested_attributes_for :address 

end 

điều khiển của bạn có thể được đơn giản hóa rất nhiều. Không cần phải lưu địa chỉ riêng biệt vì @patient.save sẽ xử lý điều đó. Bạn không cần đặt thuộc tính created_on theo cách thủ công vì thuộc tính này sẽ được đặt tự động :) Ngoài ra, khi bạn không muốn @patient.save không thể render :action => 'new' và không redirect_to :action => 'new'. Điều này sẽ hiển thị lại biểu mẫu với bất kỳ lỗi xác thực nào (redirect_to sẽ không.)

Cũng lưu ý rằng tôi đã đổi tên lớp điều khiển thành PatientsController thay vì PatientController. Điều này sẽ phù hợp hơn với các quy ước RESTful của Rails và cũng sẽ giúp bạn đơn giản hóa quan điểm của bạn một chút. Nếu bạn làm điều này, bạn sẽ cần một số map.resources :patients trong tệp routes.db của mình và bạn cũng sẽ cần phải đổi tên tệp của mình.

class PatientsController < ApplicationController 
    def index 
    @title = "Outpatient Services - Patient" 
    @today = Date.today.to_formatted_s(:long) 
    @patients = Patient.find(:all) 
    end 

    def new 
    @patient = Patient.new 
    @patient.build_address 
    end 

    def create 
    @patient = Patient.new(params[:patient]) 

    if @patient.save 
     redirect_to :action => 'index' 
    else 
     render :action => 'new' 
    end 
    end 
end 

Chế độ xem của bạn có lỗi nhỏ. Nó cần phải là fields_for :address và không phải là fields_for @address. Ngoài ra kể từ khi bộ điều khiển của bạn bây giờ là RESTful bạn có thể loại bỏ phần :url => { :action => "create" }.

<%= content_tag('h3', 'Create New Patient') %> 
<hr> 
<% form_for @patient do |patient_form| -%> 
    <%= error_messages_for :patient %> 
    <%= patient_form.label :last_name, 'Last Name:' %> <%= patient_form.text_field :last_name, :size => 30 %><br> 
    <%= patient_form.label :first_name, 'First Name:' %> <%= patient_form.text_field :first_name, :size => 30 %><br> 
    <%= patient_form.label :middle_name, 'Middle Name:' %> <%= patient_form.text_field :middle_name, :size => 30 %><br> 

    <fieldset> 
     <legend>Patient's Permanent Address</legend> 
     <%= error_messages_for :address %> 
     <% patient_form.fields_for :address do |address_fields| -%> 
       <%= address_fields.label :street_name, 'Street Name:' %> <%= address_fields.text_field :street_name %><br> 
       <%= address_fields.label :barangay, 'Barangay:' %> <%= address_fields.text_field :barangay %><br> 
       <%= address_fields.label :city_municipality, 'City/Municipality:' %> <%= address_fields.text_field :city_municipality %><br> 
       <%= address_fields.label :country, 'Country:' %> <%= address_fields.text_field :country %><br> 
       <%= address_fields.label :zip_cide, 'Zip Code:' %> <%= address_fields.text_field :zip_code %><br> 
     <% end -%> 
    </fieldset> 

    <%= submit_tag "Add Patient" %> 
<% end -%> 

Hy vọng điều này sẽ giúp ích: