acts_as_paranoid 0.1.7 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ *0.2.0* (6 Nov 2005)
2
+
3
+ * Upgrade to Rails 1.0 RC4. ActiveRecord::Base#constrain has been replaced with scope_with.
4
+
1
5
  *0.1.7* (22 Oct 2005)
2
6
 
3
7
  * Added :with_deleted as a valid option of ActiveRecord::Base#find
@@ -45,6 +45,7 @@ module ActiveRecord #:nodoc:
45
45
  class << self
46
46
  alias_method :original_find, :find
47
47
  alias_method :count_with_deleted, :count
48
+ alias_method :clobbering_with_scope, :with_scope
48
49
  end
49
50
  end
50
51
  include ParanoidMethods
@@ -53,9 +54,6 @@ module ActiveRecord #:nodoc:
53
54
 
54
55
  module ParanoidMethods #:nodoc:
55
56
  def self.included(base) # :nodoc:
56
- class << base
57
- alias_method :clobbering_constrain, :constrain
58
- end
59
57
  base.extend ClassMethods
60
58
  end
61
59
 
@@ -65,7 +63,7 @@ module ActiveRecord #:nodoc:
65
63
  call_original_find = lambda { original_find(*(args << options)) }
66
64
 
67
65
  if !options[:with_deleted]
68
- constrain(scope_constrains.merge(:conditions => deleted_constrain)) { return call_original_find.call }
66
+ with_deleted_scope { return call_original_find.call }
69
67
  end
70
68
 
71
69
  call_original_find.call
@@ -76,36 +74,53 @@ module ActiveRecord #:nodoc:
76
74
  end
77
75
 
78
76
  def count(conditions = nil, joins = nil)
79
- constrain(scope_constrains.merge(:conditions => deleted_constrain)) { count_with_deleted(conditions, joins) }
77
+ with_deleted_scope { count_with_deleted(conditions, joins) }
80
78
  end
81
79
 
82
- # Override #constrain so that nested constrains don't clobber each other.
83
- #
84
- # Entry.constrain(:conditions => 'published_at IS NOT NULL') do
85
- # Entry.constrain(:conditions => 'deleted_at IS NULL') do
86
- # Entry.find(:all)
87
- # end
88
- # end
89
- def constrain(options = {}, &block)
90
- begin
91
- is_new_scope = scope_constrains.empty?
92
- self.scope_constrains = options
93
- block.call if block_given?
94
- ensure
95
- self.scope_constrains = nil if is_new_scope
80
+ def with_scope(method_scoping = {}, is_new_scope = true)
81
+ # Dup first and second level of hash (method and params).
82
+ method_scoping = method_scoping.inject({}) do |hash, (method, params)|
83
+ hash[method] = params.dup
84
+ hash
85
+ end
86
+
87
+ method_scoping.assert_valid_keys [:find, :create]
88
+ if f = method_scoping[:find]
89
+ f.assert_valid_keys [:conditions, :joins, :offset, :limit, :readonly]
90
+ f[:readonly] = true if !f[:joins].blank? && !f.has_key?(:readonly)
96
91
  end
92
+
93
+ raise ArgumentError, "Nested scopes are not yet supported: #{scoped_methods.inspect}" unless scoped_methods.nil?
94
+
95
+ self.scoped_methods = method_scoping
96
+ yield
97
+ ensure
98
+ self.scoped_methods = nil if is_new_scope
97
99
  end
98
100
 
99
101
  protected
100
- def deleted_constrain
102
+ def with_deleted_scope(&block)
101
103
  deleted_cond = "#{table_name}.deleted_at IS NULL"
102
- case scope_constrains[:conditions]
103
- when /#{deleted_cond}/ then scope_constrains[:conditions]
104
- when NilClass then deleted_cond
105
- else "#{scope_constrains[:conditions]} AND #{deleted_cond}"
104
+ if scoped_methods.nil?
105
+ is_new_scope = true
106
+ current_scope = {}
107
+ else
108
+ is_new_scope = false
109
+ current_scope = scoped_methods.clone
110
+ self.scoped_methods = nil
106
111
  end
