Skip to content
This repository has been archived by the owner on Jun 30, 2021. It is now read-only.

add option to not use default scope. #126

Closed
wants to merge 3 commits into from

Conversation

sufleR
Copy link

@sufleR sufleR commented Aug 20, 2013

I have a situation when I want all behavior of acts_as_paranoid but don't want to scope records by default.

I have added option to not use default scope and add scope to retrieve not deleted records only.

Default option is false to not break any current behavior.

@christopherchiu
Copy link
Collaborator

Hey @sufleR. Thanks for the contribution. Can you explain what is the situation that you're in and why you want this behavior?

@hidde-jan
Copy link

There are some big problems with default_scope in rails. There are currently a handful of issues in rails/rails that show the shortcommings of default_scope and I've been bitten by it in one of my own apps.

Let me show an example. Suppose that we have the following

class Customer < ActiveRecord::Base
  has_many :orders
end

class Order < ActiveRecord::Base
  default_scope { where(deleted_at: nil) }
end

Customer.first.orders.to_sql
=> "SELECT * FROM `orders` WHERE `orders`.`deleted_at` IS NULL AND `orders`.`customer_id` = 1"

Suppose that I want to easily get all orders for the customer (including the deleted ones), the only way to do this is to do the following query:

Order.unscoped.where(customer_id: Customer.first).to_sql
=> "SELECT * FROM `orders` WHERE `orders`.`customer_id` = 1"

In rails < 4.0, this is the only way as far as I know, from 4.0 onwards, we get the except and uscope methods (http://guides.rubyonrails.org/active_record_querying.html#overriding-conditions), which allows us to remove certain pieces of our query:

# Rails 4.0
Customer.where(name: 'Hidde-Jan').except(where: :name).to_sql
=> "SELECT * FROM `customers`"

Customer.order('email DESC').select('id').where(name: "John")
    .unscope(:order, :select, :where).to_sql
=> "SELECT * FROM `customers`"

However, these methods do not work with default_scope, so the following will give an undesired result:

# Rails 4.0
Order.all.unscope(where: :deleted_at)  # Should result in SELECT * FROM `orders`
=> "SELECT * FROM `orders` WHERE `orders`.`deleted_at` IS NULL"

This behavior will not be fixed before rails 4.1 according to some of the rails maintainers.

If you need to show deleted objects in a lot of places, then it get's rather hacky really quick.

@sufleR
Copy link
Author

sufleR commented Sep 6, 2013

Sorry for late reply but I was offline.
@hidde-jan great explanation.

@christopherchiu I am building tables which collect statistics in snowlfake schema wiki.

Fact table model and main model are in one to one relation.
Main model can be removed but statistics not(it's not my decision).

I define relation as has_one with dependent: :destroy and all 'paranoid' magic happens with callbacks.
We use act_as_paranoid elsewhere so I don't want to write all callbacks.

Examples where default scope is wrong behavior:
Department is one of dimensions.

Department.first.task_stats
SELECT "task_stats".* FROM "task_stats" WHERE "task_stats"."department_id" = 1 AND ("task_stats"."deleted_at" IS NULL)

It should contain all task_stats.

Department.includes(:task_stats)
  SELECT "departments".* FROM "departments"
  SELECT "task_stats".* FROM "task_stats" WHERE "task_stats"."department_id" IN (...) AND ("task_stats"."deleted_at" IS NULL)

It should also contain all statistics.

Some of pull requests with "with_deleted" (example) option will be also helpfull to my implementations.

@zzak
Copy link
Contributor

zzak commented May 12, 2014

In this case I think acts_as_paranoid doesn't fit, and you should extend it to fit your needs.

@zzak zzak closed this May 12, 2014
@zzak zzak added the Won't Fix label May 12, 2014
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants