簡體   English   中英

Ruby Rails嵌套記錄

[英]Ruby Rails Nested Records

我不確定我什至試圖做的事是否可行,但這是可行的。

我有一個定義了以下表的SQL數據庫(僅顯示SQL中的相關表):

CREATE TABLE customers(
    id integer NOT NULL UNIQUE,
    name vachar(25) NOT NULL,
    surname vachar(25) NOT NULL,
    password vachar(20) NOT NULL,
    email_address vachar(1024) NOT NULL,
    home_phone vachar(15),
    mobile_phone vachar(15),
    office_phone vachar(15),
    billing_address_id integer NOT NULL,
    postal_address_id integer,
    FOREIGN KEY (billing_address_id) REFERENCES addresses(id),
    FOREIGN KEY (postal_address_id) REFERENCES addresses(id),
    PRIMARY KEY (id));

CREATE TABLE addresses(
    id integer NOT NULL UNIQUE,
    line1 vachar(100) NOT NULL,
    line2 vachar(100),
    state vachar(30) NOT NULL,
    postcode vachar(10) NOT NULL,
    country_id vachar(3) NOT NULL,
    PRIMARY KEY (id));

CREATE TABLE orders(
    id integer NOT NULL UNIQUE,
    customer_id integer NOT NULL UNIQUE,
    order_date date NOT NULL,
    postal_address_id integer NOT NULL UNIQUE,
    FOREIGN KEY (customer_id) REFERENCES customers(id),
    PRIMARY KEY (id));

正如你所看到的,“客戶”表中定義了地址(一個計費地址和一個郵政/送貨地址)一個一對一2間的關系。 這里的想法有兩個方面:

  1. 通過使用與地址表的關系,將重復的地址字段保存在客戶表中。
  2. 稍后,我可以使用地址ID輕松填寫“訂單”的送貨地址。

現在,我想使用帶軌道的Active Records對此建模。 到目前為止,我有以下內容:

1)“客戶”模型:

class Customer < ActiveRecord::Base
    has_one :postal_address, :class_name => 'Address', :foreign_key => :postal_address_id
    has_one :billing_address, :class_name => 'Address', :foreign_key => :billing_address_id
    accepts_nested_attributes_for :postal_address, :billing_address, :allow_destroy => true
end

2)地址模型(默認):

class Address < ActiveRecord::Base
end

3)客戶控制者(僅顯示相關方法,即new和create):

class CustomersController < ApplicationController

  # GET /customers/new
  # GET /customers/new.xml
  def new
    @customer = Customer.new
    @customer.postal_address = Address.new
    @customer.billing_address = Address.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @customer }
    end
  end

  # POST /customers
  # POST /customers.xml
  def create
    @customer = Customer.new(params[:customer])

    respond_to do |format|
      if @customer.save
        flash[:notice] = 'Customer was successfully created.'
        format.html { redirect_to(@customer) }
        format.xml  { render :xml => @customer, :status => :created, :location => @customer }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @customer.errors, :status => :unprocessable_entity }
      end
    end
  end

end

3)我的嵌套表格也用於創建具有帳單地址的新客戶。

