Skip to content

With_role cannot be combined into larger queries #579

Closed

Description

@Taeir

The issue

The definition of resources_find in ResourceAdapter uses (simplified) resources.select("table_name.*"). This hinders the ability of ActiveRecord to combine queries together, because the select is already supplied to select all fields, even when only some of them are needed.

The fix

As far as I understand, removing the complete line that supplies the select does not alter any behavior. It leaves it up to ActiveRecord to determine which fields are necessary for the query. It will default to * but can be limited to id when useful for combining queries. I will try to make a pull request (#580) to see if this is indeed the case in all scenarios. I have tested so far with MySQL and SQLite where it works, and I expect other implementations to behave the same.

A detailed example

Setup
Showing with an example, consider models User, Blog and Article:

class User < ActiveRecord::Base
  rolify
end

class Blog < ActiveRecord::Base
  ROLES = %i[editor].freeze
  resourcify

  has_many :articles
end

class Article < ActiveRecord::Base
  belongs_to :blog
end

Normal Behavior
In active record, the following works

Article.where(blog_id: Blog.where(<some conditions>))

These are (usually) combined into a single query. This is because ActiveRecord recognizes that we want only the ids of the blogs and effectively applies .select(:id). Contrast that with for example:

Article.where(blog_id: Blog.where(<some conditions>).ids)

Now we get 2 separate queries, once for all the ids of the blogs and then another query with the condition blog_id IN (... those ids ...).

So for efficiency sake (less requests to the database), the top way would be preferable.

Rolify
Unfortunatly, the rolify with_role has already specified a select * (in resources_find), and this breaks this functionality. For example:

Article.where(blog_id: Blog.with_role(:editor, user))

Gives an invalid SQL query. Similarly, applying .select(:id) has no effect and does not affect the (invalid) query (the former select seems to take precedence). The only resort is to use .ids, which splits it into 2 separate queries.

Versions

Rolify 6.0.0
ActiveRecord 6.1.4.6
All versions of Ruby

Activity

  1. added a commit that references this issue on Feb 23, 2022
    27cb176
  2. Taeir commented on Feb 23, 2022

    @Taeir
    ContributorAuthor

    Actually, #175 explains why this select was added in the first place: as a way to mark the query as not read-only. However, the select prevents the user from specifying their own select (and prevents ActiveRecord from inferring it). Instead, a .readonly(false) might be a cleaner solution.

    Not sure if that is necessary though with newer versions of ActiveRecord since that issue is already 8 years old.

  3. wheatevo commented on Sep 15, 2023

    @wheatevo

    Issue #584 is caused by this select as well.

  4. januszm commented on Dec 10, 2025

    @januszm

    Not sure if that is necessary though with newer versions of ActiveRecord since that issue is already 8 years old.

    It's an old issue, but not critical. I think it's worth resolving, so we have the ability to override select. In the past 2 months I had to find a workaround for this at least once in a Rails application.

  5. januszm commented on Dec 26, 2025

    @januszm

    Actually it's quite important, it really complicates queries in larger projects. @thomas-mcdonald you meantioned you're not using this project anymore. I offer my help as I want to use it in production in at least one app (I like this solution so there may be more projects anyway). Can you add me to maintainers of this repo and to rubygems.org gem?

  6. added a commit that references this issue on Jan 24, 2026
    3d5234d
  7. januszm commented on Jan 27, 2026

    @januszm

    Thanks @thomas-mcdonald ! Also please remember about releasing the gem to rubygems.org
    I'll test master branch after the change now.

  8. Taeir commented on Mar 13, 2026

    @Taeir
    ContributorAuthor

    For those who can't wait for a new release, I have been using the following as an initializer in rails to effectively overwrite the behavior from rolify to apply a fix for this problem:

    # -----------------------------------------------------------------------------------------------------------------
    # Redefine the resources_find method to fix a bug in rolify: https://github.com/RolifyCommunity/rolify/issues/579
    module ResourceAdapterExtension
      def resources_find(roles_table, relation, role_name)
        super(roles_table, relation, role_name).except(:select).readonly(false)
      end
    end
    
    require 'rolify/adapters/active_record/resource_adapter'
    Rolify::Adapter::ResourceAdapter.prepend(ResourceAdapterExtension)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions