has_many :through query based on the 'bridge' model's property
What would be the best way to resolve this type of query:
- Each group has many districts
- Each state has many districts
- Each group has many states through districts
- Each district belongs to one member
Group 1 -- * District (belongs to one member) * -- 1 State
I want to look up a particular group's list of states where at least one of its district isn't assigned to a member (i.e. district's member_id is null). In other words, if all the districts in that state have been assigned to a member, that state does not show up in my list.
class State < ActiveRecord::Base
has_many :districts
end
class Group < ActiveRecord::Base
has_many :districts
has_many :states, :through => :districts, :uniq => true
end
class District < ActiveRecord::Base
belongs_to :state
belongs_to :group
belongs_to :member
end
What I'm trying to accomplish in my view is to have the user first select his group, then select the state he wants to work from, and finally the available districts which is populated based on his group and state selections. So basically I don't want the state list to include states which have no districts available.
EDIT:
One possible solution I came up was to define a new method in my Group
class, please tell me if this is a good solution:
class Group < ActiveRecord::Base
...
开发者_运维技巧
def available_states
result = []
self.states.each do |state|
state_list = state.districts & self.districts.where(:member_id => nil)
if !state_list.empty?
result << state
end
end
result
end
end
I feel like you're overcomplicating things.
You say you want the user to choose their group first, then state. So why do you need to filter through each state's full district list? You already have the list of possible districts on the group, don't you? If you &
against each state's districts, you're just going to end up with the group's districts.
It seems this would suffice:
def available_states
districts.where(:member_id => nil).group(:state_id).map(&:state)
end
Or am I missing something?
Purely untested, but you could also try something like this:
class District
# this scope is simple, but keeps the "available" definition where it
# belongs, in District
scope :available, lambda { where(:member_id => nil) }
end
class State
# then here just join "available" districts and group on id for uniqueness
scope :with_available_districts, lambda {
joins(:districts).group(:id) & District.available
}
end
# now you don't need an available_states method, it would just be:
Group.first.states.with_available_districts
精彩评论