Reputation: 768
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
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
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
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