Search code examples
ruby-on-railsrubybelongs-tohas-one

Rails - Create parent and child at the same time in has_one belongs_to


I'm sur I do it wrong, but I can't see where. I've got this two models :

Subscription.rb (child)

class Subscription < ActiveRecord::Base
  attr_accessible :state, :subscriber_id, :subscriber_type, :last_payment

  belongs_to :subscriber, polymorphic: true

  validates :subscriber_id, presence: true
  validates :subscriber_type, presence: true
end

restorer.rb (Parent)

class Restorer < User
  attr_accessible :firstname, :lastname, :restaurant_attributes, :subscription_attributes

  has_one :restaurant, dependent: :destroy, :autosave => true
  has_one :subscription, as: :subscriber, :autosave => true

  accepts_nested_attributes_for :restaurant
  accepts_nested_attributes_for :subscription

end

When I want two create a new restorer, and a new subscription (at the same time) It doesn't work :

  def create
    @restorer = Restorer.create params[:restorer]
    @restaurant = @restorer.build_restaurant params[:restorer][:restaurant_attributes]
    @subscription = @restorer.build_subscription params[:restorer][:subscription_attributes]

    if @restorer.save
      ...
    else
      ...
    end
  end

Solution

  • Looking at the comments and your code, it looks like the reason it isn't working is because of the validations on Subscriber. Restorer has one Subscription and Subscription belongs to a Subscriber. Nowhere are you creating the subscriber, hence why the subscription is failing it's validation. You need to either remove the validations, or set those validated properties (subscriber_id and subscriber_type) on Subscriber.

    It's kinda a bit gross what you are trying to do in your create, but it should look something like this if you are going to do it that way:

    def create
      @restorer = Restorer.create params[:restorer]
    
      # These two lines aren't needed if you are accepting nested attributes
      @restaurant = @restorer.build_restaurant params[:restorer][:restaurant_attributes]
      @subscription = @restorer.build_subscription params[:restorer][:subscription_attributes]
    
      subscriber = Subscriber.new params[:subscriber]
      @subscription.subscriber = subscriber
    
      if @restorer.save
        ...
      else
        ...
      end
    end
    

    Btw, its better to validate the relationship subscriber rather than the id subscriber_id:

    validates :subscriber, presence: true