112
+
113
+ current_scope ||= {}
114
+ current_scope[:find] ||= {}
115
+ if not current_scope[:find][:conditions] =~ /#{deleted_cond}/
116
+ current_scope[:find][:conditions] = current_scope[:find][:conditions].nil? ?
117
+ deleted_cond :
118
+ "(#{current_scope[:find][:conditions]}) AND #{deleted_cond}"
119
+ end
120
+
121
+ with_scope(current_scope, is_new_scope, &block)
107
122
  end
108
-
123
+
109
124
  def validate_find_options(options)
110
125
  options.assert_valid_keys [:conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :with_deleted]
111
126
  end
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :dbfile: acts_as_paranoid_plugin.sqlite.db
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :dbfile: acts_as_paranoid_plugin.sqlite3.db
7
+ postgresql:
8
+ :adapter: postgresql
9
+ :username: postgres
10
+ :password: postgres
11
+ :database: acts_as_paranoid_plugin_test
12
+ :min_messages: ERROR
13
+ mysql:
14
+ :adapter: mysql
15
+ :host: localhost
16
+ :username: rails
17
+ :password:
18
+ :database: acts_as_paranoid_plugin_test
@@ -1,4 +1,4 @@
1
- require 'abstract_unit'
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
3
  class Widget < ActiveRecord::Base
4
4
  acts_as_paranoid
@@ -78,20 +78,20 @@ class ParanoidTest < Test::Unit::TestCase
78
78
  assert Widget.find(1)
79
79
  end
80
80
 
81
- def test_should_not_override_constrains_when_counting
82
- assert_equal 1, Widget.constrain(:conditions => "title = 'widget 1'") { Widget.count }
83
- assert_equal 0, Widget.constrain(:conditions => "title = 'deleted widget 2'") { Widget.count }
84
- assert_equal 1, Widget.constrain(:conditions => "title = 'deleted widget 2'") { Widget.count_with_deleted }
81
+ def test_should_not_override_scopes_when_counting
82
+ assert_equal 1, Widget.with_scope(:find => { :conditions => "title = 'widget 1'" }) { Widget.count }
83
+ assert_equal 0, Widget.with_scope(:find => { :conditions => "title = 'deleted widget 2'" }) { Widget.count }
84
+ assert_equal 1, Widget.with_scope(:find => { :conditions => "title = 'deleted widget 2'" }) { Widget.count_with_deleted }
85
85
  end
86
86
 
87
- def test_should_not_override_constrains_when_finding
88
- assert_equal [1], Widget.constrain(:conditions => "title = 'widget 1'") { Widget.find(:all) }.ids
89
- assert_equal [], Widget.constrain(:conditions => "title = 'deleted widget 2'") { Widget.find(:all) }.ids
90
- assert_equal [2], Widget.constrain(:conditions => "title = 'deleted widget 2'") { Widget.find_with_deleted(:all) }.ids
87
+ def test_should_not_override_scopes_when_finding
88
+ assert_equal [1], Widget.with_scope(:find => { :conditions => "title = 'widget 1'" }) { Widget.find(:all) }.ids
89
+ assert_equal [], Widget.with_scope(:find => { :conditions => "title = 'deleted widget 2'" }) { Widget.find(:all) }.ids
90
+ assert_equal [2], Widget.with_scope(:find => { :conditions => "title = 'deleted widget 2'" }) { Widget.find_with_deleted(:all) }.ids
91
91
  end
92
92
 
93
- def test_should_allow_multiple_constrained_calls_when_finding
94
- Widget.constrain(:conditions => "title = 'deleted widget 2'") do
93
+ def test_should_allow_multiple_scoped_calls_when_finding
94
+ Widget.with_scope(:find => { :conditions => "title = 'deleted widget 2'" }) do
95
95
  assert_equal [2], Widget.find_with_deleted(:all).ids
96
96
  assert_equal [2], Widget.find_with_deleted(:all).ids, "clobbers the constrain on the unmodified find"
97
97
  assert_equal [], Widget.find(:all).ids
@@ -99,8 +99,8 @@ class ParanoidTest < Test::Unit::TestCase
99
99
  end
100
100
  end
101
101
 
102
- def test_should_allow_multiple_constrained_calls_when_counting
103
- Widget.constrain(:conditions => "title = 'deleted widget 2'") do
102
+ def test_should_allow_multiple_scoped_calls_when_counting
103
+ Widget.with_scope(:find => { :conditions => "title = 'deleted widget 2'" }) do
104
104
  assert_equal 1, Widget.count_with_deleted
105
105
  assert_equal 1, Widget.count_with_deleted, "clobbers the constrain on the unmodified find"
106
106
  assert_equal 0, Widget.count
@@ -0,0 +1,19 @@
1
+ ActiveRecord::Schema.define(:version => 1) do
2
+
3
+ create_table :widgets, :force => true do |t|
4
+ t.column :title, :string, :limit => 50
5
+ t.column :deleted_at, :timestamp
6
+ end
7
+
8
+ create_table :categories, :force => true do |t|
9
+ t.column :widget_id, :integer
10
+ t.column :title, :string, :limit => 50
11
+ t.column :deleted_at, :timestamp
12
+ end
13
+
14
+ create_table :categories_widgets, :force => true, :id => false do |t|
15
+ t.column :category_id, :integer
16
+ t.column :widget_id, :integer
17
+ end
18
+
19
+ end
@@ -0,0 +1,36 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'test/unit'
4
+ #require 'active_record'
5
+ #require 'active_support/binding_of_caller'
6
+ #require 'active_support/breakpoint'
7
+ require "#{File.dirname(__FILE__)}/../../../../config/environment"
8
+ require 'active_record/fixtures'
9
+ require "#{File.dirname(__FILE__)}/../init"
10
+
11
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
12
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
13
+ ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite'])
14
+
15
+ load(File.dirname(__FILE__) + "/schema.rb")
16
+
17
+ Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
18
+ $LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
19
+
20
+ class Test::Unit::TestCase #:nodoc:
21
+ def create_fixtures(*table_names)
22
+ if block_given?
23
+ Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
24
+ else
25
+ Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
26
+ end
27
+ end
28
+
29
+ # Turn off transactional fixtures if you're working with MyISAM tables in MySQL
30
+ self.use_transactional_fixtures = true
31
+
32
+ # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
33
+ self.use_instantiated_fixtures = false
34
+
35
+ # Add more helper methods to be used by all tests here...
36
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
3
3
  specification_version: 1
4
4
  name: acts_as_paranoid
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.7
7
- date: 2005-10-22
6
+ version: "0.2"
7
+ date: 2005-11-15
8
8
  summary: acts_as_paranoid keeps models from actually being deleted by setting a deleted_at field.
9
9
  require_paths:
10
10
  - lib
@@ -28,42 +28,20 @@ authors:
28
28
  - Rick Olson
29
29
  files:
30
30
  - lib/acts_as_paranoid.rb
31
- - test/abstract_unit.rb
32
- - test/connections
31
+ - test/database.yml
33
32
  - test/fixtures
34
33
  - test/paranoid_test.rb
35
- - test/tests.rb
36
- - test/connections/native_db2
37
- - test/connections/native_mysql
38
- - test/connections/native_oci
39
- - test/connections/native_postgresql
40
- - test/connections/native_sqlite
41
- - test/connections/native_sqlite3
42
- - test/connections/native_sqlserver
43
- - test/connections/native_sqlserver_odbc
44
- - test/connections/native_db2/connection.rb
45
- - test/connections/native_mysql/connection.rb
46
- - test/connections/native_oci/connection.rb
47
- - test/connections/native_postgresql/connection.rb
48
- - test/connections/native_sqlite/connection.rb
49
- - test/connections/native_sqlite3/connection.rb
50
- - test/connections/native_sqlserver/connection.rb
51
- - test/connections/native_sqlserver_odbc/connection.rb
52
- - test/fixtures/activerecord_paranoid.sqlite
34
+ - test/schema.rb
35
+ - test/test_helper.rb
53
36
  - test/fixtures/categories.yml
54
37
  - test/fixtures/categories_widgets.yml
55
- - test/fixtures/db_definitions
56
38
  - test/fixtures/widgets.yml
57
- - test/fixtures/db_definitions/postgresql.drop.sql
58
- - test/fixtures/db_definitions/postgresql.sql
59
- - test/fixtures/db_definitions/sqlite.drop.sql
60
- - test/fixtures/db_definitions/sqlite.sql
61
39
  - README
62
40
  - MIT-LICENSE
63
41
  - CHANGELOG
64
42
  - RUNNING_UNIT_TESTS
65
43
  test_files:
66
- - test/tests.rb
44
+ - test/paranoid_test.rb
67
45
  rdoc_options: []
68
46
  extra_rdoc_files: []
69
47
  executables: []
@@ -1,25 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../lib')
2
-
3
- require 'rubygems'
4
- require 'test/unit'
5
- require 'active_record'
6
- require 'active_record/fixtures'
7
- require 'active_support/binding_of_caller'
8
- require 'active_support/breakpoint'
9
- require 'connection'
10
- require 'acts_as_paranoid'
11
-
12
- class Test::Unit::TestCase #:nodoc:
13
- def create_fixtures(*table_names)
14
- if block_given?
15
- Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names) { yield }
16
- else
17
- Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names)
18
- end
19
- end
20
- end
21
-
22
- Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
23
- Test::Unit::TestCase.use_instantiated_fixtures = false
24
- Test::Unit::TestCase.use_transactional_fixtures = (ENV['AR_TX_FIXTURES'] == "yes")
25
-
@@ -1,14 +0,0 @@
1
- print "Using native DB2\n"
2
- require 'logger'
3
-
4
- ActiveRecord::Base.logger = Logger.new("debug.log")
5
-
6
- db1 = 'arparanoid'
7
-
8
- ActiveRecord::Base.establish_connection(
9
- :adapter => "db2",
10
- :host => "localhost",
11
- :username => "arunit",
12
- :password => "arunit",
13
- :database => db1
14
- )
@@ -1,14 +0,0 @@
1
- print "Using native MySQL\n"
2
- require 'logger'
3
-
4
- ActiveRecord::Base.logger = Logger.new("debug.log")
5
-
6
- db1 = 'activerecord_paranoid'
7
-
8
- ActiveRecord::Base.establish_connection(
9
- :adapter => "mysql",
10
- :host => "localhost",
11
- :username => "rails",
12
- :password => "",
13
- :database => db1
14
- )
@@ -1,15 +0,0 @@
1
- print "Using OCI Oracle\n"
2
- require 'logger'
3
-
4
- ActiveRecord::Base.logger = Logger.new STDOUT
5
- ActiveRecord::Base.logger.level = Logger::WARN
6
-
7
- db1 = 'activerecord_paranoid'
8
-
9
- ActiveRecord::Base.establish_connection(
10
- :adapter => 'oci',
11
- :host => '', # can use an oracle SID
12
- :username => 'arunit',
13
- :password => 'arunit',
14
- :database => db1
15
- )
@@ -1,14 +0,0 @@
1
- print "Using native PostgreSQL\n"
2
- require 'logger'
3
-
4
- ActiveRecord::Base.logger = Logger.new("debug.log")
5
-
6
- db1 = 'activerecord_paranoid'
7
-
8
- ActiveRecord::Base.establish_connection(
9
- :adapter => "postgresql",
10
- :host => nil,
11
- :username => "postgres",
12
- :password => "postgres",
13
- :database => db1
14
- )
@@ -1,34 +0,0 @@
1
- print "Using native SQlite\n"
2
- require 'logger'
3
- ActiveRecord::Base.logger = Logger.new("debug.log")
4
-
5
- class SqliteError < StandardError
6
- end
7
-
8
- BASE_DIR = File.expand_path(File.dirname(__FILE__) + '/../../fixtures')
9
- sqlite_test_db = "#{BASE_DIR}/activerecord_paranoid.sqlite"
10
-
11
- def make_connection(clazz, db_file, db_definitions_file)
12
- unless File.exist?(db_file)
13
- puts "SQLite database not found at #{db_file}. Rebuilding it."
14
- sqlite_command = %Q{sqlite #{db_file} "create table a (a integer); drop table a;"}
15
- puts "Executing '#{sqlite_command}'"
16
- raise SqliteError.new("Seems that there is no sqlite executable available") unless system(sqlite_command)
17
- clazz.establish_connection(
18
- :adapter => "sqlite",
19
- :dbfile => db_file)
20
- script = File.read("#{BASE_DIR}/db_definitions/#{db_definitions_file}")
21
- # SQLite-Ruby has problems with semi-colon separated commands, so split and execute one at a time
22
- script.split(';').each do
23
- |command|
24
- clazz.connection.execute(command) unless command.strip.empty?
25
- end
26
- else
27
- clazz.establish_connection(
28
- :adapter => "sqlite",
29
- :dbfile => db_file)
30
- end
31
- end
32
-
33
- make_connection(ActiveRecord::Base, sqlite_test_db, 'sqlite.sql')
34
-
@@ -1,33 +0,0 @@
1
- print "Using native SQLite3\n"
2
- require 'logger'
3
- ActiveRecord::Base.logger = Logger.new("debug.log")
4
-
5
- class SqliteError < StandardError
6
- end
7
-
8
- BASE_DIR = File.expand_path(File.dirname(__FILE__) + '/../../fixtures')
9
- sqlite_test_db = "#{BASE_DIR}/activerecord_paranoid.sqlite3"
10
-
11
- def make_connection(clazz, db_file, db_definitions_file)
12
- unless File.exist?(db_file)
13
- puts "SQLite3 database not found at #{db_file}. Rebuilding it."
14
- sqlite_command = %Q{sqlite3 #{db_file} "create table a (a integer); drop table a;"}
15
- puts "Executing '#{sqlite_command}'"
16
- raise SqliteError.new("Seems that there is no sqlite3 executable available") unless system(sqlite_command)
17
- clazz.establish_connection(
18
- :adapter => "sqlite3",
19
- :dbfile => db_file)
20
- script = File.read("#{BASE_DIR}/db_definitions/#{db_definitions_file}")
21
- # SQLite-Ruby has problems with semi-colon separated commands, so split and execute one at a time
22
- script.split(';').each do
23
- |command|
24
- clazz.connection.execute(command) unless command.strip.empty?
25
- end
26
- else
27
- clazz.establish_connection(
28
- :adapter => "sqlite3",
29
- :dbfile => db_file)
30
- end
31
- end
32
-
33
- make_connection(ActiveRecord::Base, sqlite_test_db, 'sqlite.sql')
@@ -1,14 +0,0 @@
1
- print "Using native SQLServer\n"
2
- require 'logger'
3
-
4
- ActiveRecord::Base.logger = Logger.new("debug.log")
5
-
6
- db1 = 'activerecord_paranoid'
7
-
8
- ActiveRecord::Base.establish_connection(
9
- :adapter => "sqlserver",
10
- :host => "localhost",
11
- :username => "sa",
12
- :password => "",
13
- :database => db1
14
- )
@@ -1,15 +0,0 @@
1
- print "Using native SQLServer via ODBC\n"
2
- require 'logger'
3
-
4
- ActiveRecord::Base.logger = Logger.new("debug.log")
5
-
6
- dsn1 = 'activerecord_paranoid'
7
-
8
- ActiveRecord::Base.establish_connection(
9
- :adapter => "sqlserver",
10
- :mode => "ODBC",
11
- :host => "localhost",
12
- :username => "sa",
13
- :password => "",
14
- :dsn => dsn1
15
- )
@@ -1,3 +0,0 @@
1
- drop table categories_widgets;
2
- drop table categories;
3
- drop table widgets;
@@ -1,19 +0,0 @@
1
- CREATE TABLE widgets (
2
- id SERIAL,
3
- title VARCHAR(50),
4
- deleted_at TIMESTAMP
5
- );
6
- SELECT setval('widgets_id_seq', 100);
7
-
8
- CREATE TABLE categories (
9
- id SERIAL,
10
- widget_id INT,
11
- title VARCHAR(50),
12
- deleted_at TIMESTAMP
13
- );
14
- SELECT setval('categories_id_seq', 100);
15
-
16
- CREATE TABLE categories_widgets (
17
- category_id INT,
18
- widget_id INT
19
- );
@@ -1,3 +0,0 @@
1
- DROP TABLE 'categories_widgets';
2
- DROP TABLE 'categories';
3
- DROP TABLE 'widgets';
@@ -1,17 +0,0 @@
1
- CREATE TABLE 'widgets' (
2
- 'id' INTEGER NOT NULL PRIMARY KEY,
3
- 'title' VARCHAR(50),
4
- 'deleted_at' DATETIME
5
- );
6
-
7
- CREATE TABLE 'categories' (
8
- 'id' INTEGER NOT NULL PRIMARY KEY,
9
- 'widget_id' INTEGER,
10
- 'title' VARCHAR(50),
11
- 'deleted_at' DATETIME
12
- );
13
-
14
- CREATE TABLE 'categories_widgets' (
15
- 'category_id' INTEGER,
16
- 'widget_id' INTEGER
17
- );
@@ -1,2 +0,0 @@
1
- $:.unshift "../lib"
2
- Dir["**/*_test.rb"].each { |f| load f }