Spyros
Spyros

Reputation: 48606

Ruby/Rails Way to Check if object in an Array exists in other Array

Think of these lines of code :

@boss_locations = BossLocation.order('min_level asc').all
@discovered = current_user.discovered_locations.includes(:boss_location).all

The first one gets all available boss locations. The second one, gets all the discovered user locations(user_id, boss_location_id) and also includes the boss_location object.

Now, in my view, i want to present every boss location and a message like 'Discovered' or 'Not Discovered', based on whether a boss location exists on @discovered.

Now, my question is how can i feed my view with an easy way to do that. I could just traverse both arrays, but i'm pretty sure it's not the better way. Maybe there is a nice way to map all the boss locations based on the discovered boss locations for the user. How would you do it ?

EDIT - The variables have :

@boss_locations :

 => [#<BossLocation id: 670261930, name: "Fire Swamp", location_index: 1, min_level: 5, needed_gold_to_open: 500, created_at: "2011-05-18 05:35:48", updated_at: "2011-05-18 05:35:48">, #<BossLocation id: 723149845, name: "Rabbit Remains", location_index: 3, min_level: 15, needed_gold_to_open: 3000, created_at: "2011-05-18 05:35:48", updated_at: "2011-05-18 05:35:48">, #<BossLocation id: 81327760, name: "Grateful Plains", location_index: 2, min_level: 10, needed_gold_to_open: 1200, created_at: "2011-05-18 05:35:48", updated_at: "2011-05-18 05:35:48">]

@discovered :

 => [#<DiscoveredLocation id: 736487645, user_id: 986759322, boss_location_id: 670261930, created_at: "2011-05-22 05:37:01", updated_at: "2011-05-22 05:37:01">, #<DiscoveredLocation id: 736487646, user_id: 986759322, boss_location_id: 723149845, created_at: "2011-05-22 05:37:06", updated_at: "2011-05-22 05:37:06">, #<DiscoveredLocation id: 736487647, user_id: 986759322, boss_location_id: 81327760, created_at: "2011-05-22 06:01:35", updated_at: "2011-05-22 06:01:35">] 

Upvotes: 0

Views: 1814

Answers (3)

Jonathan Tran
Jonathan Tran

Reputation: 15276

To encapsulate your data-model better, you'll want to modify your model class.

class BossLocation < ActiveRecord::Base
  has_many :discovered_locations
  has_many :users, :through => :discovered_locations

  def discovered_by?(user)
    self.users.include?(user)
  end
end

Then all you need in your controller is:

@boss_locations = BossLocation.order('min_level asc').all

And in your view:

<% @boss_locations.each do |boss_location| %>
  <div>
    <%= boss_location.name %>:
    <%= boss_location.discovered_by?(current_user) ? 'Discovered' : 'Not Discovered' %>
  </div>
<% end %>

Upvotes: 1

dwhalen
dwhalen

Reputation: 1925

This is a lot of logic to put in a controller or view; consider creating a discovered? method on the BossLocation model. That way you could iterate through @boss_locations and call discovered? on each:

  <% @boss_locations.each do |bl| %>
    <div>
      <%= "#{bl.name}: #{bl.discovered?(current_user)}" %>
    </div>
  <% end %>

The method would probably look like this:

class BossLocation < ActiveRecord::Base
  def discovered?(user)
    user.discovered_locations.map(&:boss_location).include?(self)
  end
end

I commented above and you seemed to like the idea, so I wrote it out.

Upvotes: 3

Doug English
Doug English

Reputation: 286

As the objects in the two arrays are not identical, you might need to iterate in a custom way:

<% @boss_locations.each do |boss_location|
  <div>
    <%= boss_location.name %>:
    <%= @discovered_boss_locations.inject('Not Discovered') { |result, element| result = 'Discovered' if element.boss_location_id ==  boss_location.id}
  </div>
<% end %>

Upvotes: 0

Related Questions