Reputation: 4439
A transaction_record
has many workflows
, and each workflow
has many milestones
. One of the milestones
is marked current: true
, and I want to go from the transaction_record
to the current_milestone
:
class TransactionRecord < ApplicationRecord
has_many :workflows
has_many :milestones, through: :workflows
# DOES NOT WORK, but what I want to do...
has_one :current_milestone, through: :workflows, class: Milestone, source: :milestones
# Works, but want to make an association for including
def current_milestone
milestones.where(current: true).first
end
end
class Workflow < ApplicationRecord
belongs_to :transaction_record
has_many :milestones
end
class Milestone < ApplicationRecord
belongs_to :workflow
end
I can create a method that returns the desired milestone
, but I want to make it an actual association so I can include it for DB performance.
I have a transaction_records#index
page where I list the transaction_records
and the current_milestone
for each one. That's an n+1
unless I can figure this out.
I really want to be able to do something like:
@transaction_records = TransactionRecord.includes(:current_milestone)
<% @transaction_records.each do |transaction_record| %>
<%= transaction_record.name %> - <%= transaction_record.current_milestone.name %>
<% end %>
I can specify a direction relationship between transaction_record
and milestone
, and then do transaction_record has_one :current_milestone, -> { where(current: true) }, class_name: Milestone
. But now I'm changing my DB schema for a more efficient load query. Not the end of the world, but not my preference if I already have an association.
Upvotes: 0
Views: 380
Reputation: 1784
To be honest I don't like the concept, that transaction_record
has some kind of active_milestone without any mentioning about joining current_workflow
.
Good solution is to think about both workflow
and milestone
to have an ability to be current
and then:
class TransactionRecord < ApplicationRecord
has_one :current_workflow, ....
has_one :current_milestone, through: current_workflow, ....
end
class Workflow < ApplicationRecord
has_one :current_milestone, condition: ....
end
This is far better for me, but you still need to add additional current
flag attribute in workflow
.
That's why better solution is rework your concept at all.
Remove current
from milestone and add current_milestone_id
to workflow. If it's nil, then this workflow
has no current_milestone
. If it contains some id, then this is your current_workflow
and current_milestone_id
.
Code will look pretty the same, but it will don't have ugly condition in Workflow
Upvotes: 0