0

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">] 
5
  • 1
    can you show @boss_locations and @discovered examples? May be this will help: [ 1, 3, 5 ] & [ 1, 2, 3 ] #=> [ 1, 3 ] Commented May 22, 2011 at 6:09
  • What does discovered_locations return? Is it an array of BossLocation's, or some general Location type. Commented May 22, 2011 at 6:30
  • nash, that seems like a good idea. The only problem is that @boss_locations has boss locations while discovered mainly have discovered locations that includes boss location as well. I edit to illustrate thanx guys Commented May 22, 2011 at 6:34
  • 1
    Ok, I agree with Jonathan Tran's answer, but I think you should consider creating a discovered? method on the BossLocation model (if possible). Commented May 22, 2011 at 6:42
  • Danny, you are right, i like the idea, i will include that as well, maybe that can handle the situation in a better manner, you're totally right. Commented May 22, 2011 at 6:44

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

yes i like the idea a lot, it's probably what i will implement thanx :) I would only change discovered? because now it knows too much about discovered_locations. It needs some careful thinking, but i think it's the best way to go.
1

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 %>

4 Comments

@SpyrosP I updated my answer with an example of using has_many :through. Check it out.
thanx Jonathan, this combines both answers very nicely and is definitely what i am gonna be using :)
I like the encapsulating method better, but do you think it's better in terms of performance ? It seems so at first glance, to be sincere.
@SpyrosP It's not clear to me. I'd start by looking at the generated SQL in the logs. It may be obvious from that. But in general, ActiveRecord's caching makes it hard to reason about performance w/o benchmarking.
0

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 %>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.