Bye
Bye

Reputation: 768

Rails: can I use two nested map?

  def has_name? name
    results = auths.map do |auth|
                auth.role_groups.map do |role_group|
                  role_group.resources.any?{ |r| r.name == name}
                end
              end 
    results.any?
  end

This is a method in User model
1 user has many auths
1 auth has many role_groups
1 role_group has many resources

I used two map there, but it does not return results I expect. This is the first time I two nested map, can I use it like this?

Upvotes: 3

Views: 2606

Answers (3)

duhaime
duhaime

Reputation: 27594

Yes you can use nested maps to get the Cartesian product (simple list of all combinations) of two arrays:

a = [1,2,3]
b = [4,5,6]

l = a.map { |i|
  b.map { |j|
    {"a": i, "b": j}
  }
}.flatten(1)

l result:

=> [{:a=>1, :b=>4}, {:a=>1, :b=>5}, {:a=>1, :b=>6}, {:a=>2, :b=>4}, {:a=>2, :b=>5}, {:a=>2, :b=>6}, {:a=>3, :b=>4}, {:a=>3, :b=>5}, {:a=>3, :b=>6}]

Upvotes: 0

Aaditi Jain
Aaditi Jain

Reputation: 7027

Firstly, you can add a direct relationship between auth and resources. In the Auth model: has_many: resources, through: role_groups

the has-many-through relationship can also be used for nested has-many relationships(like in your case). Check out the last example (document, section, paragraph relationships) in here: http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

Then you can do as follows:

def has_name? name
  auths.includes(:resources).flat_map(&:resources).any? do |resource| 
    resource.name == name
  end
end

Upvotes: 0

Nikita Misharin
Nikita Misharin

Reputation: 2030

You can, but the result will have array of array and it isn't considered empty.

[[]].any?
=> true

#flat_map might help you here

def has_name? name
  results = auths.flat_map do |auth|
    auth.role_groups.map do |role_group|
      role_group.resources.any?{ |r| r.name == name}
    end
  end 

  results.any?
end

Or you could change your solution altogether to more performant one with sql (without seeing your models, not sure it will work)

auths.joins(role_groups: :resources).where(resources: { name: name }).exists?

Upvotes: 3

Related Questions