milkman
milkman

Reputation: 526

Rails 4 ActiveRecord includes(:model) without its default_scope

I have the following situation in my Rails app. There are two models, let's say User and Company:

class User < ActiveRecord::Base
  belongs_to :company
  default_scope -> {where(removed_at: nil)}
end

and

class Company < ActiveRecord::Base
  has_many :users
end

What I want now is loading an Company record and include the Users

Company.unscoped.all.includes(:users)

What will result in a query to the users table which includes the default-scope. So I get the Company record with all not removed users prefetched. But in this case I do also want the Users where removed_at is not null (=> the removed User records). The "unscoped" method is only applied to the Company model, not to the User model.

Is there any way to do this? Thanks for any ideas!

Upvotes: 7

Views: 7528

Answers (4)

estani
estani

Reputation: 26487

The relation is not preserving this state, when accessing it later (Rails 6.0)

A possible workaround for some cases is forcing the resolution, e.g.:

User.unscoped { Company.includes(:users).to_a }

to_a resolves the relation while in the block, so the scope is effectively removed.

Upvotes: 3

evilguc
evilguc

Reputation: 930

I had a greatly-branched STI models set. So the only approach, which works for me (Rails 4.2.5) is the following:

class UndeadUser < ActiveRecord::Base
  self.table_name = 'users'
end

class User < UndeadUser
  # real logic here
end

class Employee < User; end
class Manager < Employee; end

# grouping model
class Organization < ActiveRecord::Base
  has_many :employees

  has_many :users, class: UndeadUsers
  before_destroy :really_destroy_users_and_data! # in case of using acts_as_paranoid or paranoia gems it might be helpful
end

Solution from @abstractcoder doesn't work for me, because rails try to add WHERE users.type IN ('UndeadUser') when UndeadUser inherited from User.

Upvotes: 0

abstractcoder
abstractcoder

Reputation: 376

Here is the solution I got working in my Rails 4.0 application

class User < ActiveRecord::Base
  belongs_to :company
  default_scope -> {where(removed_at: nil)}
end

class UserUnscoped < User
  self.default_scopes = []
end

class Company < ActiveRecord::Base
  has_many :users, class_name: "UserUnscoped"
end

Company.unscoped.all.includes(:users)

Upvotes: 4

user2503775
user2503775

Reputation: 4367

This method accepts a block. All queries inside the block will not use the default_scope:

User.unscoped { Company.includes(:users).all }

or:

User.unscoped do
 Company.includes(:users).all
end

Upvotes: 3

Related Questions