Ryan.lay
Ryan.lay

Reputation: 1761

rails group collection by association

I'm have a few collections in a controller like so:

def show
  @cave = Cave.includes(cubs: :mamabear).where(id: params[:id]).first
  @cubs = @cave.cubs
  @papabear = Papabear.first
  @dens = Den.where(papabear_id: @papabear.id)
end

and now I'm trying to sort cubs by dens so I can display the cubs with

@dens.each do |d| 
  d.cubs
end

so I wrote the following:

def show
....
  @dens.each do |den|
    den.cubs = []  ## < --- Den does not have an association with Cub ##
    @cubs.each do |cub|
      den.cubs << cub if cub.mamabear.den_id == den.id
    end
  end

  #reject dens if they don't have cubs
  @dens = @dens.reject { |den| den.cubs.all?(&:blank?) }

end

But now I'm getting an undefined method 'cubs for Den' error because Den doesn't have an association with Cub. How do I assign an array of Cubs to each Den without an association?

Upvotes: 0

Views: 391

Answers (3)

kaspernj
kaspernj

Reputation: 1263

Have you considered using a "has many through"-association in regards to cubs -> dens and dens -> cubs?

http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

Examples:

class Den
  has_many :mamabears
  has_many :cubs, through: :mamabears
end

class Cup
  belongs_to :mamabear
  has_one :den, through: :mamabear
end

Then you should be able to do something like:

den.cups #=> [<Cup ...>]
cup.den #=> <Den ...>

Upvotes: 1

Athar
Athar

Reputation: 3268

Association is the best way to handle such scenarios if you want to fetch those cubs belonging to den at multiple places. if you dont want to implement association. you can try this solution

@den_cubs = []
@dens.each do |den|
  cub_for_den= {}  #here we are initializing hash each time for new den
  @cubs.each do |cub|
    cub_for_den[cub.id] = cub if cub.mamabear.den_id == den.id
  end
  @den_cubs << cub_for_den #put the hash in array
end

@den_cubs = @den_cubs.reject { |dc| dc.blank? }

on the show page you can do this

@den_cubs.each do |dc|
  dc.each do |k,v|
    # now here you can display all attributes for the cubs
  end
end

Upvotes: 1

AJFaraday
AJFaraday

Reputation: 2450

1: I would create a standard association of Cubs for den. Probably a standard has_many On dens, so each cub has a den_id.

You're messing about re-inventing the wheel, otherwise.

2: you'll probably find that the undefined method is 'cubs=' as opposed to 'cubs'. It's an important distinction as it says what the code is doing when the error is thrown.

3: if you really want to ignore point 1 and make your own which fills an arbitrary attribute from the controller, you can add this to the Den model.

attr_accessor :cubs

Upvotes: 1

Related Questions