I have the following models
class Cargo < ApplicationRecord
has_many :destinations
has_many :assignments
accepts_nested_attributes_for :destinations
accepts_nested_attributes_for :assignments
end
class Destination < ApplicationRecord
has_one :assignment_coming_to_me, class_name: 'Assignment', foreign_key: 'arrive_destination_id'
has_one :assignment_leaving_me, class_name: 'Assignment', foreign_key: 'start_destination_id'
end
class Assignment < ApplicationRecord
belongs_to :start_from, class_name: 'Destination', foreign_key: 'start_destination_id'
belongs_to :arrive_at, class_name: 'Destination', foreign_key: 'arrive_destination_id'
end
Giving a visual image, it's something like this
+-------------+
+---| Destination |
| +-------------+---+ <= start_from
| | +------------+
| +---| Assignment |
| | +------------+
+-------+ | +-------------+---+ <= arrive_at
| Cargo | --+---| Destination |
+-------+ | +-------------+---+ <= start_from
| | +------------+
| +---| Assignment |
| | +------------+
| +-------------+---+ <= arrive_at
+---| Destination |
| +-------------+---+
| |
. .
. .
Now, is there a way to create the whole records at once, given the the parameters like this? (Suppose the destinations and assignments are associated to each other just as the order of the parameter array)
{
cargo: [
destinations_attributes: [{place_id: ..}, {place_id: ...}, ...],
assignments_attributes: [{assignee_id: ..}, {assignee_id: ...}, ...],
]
}
I know saving Destinations first then iterating through them to set Assignment's destination_id can do the job, but wondering if there's a smarter way.
They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.
ActiveRecord expects applications to follow certain naming conventions. These conventions extend from file naming, class naming, table naming and more. By default classes are singular, tables are plural, primary keys are id and foreign keys are table_id.
Whereas an instance of ActiveRecord::Relation is a representation of a query that can be run against your database (but wasn't run yet). Once you run that query by calling to_a , each , first etc. on that Relation a single instance or an array of ActiveRecord::Base instances will be returned.
Well, not knowing the details of your problem I will answer what I think it would be a "smater" way to solve.
Use a has_many through association where you would have:
Cargo has many Destinations through Assignments.
Destinations has many Cargo through Assignments.
Assignments holds both Cargo and Destinations foreign key.
If you need information about the order of destinations, you could just query the records based on the Assignment's create timestamp.
Here has a example-of-has-many-through-using-nested-attributes. I believe that way you can have rails saving all the records "automagicly". Furthermore, you can have the queries offered by the association to handle all the three table's records!
Let me know what you think! Good luck!
Link to guide rails has_many_through assoaciton
Hierarchical structure is too rich for architectural purposes: I could reproduce all your workflow with it:
In the end of the code I left comments
You can run the code in terminal just copy it to test.rb
file and run ruby test.rb
in terminal
And just before, create db in postgresql (or mysql)
require "active_record"
class Cargo < ActiveRecord::Base
establish_connection adapter: 'postgresql', database: 'test_destination'
connection.create_table table_name, force: true do |t|
t.string :name
end
has_many :delivery_places
accepts_nested_attributes_for :delivery_places
end
class DeliveryPlace < ActiveRecord::Base
establish_connection adapter: 'postgresql', database: 'test_destination'
connection.create_table table_name, force: true do |t|
t.string :name
t.integer :order, default: 0
t.datetime :arrived_at
t.belongs_to :cargo
end
belongs_to :cargo
has_one :assigment
accepts_nested_attributes_for :assigment
end
class Assignee < ActiveRecord::Base
establish_connection adapter: 'postgresql', database: 'test_destination'
connection.create_table table_name, force: true do |t|
t.string :name
end
has_many :assigments
has_many :delivery_places, through: :assigments
has_many :cargos, through: :delivery_places
end
class Assigment < ActiveRecord::Base
establish_connection adapter: 'postgresql', database: 'test_destination'
connection.create_table table_name, force: true do |t|
t.belongs_to :delivery_place
t.belongs_to :assignee
end
belongs_to :delivery_place
belongs_to :assignee
accepts_nested_attributes_for :assignee
end
nikolay = Assignee.create! name: 'Nikolay'
dec12 = DateTime.new(2017, 12, 12)
dec13 = DateTime.new(2017, 12, 13)
dec14 = DateTime.new(2017, 12, 14)
Cargo.create! \
name: 'candies',
delivery_places_attributes: [
{
name: 'Moscow',
order: 0,
arrived_at: dec12,
assigment_attributes: {
assignee_id: nikolay.id
}
},
{
name: 'Tokio',
order: 1,
arrived_at: dec13,
assigment_attributes: {
assignee_attributes: {
name: 'Ryo'
}
}
},
{
name: 'Ny York',
order: 2,
arrived_at: dec14,
assigment_attributes: {
assignee_attributes: {
name: 'John'
}
}
}
]
# Let's find all my cargos
puts nikolay.cargos
# => [#<Cargo:0x007fae3e4475e8 id: 1, name: "candies">]
# Do I have any cargos since 13 december till 14 december?
puts nikolay.cargos.joins(:delivery_places).where(delivery_places: { arrived_at: dec13...dec14 }).distinct
# []
# Do I have any cargos since 12 december till 14 december?
puts nikolay.cargos.joins(:delivery_places).where(delivery_places: { arrived_at: dec12...dec14 }).distinct
# => [#<Cargo:0x007fefac16a460 id: 1, name: "candies">]
# Do I have cargo which I sent?
nikolay.cargos.joins(:delivery_places).where(delivery_places: { order: 0 }).distinct
# => [#<Cargo:0x007fefac16a460 id: 1, name: "candies">]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With