acts_as_nested_by 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +52 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/acts_as_nested_by.gemspec +65 -0
- data/lib/acts_as_nested_by.rb +38 -0
- data/test/helper.rb +24 -0
- data/test/test_acts_as_nested_by.rb +78 -0
- metadata +113 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Thomas Limp
|
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,52 @@
|
|
1
|
+
= acts_as_nested_by
|
2
|
+
|
3
|
+
"acts_as_nested_by" is/will be a simple counterpart for rails' "accepts_attribute_for".
|
4
|
+
|
5
|
+
== Use case example
|
6
|
+
Since the rails-way of handling referential integrity is to code the logic into you your model, without using database dependent foreign key constraints, you might come across situations like this.
|
7
|
+
|
8
|
+
class Foo < ActiveRecord
|
9
|
+
has_many :bars
|
10
|
+
validates_associated :bars
|
11
|
+
accepts_nested_attributes_for :bars
|
12
|
+
end
|
13
|
+
|
14
|
+
class Bar < ActiveRecord
|
15
|
+
belongs_to :foo
|
16
|
+
validates_presence_of :foo
|
17
|
+
end
|
18
|
+
|
19
|
+
Using validates_presence_of :foo instead of :foo_id ensures that not only a :foo_id was given but a Foo object existst in the :foos table.
|
20
|
+
|
21
|
+
But on creation of a Foo with nested Bars in on step produces a kind of dead look, since the :foo_id for the Bars is not available until the Foo ist saved, and the validates_presence_of :bars produces an error in the Bars, no :foo_id, no Foo in the :foos table. And because the Foo :validates_associated :bars it cannot be saved.
|
22
|
+
Using an :unless => :new_record? conditions with the validations might help, but it can but those valdation would also be skipped, if the Bars were not to be created in a nested form.
|
23
|
+
|
24
|
+
To handle this acts_as_nested_by comes in handy.
|
25
|
+
class Bar < ActiveRecord
|
26
|
+
belongs_to :foo
|
27
|
+
acts_as_nested_by :foo
|
28
|
+
validates_presence_of :foo, :unless => :nested_by_foo?
|
29
|
+
end
|
30
|
+
|
31
|
+
Now just pass a parameter (with a hidden form parameter, or in the controller) :nested_by_foo => true when creating Bars nested in a Foo. If the Foo ist valid? it can be saved and the nested Bars will be auto saved and consistency is assured. ;)
|
32
|
+
|
33
|
+
== Nota bene
|
34
|
+
When using :attr_accessible, :attr_proteced and a hidden form parameter you should add :nested_by_foo to the mass-assignable attributes.
|
35
|
+
|
36
|
+
== Next steps/known issues
|
37
|
+
|
38
|
+
Since the setting of :nested_by_foo via mass assignement could be exploited to create inconsitent entries, the build/create methods provide by the association macros should set the :nested_by_foo internaly and the generated ActiveRecord::Base#nested_by_foo should be defined protected.
|
39
|
+
|
40
|
+
== Note on Patches/Pull Requests
|
41
|
+
|
42
|
+
* Fork the project.
|
43
|
+
* Make your feature addition or bug fix.
|
44
|
+
* Add tests for it. This is important so I don't break it in a
|
45
|
+
future version unintentionally.
|
46
|
+
* Commit, do not mess with rakefile, version, or history.
|
47
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
48
|
+
* Send me a pull request. Bonus points for topic branches.
|
49
|
+
|
50
|
+
== Copyright
|
51
|
+
|
52
|
+
Copyright (c) 2010 Thomas Limp. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "acts_as_nested_by"
|
8
|
+
gem.summary = %Q{Add a acts_as_nested_by :nesting_model class method to ActiveRecord::Base models}
|
9
|
+
gem.description = %Q{
|
10
|
+
The acts_as_nested_by class method add 3 instance methods to the model.
|
11
|
+
nested_by_nesting_model=(flag) sets the nesting_model
|
12
|
+
nested_by_nesting_model returns true if nested_by nesting_model
|
13
|
+
nested_by_nesting_model? alias for nested_by_nesting_model
|
14
|
+
}
|
15
|
+
gem.email = "thomas.limp@valiton.com"
|
16
|
+
gem.homepage = "http://github.com/tehael/acts_as_nested_by"
|
17
|
+
gem.authors = ["Thomas Limp"]
|
18
|
+
gem.add_development_dependency "shoulda", ">= 0"
|
19
|
+
gem.add_development_dependency "sqlite3-ruby", ">= 0"
|
20
|
+
gem.add_dependency "activerecord"
|
21
|
+
end
|
22
|
+
Jeweler::GemcutterTasks.new
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
Rake::TestTask.new(:test) do |test|
|
29
|
+
test.libs << 'lib' << 'test'
|
30
|
+
test.pattern = 'test/**/test_*.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/test_*.rb'
|
39
|
+
test.verbose = true
|
40
|
+
end
|
41
|
+
rescue LoadError
|
42
|
+
task :rcov do
|
43
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
task :test => :check_dependencies
|
48
|
+
|
49
|
+
task :default => :test
|
50
|
+
|
51
|
+
require 'rake/rdoctask'
|
52
|
+
Rake::RDocTask.new do |rdoc|
|
53
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
54
|
+
|
55
|
+
rdoc.rdoc_dir = 'rdoc'
|
56
|
+
rdoc.title = "acts_as_nested_by #{version}"
|
57
|
+
rdoc.rdoc_files.include('README*')
|
58
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
59
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{acts_as_nested_by}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Thomas Limp"]
|
12
|
+
s.date = %q{2010-05-05}
|
13
|
+
s.description = %q{
|
14
|
+
The acts_as_nested_by class method add 3 instance methods to the model.
|
15
|
+
nested_by_nesting_model=(flag) sets the nesting_model
|
16
|
+
nested_by_nesting_model returns true if nested_by nesting_model
|
17
|
+
nested_by_nesting_model? alias for nested_by_nesting_model
|
18
|
+
}
|
19
|
+
s.email = %q{thomas.limp@valiton.com}
|
20
|
+
s.extra_rdoc_files = [
|
21
|
+
"LICENSE",
|
22
|
+
"README.rdoc"
|
23
|
+
]
|
24
|
+
s.files = [
|
25
|
+
".document",
|
26
|
+
".gitignore",
|
27
|
+
"LICENSE",
|
28
|
+
"README.rdoc",
|
29
|
+
"Rakefile",
|
30
|
+
"VERSION",
|
31
|
+
"acts_as_nested_by.gemspec",
|
32
|
+
"lib/acts_as_nested_by.rb",
|
33
|
+
"test/helper.rb",
|
34
|
+
"test/test_acts_as_nested_by.rb"
|
35
|
+
]
|
36
|
+
s.homepage = %q{http://github.com/tehael/acts_as_nested_by}
|
37
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
s.rubygems_version = %q{1.3.6.1}
|
40
|
+
s.summary = %q{Add a acts_as_nested_by :nesting_model class method to ActiveRecord::Base models}
|
41
|
+
s.test_files = [
|
42
|
+
"test/helper.rb",
|
43
|
+
"test/test_acts_as_nested_by.rb"
|
44
|
+
]
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
51
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
52
|
+
s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
|
53
|
+
s.add_runtime_dependency(%q<activerecord>, [">= 0"])
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
56
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
57
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
58
|
+
end
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
61
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
62
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ActsAsNestedBy#:nodoc
|
2
|
+
def self.included(base)
|
3
|
+
base.send :extend, ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods #:nodoc
|
7
|
+
# Generates instance methods for setting and reading a nested_by_other flag
|
8
|
+
# raises ArgumentError if association to other does not exist or is not created by the :belongs_to macro
|
9
|
+
def acts_as_nested_by(*association_names)
|
10
|
+
association_names.each do |association_name|
|
11
|
+
if reflection = reflect_on_association(association_name)
|
12
|
+
if :belongs_to == reflection.macro
|
13
|
+
class_eval %{
|
14
|
+
|
15
|
+
def nested_by_#{association_name}=(nested_by_#{association_name})
|
16
|
+
@nested_by_#{association_name} = nested_by_#{association_name}
|
17
|
+
end
|
18
|
+
|
19
|
+
def nested_by_#{association_name}
|
20
|
+
@nested_by_#{association_name} = @nested_by_#{association_name}.nil? ? false : true
|
21
|
+
end
|
22
|
+
|
23
|
+
def nested_by_#{association_name}?
|
24
|
+
nested_by_#{association_name}
|
25
|
+
end
|
26
|
+
}
|
27
|
+
else
|
28
|
+
raise ArgumentError, "Association `#{association_name}' must be :belongs_to but it's `#{reflection.macro}'."
|
29
|
+
end
|
30
|
+
else
|
31
|
+
raise ArgumentError, "No association found for name `#{association_name}'. Has it been defined yet?"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
require "active_record"
|
38
|
+
ActiveRecord::Base.send :include, ActsAsNestedBy
|
data/test/helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
|
+
require 'acts_as_nested_by'
|
8
|
+
|
9
|
+
class Foo < ActiveRecord::Base; end
|
10
|
+
|
11
|
+
class Bar < ActiveRecord::Base; end
|
12
|
+
|
13
|
+
class Test::Unit::TestCase
|
14
|
+
def self.db_setup
|
15
|
+
@dbfile = File.join(File.dirname(__FILE__),"test.sqlite3")
|
16
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => @dbfile)
|
17
|
+
ActiveRecord::Migration.create_table :foos
|
18
|
+
ActiveRecord::Migration.create_table :bars do |t| t.references :foo end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.db_teardown
|
22
|
+
File.delete(@dbfile)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestActsAsNestedBy < Test::Unit::TestCase
|
4
|
+
db_setup
|
5
|
+
|
6
|
+
context "ActiveRecord::Base decendant class" do
|
7
|
+
should "respond to :acts_as_nested_by" do
|
8
|
+
assert Foo.respond_to? :acts_as_nested_by
|
9
|
+
end
|
10
|
+
|
11
|
+
should "raise ArgumentError when trying to set :acts_as_nested_by for an undefined association" do
|
12
|
+
assert_raise ArgumentError do
|
13
|
+
class Bar < ActiveRecord::Base
|
14
|
+
acts_as_nested_by :foo
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
should "raise ArgumentError when trying to set :acts_as_nested_by for association :has_many" do
|
20
|
+
assert_raise ArgumentError do
|
21
|
+
class Foo < ActiveRecord::Base
|
22
|
+
has_many :bars
|
23
|
+
acts_as_nested_by :bars
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
should "raise ArgumentError when trying to set :acts_as_nested_by for association :has_one" do
|
29
|
+
assert_raise ArgumentError do
|
30
|
+
class Foo < ActiveRecord::Base
|
31
|
+
has_one :bar
|
32
|
+
acts_as_nested_by :bar
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "Instance of Bar (which acts_as_nested_by)" do
|
39
|
+
setup do
|
40
|
+
class Bar < ActiveRecord::Base
|
41
|
+
belongs_to :foo
|
42
|
+
acts_as_nested_by :foo
|
43
|
+
end
|
44
|
+
@bar = Bar.new
|
45
|
+
end
|
46
|
+
should "respond to :nested_by_foo=" do
|
47
|
+
assert @bar.respond_to? :nested_by_foo=
|
48
|
+
end
|
49
|
+
|
50
|
+
should "respond to :nested_by_foo" do
|
51
|
+
assert @bar.respond_to? :nested_by_foo
|
52
|
+
end
|
53
|
+
|
54
|
+
should "respond to :nested_by_foo?" do
|
55
|
+
assert @bar.respond_to? :nested_by_foo?
|
56
|
+
end
|
57
|
+
|
58
|
+
should "return false when called #nested_by_foo if nested_by_foo was not set" do
|
59
|
+
assert !@bar.nested_by_foo
|
60
|
+
end
|
61
|
+
|
62
|
+
should "return false when called #nested_by_foo? if nested_by_foo was not set" do
|
63
|
+
assert !@bar.nested_by_foo?
|
64
|
+
end
|
65
|
+
|
66
|
+
should "return true when called #nested_by_foo if nested_by_foo was set" do
|
67
|
+
@bar = Bar.new(:nested_by_foo => 1)
|
68
|
+
assert @bar.nested_by_foo
|
69
|
+
end
|
70
|
+
|
71
|
+
should "return true when called #nested_by_foo? if nested_by_foo was set" do
|
72
|
+
@bar = Bar.new(:nested_by_foo => 1)
|
73
|
+
assert @bar.nested_by_foo?
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
db_teardown
|
78
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: acts_as_nested_by
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Thomas Limp
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-05 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: shoulda
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :development
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: sqlite3-ruby
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
type: :development
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activerecord
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
type: :runtime
|
58
|
+
version_requirements: *id003
|
59
|
+
description: "\n The acts_as_nested_by class method add 3 instance methods to the model.\n nested_by_nesting_model=(flag) sets the nesting_model \n nested_by_nesting_model returns true if nested_by nesting_model\n nested_by_nesting_model? alias for nested_by_nesting_model\n "
|
60
|
+
email: thomas.limp@valiton.com
|
61
|
+
executables: []
|
62
|
+
|
63
|
+
extensions: []
|
64
|
+
|
65
|
+
extra_rdoc_files:
|
66
|
+
- LICENSE
|
67
|
+
- README.rdoc
|
68
|
+
files:
|
69
|
+
- .document
|
70
|
+
- .gitignore
|
71
|
+
- LICENSE
|
72
|
+
- README.rdoc
|
73
|
+
- Rakefile
|
74
|
+
- VERSION
|
75
|
+
- acts_as_nested_by.gemspec
|
76
|
+
- lib/acts_as_nested_by.rb
|
77
|
+
- test/helper.rb
|
78
|
+
- test/test_acts_as_nested_by.rb
|
79
|
+
has_rdoc: true
|
80
|
+
homepage: http://github.com/tehael/acts_as_nested_by
|
81
|
+
licenses: []
|
82
|
+
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options:
|
85
|
+
- --charset=UTF-8
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
segments:
|
94
|
+
- 0
|
95
|
+
version: "0"
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
requirements: []
|
105
|
+
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.3.6.1
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: Add a acts_as_nested_by :nesting_model class method to ActiveRecord::Base models
|
111
|
+
test_files:
|
112
|
+
- test/helper.rb
|
113
|
+
- test/test_acts_as_nested_by.rb
|