<% form_for(@customer) do |f| %>
  <%= f.error_messages %>

  <%= f.label :name, 'Name:' %>
  <%= f.text_field :name %>

  <%= f.label :surname, 'Surname:' %>
  <%= f.text_field :surname %>

  <br>

  <%= f.label :email_address, 'Email:' %>
  <%= f.text_field :email_address %>

  <%= f.label :confirm_email_address, 'Confirm Email:' %>
  <input id="confirm_email_address" type="text" />

  <br>

  <%= f.label :password, 'Password:' %>
  <%= f.text_field :password %>
  <%= f.label :confirm_password, 'Confirm Password:' %>
  <input id="confirm_password" type="password" %>

  <br>

  <%= f.label :home_phone, 'Home Phone:' %> 
  <%= f.text_field :home_phone %>

  <%= f.label :mobile_phone, 'Mobile Phone:' %>
  <%= f.text_field :mobile_phone %>

  <%= f.label :office_phone, 'Office Phone:' %>
  <%= f.text_field :office_phone %>

  <br>

  <% f.fields_for :billing_address do |billing_form| %>

    <%= billing_form.label :line1, 'Billing Address:' %>
    <%= billing_form.text_field :line1 %>

    <br>

    <%= billing_form.text_field :line2 %>

    <br>

    <%= billing_form.label :state, 'State / Province / Region:' %>
    <%= billing_form.text_field :state %>

    <br>

    <%= billing_form.label :postcode, 'Postcode / ZIP:' %>
    <%= billing_form.text_field :postcode %>

    <br>

    <%= billing_form.label :country_id, 'Country:' %>
    <%= billing_form.text_field :country_id %>

  <% end %>

  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %>

現在解決問題。 當我填寫此表格並繼續創建新記錄時,出現以下錯誤:

SQLite3::SQLException: customers.billing_address_id may not be NULL: INSERT INTO "customers" ("name", "office_phone", "billing_address_id", "postal_address_id", "home_phone", "surname", "password", "email_address", "mobile_phone") VALUES('Michael', '', NULL, NULL, '93062145', 'Fazio', '9npn4zicr', 'michael.fazio@me.com', '')

由此可知,帳單地址不是在客戶之前創建的。 我認為(可能很天真),該活動記錄將識別客戶和地址記錄之間的關系,並做了正確的操作來創建新的記錄。 顯然不是這樣。

我怎樣才能讓這樣呢? 我假設邏輯需要放在客戶控制器中,以便首先保存地址記錄,然后獲取該記錄的ID,以便在客戶控制器中使用。 全部都在交易中嗎? 還是我剛剛以一種不好的方式對數據庫建模?

希望所有這些代碼不要太多,但是我想提供盡可能多的上下文。

第二回合:

好的,希望現在對您有所幫助。 在一個表中實現雙重地址的方式並不完全是“軌道”方式。 總的來說,如果您想做某些事情,例如DHH,就必須要做。 因此,rails具有STI( 單表繼承 ),您可以在其中擁有一個超類,並從中繼承許多類。

在您的情況下,移動這種范例不應做太多工作(我希望)。

步驟1:在盒子上切一個洞

步驟2:更新您的遷移文件。 您希望地址表具有對應於客戶的鍵。 然后刪除“客戶”表中的billing_address_id和shipping_address_id列,因為我們不再需要這些列。

您還想添加一個名為type的字段(如果已經使用type,則可以解決)。 像這樣:

create_table :addresses do |t|
  t.string :line1
  t.string :line2
  t.string :state
  t.integer :postcode
  t.integer :country_id
  t.integer :customer_id
  t.integer :type

  t.timestamps

步驟3:更新模型。 更改您的客戶類別,如下所示:

class Customer < ActiveRecord::Base
  has_one :postal_address
  has_one :billing_address
  accepts_nested_attributes_for :postal_address, :billing_address, :allow_destroy => true

然后,您將要在models目錄中創建兩個新文件:billing_address.rb和postal_address.rb。 它們應如下所示:

class BillingAddress < Address
  belongs_to :customer
end

class PostalAddress < Address
  belongs_to :customer
end

步驟4:更新控制器。 現在,您在問題中顯示的唯一控制器是customer_controller.rb,但是,可以在任何地方使用。 您要用實例化“送貨地址”或“帳單地址”的調用替換Address.new

def new
  @customer = Customer.new
  @customer.postal_address = PostalAddress.new
  @customer.billing_address = BillingAddress.new

  respond_to do |format|
    format.html # new.html.erb
    format.xml  { render :xml => @customer }
  end
end

希望這確實有效,並且可以彌補我之前的糟糕嘗試;)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM