• Stars
    star
    169
  • Rank 223,656 (Top 5 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 15 years ago
  • Updated about 13 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

DEFUNCT: ActiveRecord 2.3 compatible gem "allowing you to hide and restore records without actually deleting them." Yes, like acts_as_paranoid, only implemented differently...

NOTICE: this library is no longer supported or actively developed by the original author. It never made it to a 1.0 stable version. Use it at your own risk and write lots of tests.

You can read more here: http://blog.semanticart.com/killing_is_paranoid/

is_paranoid ( same as it ever was )

advice and disclaimer

You should always declare is_paranoid before any associations in your model unless you have a good reason for doing otherwise. Some relationships might not behave properly if you fail to do so. If you know what you’re doing (and have written tests) and want to supress the warning then you can pass :suppress_load_order_warning => true as an option.

  is_paranoid :suppress_load_order_warning => true

You should never expect any library to work or behave exactly how you want it to: test, test, test and file an issue if you have any problems. Bonus points if you include sample failing code. Extra bonus points if you send a pull request that implements a feature/fixes a bug.

and you may ask yourself, well, how did I get here?

Sometimes you want to delete something in ActiveRecord, but you realize you might need it later (for an undo feature, or just as a safety net, etc.). There are a plethora of plugins that accomplish this, the most famous of which is the venerable acts_as_paranoid which is great but not really actively developed any more. What’s more, acts_as_paranoid was written for an older version of ActiveRecord and, with default_scope in 2.3, it is now possible to do the same thing with significantly less complexity. Thus, is_paranoid.

and you may ask yourself, how do I work this?

You should read the specs, or the RDOC, or even the source itself (which is very readable), but for the lazy, here’s the hand-holding:

You need ActiveRecord 2.3 and you need to properly install this gem. Then you need a model with a field to serve as a flag column on its database table. For this example we’ll use a timestamp named “deleted_at”. If that column is null, the item isn’t deleted. If it has a timestamp, it should count as deleted.

So let’s assume we have a model Automobile that has a deleted_at column on the automobiles table.

If you’re working with Rails, in your environment.rb, add the following to your initializer block (you may want to change the version number).

Rails::Initializer.run do |config|
  # ...
  config.gem "semanticart-is_paranoid", :lib => 'is_paranoid', :version => ">= 0.0.1"
end

Then in your ActiveRecord model

class Automobile < ActiveRecord::Base
  is_paranoid
end

Now our automobiles are now soft-deleteable.

  that_large_automobile = Automobile.create()
  Automobile.count # => 1

  that_large_automobile.destroy
  Automobile.count # => 0
  Automobile.count_with_destroyed # => 1

  # where is that large automobile?
  that_large_automobile = Automobile.find_with_destroyed(:all).first
  that_large_automobile.restore
  Automobile.count # => 1

One thing to note, destroying is always undo-able, but deleting is not. This is a behavior difference between acts_as_paranoid and is_paranoid.

  Automobile.destroy_all
  Automobile.count # => 0
  Automobile.count_with_destroyed # => 1
  
  Automobile.delete_all
  Automobile.count_with_destroyed # => 0
  # And you may say to yourself, "My god!  What have I done?"

All calculations and finds are created via a define_method call in method_missing. So you don’t get a bunch of unnecessary methods defined unless you use them. Any find/count/sum/etc. with_destroyed calls should work and you can also do find/count/sum/etc._destroyedonly.

Specifying alternate rules for what should be considered destroyed

“deleted_at” as a timestamp is what acts_as_paranoid uses to define what is and isn’t destroyed (see above), but you can specify alternate options with is_paranoid. In the is_paranoid line of your model you can specify the field, the value the field should have if the entry should count as destroyed, and the value the field should have if the entry is not destroyed. Consider the following models:

  class Pirate < ActiveRecord::Base
    is_paranoid :field => [:alive, false, true]
  end

  class DeadPirate < ActiveRecord::Base
    set_table_name :pirates
    is_paranoid :field => [:alive, true, false]
  end

These two models share the same table, but when we are finding Pirates, we’re only interested in those that are alive. To break it down, we specify :alive as our field to check, false as what the model field should be marked at when destroyed and true to what the field should be if they’re not destroyed. DeadPirates are specified as the opposite. Check out the specs if you’re still confused.

Note about validates_uniqueness_of:

validates_uniqueness_of does not, by default, ignore items marked with a deleted_at (or other field name) flag. This is a behavior difference between is_paranoid and acts_as_paranoid. You can overcome this by specifying the field name you are using to mark destroyed items as your scope. Example:

  class Android < ActiveRecord::Base
    validates_uniqueness_of :name, :scope => :deleted_at
    is_paranoid
  end

And now the validates_uniqueness_of will ignore items that are destroyed.

and you may ask yourself, where does that highway go to?

If you find any bugs, have any ideas of features you think are missing, or find things you’re like to see work differently, feel free to file an issue or send a pull request.

Currently on the todo list:

  • add options for merging additional default_scope options (i.e. order, etc.)

Thanks

Thanks to Rick Olson for acts_as_paranoid which is obviously an inspiration in concept and execution, Ryan Bates for mentioning the idea of using default_scope for this on Ryan Daigle’s post introducing default_scope, and the Talking Heads for being the Talking Heads.

More Repositories

1

simpleapiproxy

An API proxy written in Go to allow consuming apis via javascript without exposing the api keys
Go
23
star
2

hoboken

a simple wiki powered by sinatra
Ruby
21
star
3

tag-peek.vim

A neovim plugin for peeking at tag definitions using the `nvim_open_win` "floating window" feature.
Vim Script
14
star
4

smart-meta

A plugin for simplifying view titles, descriptions, and keywords in Rails 2.3
Ruby
8
star
5

rack-roll

randomly rick roll your users with the help of rack. pointless and mean.
Ruby
8
star
6

simple-menu.vim

Create simple menus in Vim
Vim Script
7
star
7

ruby-code-actions.nvim

ruby code actions for null-ls in neovim
Lua
5
star
8

url_unroller

A simple url unroller (un-shortener) in elixir
Elixir
5
star
9

liiikes

a simple app that utilizes the Dribbble API for some stats
Ruby
4
star
10

cyoa-parser

A simple parser w/ tools for managing a Choose-Your-Own-Adventure-style story in pandoc
Ruby
3
star
11

stuff-site

The app running http://stuff.lilleaas.net and http://blog.semanticart.com
Ruby
3
star
12

neighborly.js

a prototype and jQuery library for finding elements that are vertical neighbors to the user's scrolled position
JavaScript
3
star
13

ermahgerd_eberks

scrape the digital minuteman library catalog and see what matches your goodreads list
Ruby
2
star
14

LMApi

unofficial json api wrapper for archive.org's live music archive (etree)
Ruby
2
star
15

undead-music-api

an api for finding live music
Ruby
1
star
16

undead-music-app

A sample app for accessing the UndeadMusicAPI
Ruby
1
star
17

url_unroller_app

toy elixir plug app
Elixir
1
star
18

letterpress-board-parser

A simple board parser for Letterpress that leans heavily on tesseract and imagemagick
Ruby
1
star