rails 4嵌套表单,1个模型不关联id

时间:2014-06-14 13:48:49

标签: ruby-on-rails ruby-on-rails-4 nested-forms model-associations

我有一个订单,在创建订单时,也会创建一个新客户。为此,我有以下模型:

class Customer < ActiveRecord::Base
    has_many :orders 
    has_many :subscriptions, through: orders
end

class Order < ActiveRecord::Base
    belongs_to :customer
    has_many :subscriptions

    accepts_nested_attributes_for :customer
    accepts_nested_attributes_for :subscriptions
end

class Subscription< ActiveRecord::Base
    belongs_to :order
    belongs_to :customer
end

在我的订单页面上,我有这样的表格:

= simple_form_for(@order) do |f|
    = render 'order_fields', f: f 
    = f.simple_fields_for :subscriptions do |subscription| 
        = render 'subscription_fields', subscription: subscription
    = f.simple_fields_for :customer do |customer| 
        = render 'customer_fields', customer: customer 
    = f.button :submit

在我的OrderController中,我有:

def new
    @order = Order.new
    @order.build_customer
    @order.subscriptions.build
end

def create
    @order = Order.new(order_params)

    if @order.save       
        (.... etc ...)
end

private
    def order_params
        params.require(:order).permit(
            :amount,
            customer_attributes: [ :id, :email, :password, :password_confirmation], 
            subscriptions_attributes: [ :id, :product_id, :customer_id])
    end

几乎一切顺利:
     - 创建用户
     - 订单已创建且具有customer_id = User.id
     - 已创建订阅并具有order_id = Order.id

但不知何故,它不会将订阅与客户联系起来:(
我一直在 Subscription.customer_id = nil

有人可以指出我正确的方向吗?模型中有什么问题吗?还是在控制器里?我不知道在哪里看。

2 个答案:

答案 0 :(得分:1)

你们的关系设置有点不同。我没有在订阅上创建customer_id字段,而是希望您只拥有has_one :customer, through: :order

如果您这样做,您将不再需要订阅模型上的customer_id属性。如果您想从订阅的世界视图中获取客户的ID,请拨打subscription.customer.id

您可能还想在模型中为您的关系添加inverse_of名称(这总是一种很好的做法,可以最大限度地减少从数据库重新加载模型)。

所以,总的来说,我建议:

class Customer < ActiveRecord::Base
  has_many :orders, inverse_of: :customer
  has_many :subscriptions, through: orders
end

class Order < ActiveRecord::Base
  belongs_to :customer, inverse_of: :orders
  has_many :subscriptions, inverse_of: :order

  accepts_nested_attributes_for :customer
  accepts_nested_attributes_for :subscriptions
end

class Subscription< ActiveRecord::Base
  belongs_to :order, inverse_of: :subscriptions
  has_one :customer, through: :order # THIS IS THE KEY CHANGE
end

哦,然后您可以从customer_id的允许属性中删除subscriptions_attributes

<强>更新

鉴于Subscription#customer_id意图与客户脱节 - &gt;订单 - &gt;订阅关系...忽略上面的内容(可能是inverse_of内容除外)和......你应该可以这样做:

class Customer < ActiveRecord::Base
  has_many :subscriptions, through: :orders, after_add: :cache_customer_id

  private

  def cache_customer_id(subscription)
    subscription.update_column(:customer_id, self.id)
  end
end

答案 1 :(得分:0)

谢谢pdobb!我现在正在添加order.controller:

def create
    @order = Order.new(order_params)

    if @order.save       
       @order.subscriptions.each { subscription| subscription.update_column(:customer_id, @order.customer.id) }
end