Reputation: 25
I am using Ruby 2.6.3
I have four tables:
Table #1: Transaction (id, title)
Table #2: Trip (id, name)
Table #3: TripBreakdown (id, name)
Table #4: TripTransaction (id, transaction_id, trip_id, trip_breakdown_id)
Each transaction can belong to one trip and one tripBreakdown. One Trip has many transactions and one TripBreakdown has many transactions So each Transaction belongs to zero or more Trip and TripBreakdown.
For that I created Table #4 to store the transaction_id, trip_id and trip_breakdown_id
I want to create the TripTransaction table so that (transaction_id, trip_id, trip_breakdown_id) are all foreign keys.
This is what the Model classes look like:
class Transaction < ApplicationRecord
belongs_to :trip_transaction, optional: true
end
class Trip < ApplicationRecord
has_many :trip_transactions, class_name: "TripTransaction", foreign_key: "trip_transaction_id"
end
class TripBreakdown < ApplicationRecord
has_many :trip_transactions, class_name: "TripTransaction", foreign_key: "trip_transaction_id"
end
class TripTransaction < ApplicationRecord
belongs_to :transactions, class_name: "Transaction", foreign_key: "transaction_id"
belongs_to :trips, class_name: "Trip", foreign_key: "trip_id"
belongs_to :trip_breakdowns, class_name: "TripBreakdown", foreign_key: "trip_breakdown_id"
end
Questions: 1) I am not sure if my Model classes are correct or not?
2) How can I create new TripTransaction object, connect it with three foreign keys and insert it in the database?
If I have one foreign key, the documentation says I can do something like @book = @author.books.create(published_at: Time.now)
but how can I do that in my case?
Thanks
Upvotes: 0
Views: 899
Reputation: 1758
Answer 1: You don't need a join table (trip_transactions) since transaction has one trip and one trip breakdown. Your table transactions will have column trip_id and trip_breakdown_id. If they can be nil you set optional: :true in relationship.
You can simplify to:
class Transaction < ApplicationRecord
belongs_to :trip, optional: :true
belongs_to :trip_breakdown, optional: :true
end
class Trip < ApplicationRecord
has_many :transactions
end
class TripBreakdown < ApplicationRecord
has_many :transactions
end
Answer 2: Can be done in many ways depending on how you are creating the record. An example to give you an idea is:
@new_transaction = @trip.transactions.new
@new_transaction.trip_breakdown_id = @trip_breakdown.id
@new_transaction.save
Upvotes: 2
Reputation: 164829
@Catmal has the models right. I'd add renaming the generic Transaction to a more specific TripTransaction and to match the other related class names.
Creation can be done in several ways. These all assume you already have Trip and TripBreakdown objects. These all basically do the same thing, but there are subtle differences.
# Via Transaction.create!
transaction = Transaction.create!(
trip: trip,
trip_breakdown: trip_transaction
)
# Via Trip's transaction association.
transaction = trip.transactions.create!(
trip_breakdown: trip_transaction
)
# Via TripBreakdown's transaction association.
transaction = trip_breakdown.transactions.create!(
trip: trip
)
They'll make a Transaction
object associated with the Trip and TripBreakdown. Using the !
version of create means they'll raise an exception if there's a problem instead of silently returning nil.
The advantage of using the association is the cached association will be updated. For example, if you were to use Transaction.create!
you might wind up with an out of date cache.
# Load the Trip's transactions into memory
p trip.transactions
transaction = Transaction.create!(
trip: trip,
trip_breakdown: trip_transaction
)
# The Trip's transactions were cached. This will not include
# the new transaction.
p trip.transactions
# Now the new transaction is seen.
p trip.transactions.reload
If you instead create via the association the cached associations will be updated.
# Load the Trip's transactions into memory
p trip.transactions
# Create an associated Transaction and update the association.
trip.transactions.create!(
trip_breakdown: trip_transaction
)
# This will include the new Transaction.
p trip.transactions
See ActiveRecord::Associations::ClassMethods for more.
Upvotes: 1