Search code examples
recursionelixireager-loading

Elixir recursion


I have a group, which I can attach to other modules. The group can have a parent group:

schema "groups" do
  field :name, :string
  field :deleted, :boolean
  belongs_to :parent, Group
  has_many :users_groups, UserGroup, foreign_key: :group_id

  timestamps()
end

Via user_groups i Can attach users. Now I want to filter, if the user is allowed to see the attached module. I made a check, to see if the user is inside the attached group:

def get_visible_module(module, user_id) do
  case module.group do
    nil -> module
    _ ->
      case module.group.users_groups do
        nil -> module
        _ ->
          val = Enum.filter(module.group.users_groups, fn(x)->
            x.user_id == user_id
          end)

          case val do
            [] ->
              case false do
                true -> module
                false -> nil
              end

            _ -> module
          end
      end
  end
end

This may be not the best code, but I am still learning, so improvements to this part are also welcome :)

Now my problem is to add a recursion to check, if the user_id is attached via user_group to a group, which is attached via the parent_id. I am stucked at this point. For the understanding: A module has a group attached. Only the user in the group or in the group attached via parent_id are allowed to see the module. Groups are structered as a tree, so I need to eager load the parent group and check if the user_group contains the user and check every parent-group too.

Hope it is understandable. THX


Solution

  • Here is a rough skeleton which adapts the naming of your source code. It should give you an idea on how to make a recursion in elixir.

      # Exit case when a module has no more parent
      def get_visible_module(module, nil, user_id) do
        user_in_groups?(module.group.users_groups, user_id)
      end
      # Case when the module has a parent_id
      def get_visible_module(module, parent_id, user_id) do
        # check the groups for user_id permission followed by the recusive part
        user_in_groups?(module.group.users_groups, user_id) and get_visible_module(parent_module, parent_module.parent_id, user_id)  
      end
      # checks if the user is in the group
      defp user_in_groups?(users_groups, user_id) do
        # check if the use is in one of the groups
        true
      end
    

    As @bla already mentioned you should try to use pattern matching to clean up your code and reduce the nesting level of your code.