Fingertips-as_new-san 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright © 2008 Fingertips, Eloy Duran <eloy.de.enige@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,6 @@
1
+ = AsNewSan
2
+
3
+ A simple plugin which allows you to create records in the database, but treat
4
+ them as if they were new records.
5
+
6
+ See AsNewSan for documentation and an example.
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 0
data/lib/as_new_san.rb ADDED
@@ -0,0 +1,120 @@
1
+ # The AsNewSan mixin makes it easier to create associations on a new Active
2
+ # Record instance.
3
+ #
4
+ # Use the +as_new+ method to instantiate new empty objects that are immediately
5
+ # saved to the database with a special flag marking them as new. Because new
6
+ # instances are already stored in the database, you always have an +id+
7
+ # available for creating associations. This means you can use the same views
8
+ # and controller logic for new and edit actions which is especially helpful
9
+ # when you are creating new associated objects using Ajax calls.
10
+ #
11
+ # An Active Record class using this mixin needs to have an +as_new+ boolean
12
+ # column with the default value set to +false+ and a +created_at+ column.
13
+ #
14
+ # See AsNewSan::ClassMethods for documentation on the class methods added to
15
+ # ActiveRecord::Base.
16
+ #
17
+ # Example:
18
+ #
19
+ # class CreateMessages < ActiveRecord::Migration
20
+ # def self.up
21
+ # create_table :messages do |t|
22
+ # t.string :body
23
+ # t.boolean :as_new, :default => false
24
+ # t.timestamps
25
+ # end
26
+ # end
27
+ # end
28
+ #
29
+ # class CreateRecipients < ActiveRecord::Migration
30
+ # def self.up
31
+ # create_table :recipient do |t|
32
+ # t.integer :message_id
33
+ # t.string :name
34
+ # end
35
+ # end
36
+ # end
37
+ #
38
+ # class Message < ActiveRecord::Base
39
+ # include AsNewSan
40
+ # has_many :recipients, :dependent => :destroy
41
+ # end
42
+ #
43
+ # class Recipient < ActiveRecord::Base
44
+ # belongs_to :message
45
+ # end
46
+ #
47
+ # class MessagesController < ApplicationController
48
+ # def index
49
+ # # Remove all records older than 1 week that have the `as_new` property set to `true`.
50
+ # Message.collect_garbage!
51
+ #
52
+ # # The mixin comes with the `find_without_as_new` class method, which behaves as the
53
+ # # ActiveRecord::Base#find class method, but only finds records which have their
54
+ # # `as_new` property set to `false`.
55
+ # @messages = Message.find_without_as_new(:all)
56
+ # end
57
+ #
58
+ # def new
59
+ # # Create and save a message with the `as_new` property set to `true`.
60
+ # #
61
+ # # Recipients are created and associated using Ajax calls on the recipients controller.
62
+ # @message = Message.as_new
63
+ # end
64
+ #
65
+ # def update
66
+ # # The mixin comes with a `before_update` filter that sets the `as_new` column to
67
+ # # `false` before saving the updated record.
68
+ # @message = Message.find(params[:id])
69
+ # @message.update_attributes(params[:message])
70
+ #
71
+ # # So, at this point the record is not marked `as_new` anymore.
72
+ # end
73
+ # end
74
+ module AsNewSan
75
+ def self.included(base) #:nodoc:
76
+ base.extend(ClassMethods)
77
+ base.before_update(:unset_as_new)
78
+ end
79
+
80
+ module ClassMethods
81
+ # Instantiates a new object, sets the as_new column to +true+ and saves the
82
+ # associated record without validation.
83
+ #
84
+ # If the record is never updated, or its as_new property explicitely set to
85
+ # +false+, it will be destroyed after 1 week when the collect_garbage!
86
+ # class method is called.
87
+ #
88
+ # See <tt>ActiveRecord::Base.new</tt> for all the other options that can be
89
+ # passed to as_new.
90
+ def as_new(attributes = {})
91
+ returning( new(attributes.merge( :as_new => true )) ) { |record| record.save(false) }
92
+ end
93
+
94
+ # Finds and destroys all the records where the as_new column is set to
95
+ # +true+ and +created_at+ is longer than 1 week ago.
96
+ def collect_garbage!
97
+ find(:all, :conditions => ['as_new = ? AND created_at < ?', true, Time.now - 1.week]).each(&:destroy)
98
+ end
99
+
100
+ # Works the same as <tt>ActiveRecord::Base.find</tt> but only returns
101
+ # records for which the as_new column is set to +false+.
102
+ def find_without_as_new(*args)
103
+ with_scope(:find => { :conditions => { :as_new => false } }) do
104
+ find(*args)
105
+ end
106
+ end
107
+ end
108
+
109
+ # Returns a boolean indicating whether or not this is a +as_new+ record.
110
+ def as_new_record?
111
+ self.as_new
112
+ end
113
+
114
+ private
115
+
116
+ def unset_as_new
117
+ self.as_new = false
118
+ true
119
+ end
120
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe "AsNewSan" do
4
+ include DBSetupAndTeardownHelper
5
+
6
+ it "should really create a record for a `new` object with `as_new` set to `true`" do
7
+ lambda { BaconFlavour.as_new(:name => 'chunky') }.should.differ('BaconFlavour.count', +1)
8
+ BaconFlavour.find_by_name('chunky').as_new.should.be true
9
+ end
10
+
11
+ it "should garbage collect any record which has been in the db for a specific period" do
12
+ old_record = BaconFlavour.as_new(:name => 'banana', :created_at => (Time.now - 1.week - 1))
13
+ new_record = BaconFlavour.as_new(:name => 'smoked')
14
+
15
+ lambda { BaconFlavour.collect_garbage! }.should.differ('BaconFlavour.count', -1)
16
+ end
17
+
18
+ it "should be possible to do a `find` without matching any `as_new` records" do
19
+ as_new_record = BaconFlavour.as_new(:name => 'smells as new')
20
+ not_as_new_record = BaconFlavour.create(:name => 'does not smell at all')
21
+
22
+ BaconFlavour.find(:all).should == [as_new_record, not_as_new_record]
23
+ BaconFlavour.find_without_as_new(:all).should == [not_as_new_record]
24
+ end
25
+
26
+ it "should set `as_new` records to `false` on update" do
27
+ record = BaconFlavour.as_new(:name => 'ice cream')
28
+ record.as_new_record?.should.be true
29
+ record.update_attribute(:name, 'that is right, bacon ice cream')
30
+ record.as_new_record?.should.be false
31
+ end
32
+ end
@@ -0,0 +1,50 @@
1
+ require "rubygems"
2
+ require "test/unit"
3
+ require "test/spec"
4
+ require 'activerecord'
5
+
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+
9
+ require File.expand_path('../../rails/init', __FILE__)
10
+
11
+ module DBSetupAndTeardownHelper
12
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
13
+ ActiveRecord::Migration.verbose = false
14
+
15
+ def self.included(base)
16
+ base.class_eval do
17
+ before do
18
+ ActiveRecord::Schema.define(:version => 1) do
19
+ create_table :bacon_flavours do |t|
20
+ t.string :name
21
+ t.boolean :as_new, :default => false
22
+ t.timestamps
23
+ end
24
+ end
25
+ end
26
+
27
+ after do
28
+ ActiveRecord::Base.connection.tables.each do |table|
29
+ ActiveRecord::Base.connection.drop_table(table)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ class BaconFlavour < ActiveRecord::Base
37
+ include AsNewSan
38
+ end
39
+
40
+ module Test::Spec::Rails
41
+ module ShouldDiffer
42
+ def differ(eval_str, diff)
43
+ before = eval(eval_str)
44
+ @object.call
45
+ assert_equal before + diff, eval(eval_str)
46
+ end
47
+ end
48
+ end
49
+
50
+ Test::Spec::Should.send(:include, Test::Spec::Rails::ShouldDiffer)
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: Fingertips-as_new-san
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Eloy Duran
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-06 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: The AsNewSan mixin makes it easier to create associations on a new Active Record instance. Use the as_new method to instantiate new empty objects that are immediately saved to the database with a special flag marking them as new. Because new instances are already stored in the database, you always have an id available for creating associations. This means you can use the same views and controller logic for new and edit actions which is especially helpful when you are creating new associated objects using Ajax calls.
17
+ email: eloy.de.enige@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ - LICENSE
25
+ files:
26
+ - README.rdoc
27
+ - VERSION.yml
28
+ - lib/as_new_san.rb
29
+ - test/as_new_san_test.rb
30
+ - test/test_helper.rb
31
+ - LICENSE
32
+ has_rdoc: true
33
+ homepage: http://github.com/alloy/as_new_san
34
+ post_install_message:
35
+ rdoc_options:
36
+ - --inline-source
37
+ - --charset=UTF-8
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ requirements: []
53
+
54
+ rubyforge_project:
55
+ rubygems_version: 1.2.0
56
+ signing_key:
57
+ specification_version: 2
58
+ summary: A simple plugin which allows you to create records in the database, but treat them as if they were new records.
59
+ test_files: []
60
+