Search code examples
ruby-on-railsrubyruby-on-rails-5arel

Query across tables with Arel


I have two tables, users and alternative_users that are exactly the same besides a few MySQL performances tweaks.

I'd like to be able to query the second table from the first model to be able to run tests without having to change my entire codebase.

This would mean able to have this query hit the alternative_users table but still return User objects. To sum it up:

users = User.select(fields).where(conditions).limit(10) # hits alternative_users

# or

users = AlternativeUser.select(fields).where(conditions).limit(10) # returns User object

Note that find_by_sql has this ability:

users = User.find_by_sql("select * from alternative_users")`

... and it works fine, but I want to avoid rewriting code and my codebase is filled with arel keywords (where, limit...) and find_by_sql just returns an array so I can't chain.

Also note that I want this behavior only for a few queries, not the entire app. Because of this I can't use table_name.


Solution

  • To just change individual Relation queries, there's a method for that: from will override the FROM clause to point to whatever you like.

    User.select(:name).from("alternative_users").to_a
    # SELECT name FROM alternative_users;
    

    If you want to access both tables from throughout your application, then I'd suggest doing it with subclasses:

    Rename User to AbstractUser, and add:

    self.abstract_class = true
    

    Then create empty subclasses:

    class User < AbstractUser
    end
    
    class AlternativeUser < AbstractUser
    end
    

    That gives you two very similar model classes (same methods etc), but keeps them separate so you know which one you're asking for (and which one an association is linked to, for example).