Harsha M V
Harsha M V

Reputation: 54949

Rails Create Related Models together

I have two Models Order(id, user_id,...) and OrderEvent(id, order_id, ...)the data of these are stored in two Objects @order and @order_event.

Now i want to save Order and update the order_id in OrderEvent and then save the content in the database.

In CakePHP if we had the content structured in a certain way we could save all of these together at once. Is there a way to save the content in a single call so that if there is any validation error both records are not created and fails

Order

--- !ruby/object:Order
attributes:
  id: 
  host_id: 1
  user_id: 1
  order_no: PH1504-F3D11353
  type_of_order: events
  order_date: !ruby/object:DateTime 2015-04-17 10:49:52.066168000 Z
  sub_total: 7050.0
  tax_rate: 
  rate_cost: 
  deliver_charges: 
  discount_code: 
  discount_rate: 
  discount_cost: 
  total_cost: 7050.0
  order_dishes_count: 
  order_events_count: 
  status: 0
  created_at: 
  updated_at: 

OrderEvent

--- !ruby/object:OrderEvent
attributes:
  id: 
  order_id: 
  event_id: 2
  no_of_ppl: 3
  event_date: 2015-01-22 00:00:00.000000000 Z
  cost: 2350.0
  total_cost: 7050.0
  status: 0
  created_at: 
  updated_at: 

Order

class Order < ActiveRecord::Base

  belongs_to :user
  belongs_to :host

  has_many :order_events
  has_many :messages

end

OrderEvent

class OrderEvent < ActiveRecord::Base

  belongs_to :event
  belongs_to :order
end

Upvotes: 3

Views: 3048

Answers (4)

Plamena Gancheva
Plamena Gancheva

Reputation: 700

Inverse_of and accepts_nested_attributes_for allow you to create two associated objects at the same time. Your models should be something like:

class Order < ActiveRecord::Base

  has_many :order_events, inverse_of: :order

  accepts_nested_attributes_for :order_events

end

class OrderEvent < ActiveRecord::Base

  belongs_to :order, inverse_of: :order_event
end

In the orders controller:

def new
  @order = Order.new
  @order.order_events.build
end

def create
  @order = Order.new(order_params)
  ...
end

Allow order_events attributes in the params:

def order_params
   params.require(:order).permit(order_event_attributes: [])
end

In the form:

<%= form_for @order do |f| %>
  <%= f.fields_for :order_events do |event| %>
  <!-- event fields go here -->
<% end %>

Here is an article with more details what invese_of does: http://viget.com/extend/exploring-the-inverse-of-option-on-rails-model-associations

Upvotes: 3

floum
floum

Reputation: 1159

What you are looking for might be :

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

If you only want to update the OrderEvent just do

class OrderEvent
  belongs_to :order
end

And in your controller

@order_event.update_attributes(order: @order)

Edit : update_attributes saves to the database.

See http://apidock.com/rails/ActiveRecord/Persistence/update for more info.

If you have both models ready but none has an id yet then I think you should go for nested attributes :

class Order
  accepts_nested_attributes_for :order_events
  has_many :order_events
end

class OrderEvent
  belongs_to :order
end

I controller, In order to save the Order, with its order_events :

def update
  @order.update_attributes(order_events_attributes: [@order_event])
end

Should work like a charm.

Upvotes: 1

RAJ
RAJ

Reputation: 9747

If you have set proper associations, following will work for you:

@order = Order.create(...)
@order_event = @order.order_events.create(...) # pass all attrs except id & order_id

EDIT:

If I have the object ready and just wanna save can I use '.save' instead of .create – Harsha M V

In that case, you can directly update @order_event as:

@order_event.update(:order => @order)

Upvotes: 1

jon snow
jon snow

Reputation: 3072

Best way is to use Transactions of rails. Reference : Transactions

Upvotes: 1

Related Questions