Reputation: 198
I have an order form and when an order is created, a new customer is created as well. For this I have the following models:
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
On my order page I have this form:
= 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
In my OrderController I have:
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
Almost everything goes well:
- User is created
- Order is created and has customer_id = User.id
- Subscription is created and has order_id = Order.id
But somehow it wont associate the subscription to the customer :(
I keep having Subscription.customer_id = nil
Can someone please point me in the right direction? Is there something wrong in the models? or in the controllers? I have no idea anymore where to look.
Upvotes: 0
Views: 98
Reputation: 198
Thanks pdobb! I got it working now with adding in the 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
Upvotes: 0
Reputation: 18037
Your relationships are set up a little different. Instead of creating a customer_id
field on Subscription, I'd expect you'd just have a has_one :customer, through: :order
.
If you do this you won't have need for a customer_id
attribute on your Subscription model anymore. And if you want the id of the customer from the world-view of a subscription you'd call subscription.customer.id
.
You may also want to add inverse_of
designations for your relationships in your models (always a good practice to minimize reloading of models from the database).
So, in total, I'd recommend:
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
Oh, and then you can remove the customer_id
from the permitted attributes for subscriptions_attributes
.
UPDATE
Given that Subscription#customer_id is meant to be disjointed from the Customer -> Order -> Subscription relationship... Ignore the above (except for perhaps the inverse_of
stuff) and... You should be able to do:
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
Upvotes: 1