开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