tenacity 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/EXTEND.rdoc +79 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +70 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +103 -0
- data/Rakefile +96 -0
- data/lib/tenacity/associations/belongs_to.rb +28 -0
- data/lib/tenacity/associations/has_many.rb +86 -0
- data/lib/tenacity/associations/has_one.rb +40 -0
- data/lib/tenacity/class_methods.rb +226 -0
- data/lib/tenacity/instance_methods.rb +31 -0
- data/lib/tenacity/orm_ext/activerecord.rb +116 -0
- data/lib/tenacity/orm_ext/couchrest/couchrest_extended_document.rb +45 -0
- data/lib/tenacity/orm_ext/couchrest/couchrest_model.rb +46 -0
- data/lib/tenacity/orm_ext/couchrest/tenacity_class_methods.rb +52 -0
- data/lib/tenacity/orm_ext/couchrest/tenacity_instance_methods.rb +21 -0
- data/lib/tenacity/orm_ext/mongo_mapper.rb +107 -0
- data/lib/tenacity/version.rb +3 -0
- data/lib/tenacity.rb +27 -0
- data/tenacity.gemspec +34 -0
- data/test/associations/belongs_to_test.rb +119 -0
- data/test/associations/has_many_test.rb +184 -0
- data/test/associations/has_one_test.rb +77 -0
- data/test/core/classmethods_test.rb +53 -0
- data/test/fixtures/active_record_car.rb +6 -0
- data/test/fixtures/active_record_climate_control_unit.rb +5 -0
- data/test/fixtures/active_record_nuts.rb +5 -0
- data/test/fixtures/couch_rest_radio.rb +10 -0
- data/test/fixtures/mongo_mapper_button.rb +6 -0
- data/test/fixtures/mongo_mapper_dashboard.rb +10 -0
- data/test/fixtures/mongo_mapper_wheel.rb +9 -0
- data/test/helpers/active_record_test_helper.rb +7 -0
- data/test/helpers/couch_rest_test_helper.rb +8 -0
- data/test/helpers/mongo_mapper_test_helper.rb +3 -0
- data/test/orm_ext/activerecord_test.rb +85 -0
- data/test/orm_ext/couchrest_test.rb +95 -0
- data/test/orm_ext/mongo_mapper_test.rb +93 -0
- data/test/test_helper.rb +47 -0
- metadata +253 -0
data/.gitignore
ADDED
data/EXTEND.rdoc
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
For Tenacity to interact with an ORM, the ORM needs to be extended to support
|
2
|
+
the methods listed below. Beyond that, no additional configuration or code is
|
3
|
+
necessary. Tenacity communicates with the ORM using these methods only, so
|
4
|
+
as long as they have been implemented and are available on the model object,
|
5
|
+
Tenacity will be able to manage the object's relationships.
|
6
|
+
|
7
|
+
|
8
|
+
== A note about IDs
|
9
|
+
|
10
|
+
An ID can be an integer, a string, or an object, depending on the database
|
11
|
+
and ORM you are using. To be as compatible as possible, Tenacity treats
|
12
|
+
all IDs as strings. So, all ORM extensions should accept strings for IDs
|
13
|
+
as input parameters, and return strings for IDs.
|
14
|
+
|
15
|
+
|
16
|
+
== Class Methods
|
17
|
+
|
18
|
+
_t_find(id)
|
19
|
+
|
20
|
+
Find an object by its id, and return it. If the object cannot be found,
|
21
|
+
return nil.
|
22
|
+
|
23
|
+
_t_find_bulk(ids=[])
|
24
|
+
|
25
|
+
Find many objects by the specified ids, and return them in an array.
|
26
|
+
If no objects could be found, return an empty array.
|
27
|
+
|
28
|
+
_t_find_first_by_associate(property, id)
|
29
|
+
|
30
|
+
Find the first object by the specified property name, with the specified id,
|
31
|
+
and return it. If no object could be found, return nil.
|
32
|
+
|
33
|
+
_t_find_all_by_associate(property, id)
|
34
|
+
|
35
|
+
Find all objects by the specified property name, with the specified id, and
|
36
|
+
return them in an array. If no objects could be found, return an empty array.
|
37
|
+
|
38
|
+
_t_initialize_has_many_association(association_id)
|
39
|
+
|
40
|
+
Perform any ORM specific initialization necessary to support a has many
|
41
|
+
association. This could include defining properties, or callback methods,
|
42
|
+
on the object. This method is optional, and does not need to be defined.
|
43
|
+
|
44
|
+
_t_initialize_belongs_to_association(association_id)
|
45
|
+
|
46
|
+
Perform any ORM specific initialization necessary to support a belongs to
|
47
|
+
association. This could include defining properties, or callback methods,
|
48
|
+
on the object. This method is optional, and does not need to be defined.
|
49
|
+
|
50
|
+
_t_initialize_has_one_association(association_id)
|
51
|
+
|
52
|
+
Perform any ORM specific initialization necessary to support a has one
|
53
|
+
association. This could include defining properties, or callback methods,
|
54
|
+
on the object. This method is optional, and does not need to be defined.
|
55
|
+
|
56
|
+
|
57
|
+
== Instance Methods
|
58
|
+
|
59
|
+
_t_reload
|
60
|
+
|
61
|
+
Reload the object from the database, overwriting the objects properties with
|
62
|
+
the data fetched from the database. Return nothing.
|
63
|
+
|
64
|
+
_t_associate_many(association_id, associate_ids)
|
65
|
+
|
66
|
+
Create has_many associations between this object and the objects with ids
|
67
|
+
specified in the array of associate_ids. This method could involve writing
|
68
|
+
the associate_ids into a join table, or into an object's hash.
|
69
|
+
|
70
|
+
_t_get_associate_ids(association_id)
|
71
|
+
|
72
|
+
Get the ids of the objects associated with this object through the specified
|
73
|
+
association, and return them in an array.
|
74
|
+
|
75
|
+
_t_clear_associates(association_id)
|
76
|
+
|
77
|
+
Destroy the association between this object and its current associates through
|
78
|
+
the specified association. Return nothing.
|
79
|
+
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
tenacity (0.1.0)
|
5
|
+
activesupport (>= 2.3)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activemodel (3.0.3)
|
12
|
+
activesupport (= 3.0.3)
|
13
|
+
builder (~> 2.1.2)
|
14
|
+
i18n (~> 0.4)
|
15
|
+
activerecord (3.0.3)
|
16
|
+
activemodel (= 3.0.3)
|
17
|
+
activesupport (= 3.0.3)
|
18
|
+
arel (~> 2.0.2)
|
19
|
+
tzinfo (~> 0.3.23)
|
20
|
+
activesupport (3.0.3)
|
21
|
+
arel (2.0.6)
|
22
|
+
bson (1.1.5)
|
23
|
+
bson_ext (1.1.5)
|
24
|
+
builder (2.1.2)
|
25
|
+
couchrest (1.0.1)
|
26
|
+
json (>= 1.4.6)
|
27
|
+
mime-types (>= 1.15)
|
28
|
+
rest-client (>= 1.5.1)
|
29
|
+
couchrest_model (1.0.0.beta7)
|
30
|
+
activemodel (>= 3.0.0.beta4)
|
31
|
+
activesupport (>= 2.3.5)
|
32
|
+
couchrest (>= 1.0.0.beta)
|
33
|
+
mime-types (>= 1.15)
|
34
|
+
i18n (0.5.0)
|
35
|
+
jnunemaker-validatable (1.8.4)
|
36
|
+
activesupport (>= 2.3.4)
|
37
|
+
json (1.4.6)
|
38
|
+
mime-types (1.16)
|
39
|
+
mongo (1.1.5)
|
40
|
+
bson (>= 1.1.5)
|
41
|
+
mongo_mapper (0.8.6)
|
42
|
+
activesupport (>= 2.3.4)
|
43
|
+
jnunemaker-validatable (~> 1.8.4)
|
44
|
+
plucky (~> 0.3.6)
|
45
|
+
mysql (2.8.1)
|
46
|
+
plucky (0.3.6)
|
47
|
+
mongo (~> 1.1)
|
48
|
+
rake (0.8.7)
|
49
|
+
rcov (0.9.9)
|
50
|
+
rest-client (1.6.1)
|
51
|
+
mime-types (>= 1.16)
|
52
|
+
shoulda (2.11.3)
|
53
|
+
tzinfo (0.3.23)
|
54
|
+
|
55
|
+
PLATFORMS
|
56
|
+
ruby
|
57
|
+
|
58
|
+
DEPENDENCIES
|
59
|
+
activerecord (~> 3.0.0)
|
60
|
+
activesupport (>= 2.3)
|
61
|
+
bson_ext (~> 1.1.3)
|
62
|
+
bundler (~> 1.0.0)
|
63
|
+
couchrest (~> 1.0.0)
|
64
|
+
couchrest_model
|
65
|
+
mongo_mapper (~> 0.8.6)
|
66
|
+
mysql (~> 2.8.1)
|
67
|
+
rake (~> 0.8.7)
|
68
|
+
rcov (~> 0.9.9)
|
69
|
+
shoulda (~> 2.11.3)
|
70
|
+
tenacity!
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 John Wood
|
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,103 @@
|
|
1
|
+
= Tenacity
|
2
|
+
|
3
|
+
An ORM independent way of specifying simple relationships between models
|
4
|
+
backed by different databases.
|
5
|
+
|
6
|
+
It is sometimes necessary, or advantageous, to use more than one database in a
|
7
|
+
given application. However, most ORMs do not support inter-database
|
8
|
+
relationships. While supporting such relationships isn't difficult, it can
|
9
|
+
add quite a bit of boilerplate code to your project.
|
10
|
+
|
11
|
+
Tenacity aims to address this by providing an ORM independent way of specifying
|
12
|
+
simple relationships between models backed by different databases.
|
13
|
+
|
14
|
+
Tenacity is heavily based on ActiveRecord's associations, and aims to behave in
|
15
|
+
much the same way, supporting many of the same options.
|
16
|
+
|
17
|
+
|
18
|
+
== Example
|
19
|
+
|
20
|
+
class User
|
21
|
+
include MongoMapper::Document
|
22
|
+
include Tenacity
|
23
|
+
|
24
|
+
t_has_many :entries
|
25
|
+
end
|
26
|
+
|
27
|
+
class Entry < ActiveRecord::Base
|
28
|
+
include Tenacity
|
29
|
+
|
30
|
+
t_belongs_to :user
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# Fetch related object from the respective database
|
35
|
+
entry.user
|
36
|
+
|
37
|
+
# Set the related object
|
38
|
+
entry.user = some_user
|
39
|
+
entry.save
|
40
|
+
|
41
|
+
# Fetch related objects from the respective database
|
42
|
+
user.entries
|
43
|
+
|
44
|
+
# Add a related object to the collection
|
45
|
+
user.entries << some_entry
|
46
|
+
user.save
|
47
|
+
|
48
|
+
|
49
|
+
== Additional Usage Details
|
50
|
+
|
51
|
+
* The directories that contain your model classes must be in your load path in order for Tenacity to find them.
|
52
|
+
|
53
|
+
|
54
|
+
== Supported ORMs
|
55
|
+
|
56
|
+
* ActiveRecord
|
57
|
+
* MongoMapper
|
58
|
+
* CouchRest (CouchModel and ExtendedDocument)
|
59
|
+
|
60
|
+
See EXTEND.rdoc for information on extendeding Tenacity to work with other ORMs.
|
61
|
+
|
62
|
+
|
63
|
+
== Documentation
|
64
|
+
* http://rdoc.info/github/jwood/tenacity/master/frames
|
65
|
+
|
66
|
+
|
67
|
+
== Contributing to Tenacity
|
68
|
+
|
69
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
70
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
71
|
+
* Fork the project
|
72
|
+
* Start a feature/bugfix branch
|
73
|
+
* Commit and push until you are happy with your contribution
|
74
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
75
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
76
|
+
|
77
|
+
|
78
|
+
== Development
|
79
|
+
|
80
|
+
* MySQL, MongoDB, and CouchDB must be installed and configured.
|
81
|
+
* Install the dependencies
|
82
|
+
|
83
|
+
bundler install
|
84
|
+
|
85
|
+
* Create the test databases
|
86
|
+
|
87
|
+
rake db:create
|
88
|
+
|
89
|
+
* Setup the test databases
|
90
|
+
|
91
|
+
rake db:test:prepare
|
92
|
+
|
93
|
+
* Run the tests
|
94
|
+
|
95
|
+
rake test
|
96
|
+
|
97
|
+
* Code away!
|
98
|
+
|
99
|
+
|
100
|
+
== Copyright
|
101
|
+
|
102
|
+
Copyright (c) 2010 John Wood. See LICENSE.txt for further details.
|
103
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
begin
|
7
|
+
Bundler.setup(:default, :development)
|
8
|
+
rescue Bundler::BundlerError => e
|
9
|
+
$stderr.puts e.message
|
10
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
11
|
+
exit e.status_code
|
12
|
+
end
|
13
|
+
require 'rake'
|
14
|
+
|
15
|
+
require 'rake/testtask'
|
16
|
+
Rake::TestTask.new(:test) do |test|
|
17
|
+
test.libs << 'lib' << 'test' << 'test/fixtures'
|
18
|
+
test.pattern = 'test/**/*_test.rb'
|
19
|
+
test.verbose = true
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rcov/rcovtask'
|
23
|
+
Rcov::RcovTask.new do |test|
|
24
|
+
test.libs << 'test' << 'test/fixtures'
|
25
|
+
test.pattern = 'test/**/*_test.rb'
|
26
|
+
test.verbose = true
|
27
|
+
test.rcov_opts << '--exclude "gems/*"'
|
28
|
+
end
|
29
|
+
|
30
|
+
task :default => :test
|
31
|
+
|
32
|
+
require 'rake/rdoctask'
|
33
|
+
Rake::RDocTask.new do |rdoc|
|
34
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
35
|
+
|
36
|
+
rdoc.rdoc_dir = 'rdoc'
|
37
|
+
rdoc.title = "tenacity #{version}"
|
38
|
+
rdoc.rdoc_files.include('README*')
|
39
|
+
rdoc.rdoc_files.include('EXTEND*')
|
40
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Delete rcov, rdoc, and other generated files'
|
44
|
+
task :clobber => [:clobber_rcov, :clobber_rdoc]
|
45
|
+
|
46
|
+
begin
|
47
|
+
require 'test/helpers/active_record_test_helper'
|
48
|
+
namespace :db do
|
49
|
+
desc "Create the test databases"
|
50
|
+
task :create do
|
51
|
+
system "mysqladmin -u root create tenacity_test"
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "Drop the test databases"
|
55
|
+
task :drop do
|
56
|
+
system "mysqladmin -u root drop -f tenacity_test"
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "Reset the test databases"
|
60
|
+
task :reset => [:drop, :create] do
|
61
|
+
Rake::Task['db:test:prepare'].invoke
|
62
|
+
end
|
63
|
+
|
64
|
+
namespace :test do
|
65
|
+
desc "Setup the test databases"
|
66
|
+
task :prepare do
|
67
|
+
ActiveRecord::Schema.define :version => 0 do
|
68
|
+
|
69
|
+
create_table :active_record_cars, :force => true do |t|
|
70
|
+
end
|
71
|
+
|
72
|
+
create_table :active_record_climate_control_units, :force => true do |t|
|
73
|
+
t.string :mongo_mapper_dashboard_id
|
74
|
+
end
|
75
|
+
|
76
|
+
create_table :active_record_cars_mongo_mapper_wheels, :force => true do |t|
|
77
|
+
t.integer :active_record_car_id
|
78
|
+
t.string :mongo_mapper_wheel_id
|
79
|
+
end
|
80
|
+
|
81
|
+
create_table :active_record_nuts, :force => true do |t|
|
82
|
+
t.string :mongo_mapper_wheel_id
|
83
|
+
end
|
84
|
+
|
85
|
+
create_table :active_record_nuts_mongo_mapper_wheels, :force => true do |t|
|
86
|
+
t.integer :active_record_nut_id
|
87
|
+
t.string :mongo_mapper_wheel_id
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
rescue LoadError
|
95
|
+
# No ActiveRecord
|
96
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Tenacity
|
2
|
+
module BelongsTo #:nodoc:
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def belongs_to_associate(association_id)
|
7
|
+
associate_id = self.send("#{association_id}_id")
|
8
|
+
clazz = associate_class(association_id)
|
9
|
+
clazz._t_find(associate_id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_belongs_to_associate(association_id, associate)
|
13
|
+
self.send "#{association_id}_id=", associate.id.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods #:nodoc:
|
17
|
+
def initialize_belongs_to_association(association_id)
|
18
|
+
_t_initialize_belongs_to_association(association_id) if self.respond_to?(:_t_initialize_belongs_to_association)
|
19
|
+
end
|
20
|
+
|
21
|
+
def _t_stringify_belongs_to_value(record, association_id)
|
22
|
+
record.send "#{association_id}_id=", record.send("#{association_id}_id").to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Tenacity
|
2
|
+
module HasMany #:nodoc:
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def has_many_associates(association_id)
|
7
|
+
ids = _t_get_associate_ids(association_id)
|
8
|
+
clazz = associate_class(association_id)
|
9
|
+
clazz._t_find_bulk(ids)
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_many_associate_ids(association_id)
|
13
|
+
_t_get_associate_ids(association_id)
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_has_many_associate_ids(association_id, associate_ids)
|
17
|
+
clazz = associate_class(association_id)
|
18
|
+
instance_variable_set ivar_name(association_id), clazz._t_find_bulk(associate_ids)
|
19
|
+
end
|
20
|
+
|
21
|
+
def save_without_callback
|
22
|
+
@perform_save_associates_callback = false
|
23
|
+
save
|
24
|
+
ensure
|
25
|
+
@perform_save_associates_callback = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_many_property_name(association_id)
|
29
|
+
self.class.has_many_property_name(association_id)
|
30
|
+
end
|
31
|
+
|
32
|
+
module ClassMethods #:nodoc:
|
33
|
+
def initialize_has_many_association(association_id)
|
34
|
+
_t_initialize_has_many_association(association_id) if self.respond_to?(:_t_initialize_has_many_association)
|
35
|
+
|
36
|
+
attr_accessor :perform_save_associates_callback
|
37
|
+
end
|
38
|
+
|
39
|
+
def _t_save_associates(record, association_id)
|
40
|
+
return if record.perform_save_associates_callback == false
|
41
|
+
|
42
|
+
_t_clear_old_associations(record, association_id)
|
43
|
+
|
44
|
+
associates = (record.instance_variable_get "@_t_#{association_id.to_s}") || []
|
45
|
+
associates.each do |associate|
|
46
|
+
associate.send("#{property_name_for_record(record)}=", record.id.to_s)
|
47
|
+
save_associate(associate)
|
48
|
+
end
|
49
|
+
|
50
|
+
unless associates.blank?
|
51
|
+
associate_ids = associates.map { |associate| associate.id.to_s }
|
52
|
+
record._t_associate_many(association_id, associate_ids)
|
53
|
+
save_associate(record)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def _t_clear_old_associations(record, association_id)
|
58
|
+
clazz = associate_class(association_id)
|
59
|
+
property_name = property_name_for_record(record)
|
60
|
+
|
61
|
+
old_associates = clazz._t_find_all_by_associate(property_name, record.id.to_s)
|
62
|
+
old_associates.each do |old_associate|
|
63
|
+
old_associate.send("#{property_name}=", nil)
|
64
|
+
save_associate(old_associate)
|
65
|
+
end
|
66
|
+
|
67
|
+
record._t_clear_associates(association_id)
|
68
|
+
save_associate(record)
|
69
|
+
end
|
70
|
+
|
71
|
+
def property_name_for_record(record)
|
72
|
+
"#{ActiveSupport::Inflector.underscore(record.class.to_s)}_id"
|
73
|
+
end
|
74
|
+
|
75
|
+
def has_many_property_name(association_id)
|
76
|
+
"t_" + ActiveSupport::Inflector.singularize(association_id) + "_ids"
|
77
|
+
end
|
78
|
+
|
79
|
+
def save_associate(associate)
|
80
|
+
associate.respond_to?(:_t_save_without_callback) ? associate._t_save_without_callback : associate.save
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Tenacity
|
2
|
+
module HasOne #:nodoc:
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def has_one_associate(association_id)
|
7
|
+
clazz = associate_class(association_id)
|
8
|
+
clazz._t_find_first_by_associate(property_name, self.id.to_s)
|
9
|
+
end
|
10
|
+
|
11
|
+
def set_has_one_associate(association_id, associate)
|
12
|
+
associate.send "#{property_name}=", self.id.to_s
|
13
|
+
associate.save
|
14
|
+
end
|
15
|
+
|
16
|
+
def property_name
|
17
|
+
"#{ActiveSupport::Inflector.underscore(self.class.to_s)}_id"
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods #:nodoc:
|
21
|
+
def initialize_has_one_association(association_id)
|
22
|
+
begin
|
23
|
+
require association_id.to_s
|
24
|
+
rescue Exception => e
|
25
|
+
puts "ERROR: #{association_id.to_s} does not appear to be in the load path. Please make sure all model files are in the load path."
|
26
|
+
raise
|
27
|
+
end
|
28
|
+
|
29
|
+
clazz = associate_class(association_id)
|
30
|
+
clazz._t_initialize_has_one_association(ActiveSupport::Inflector.underscore(self.to_s)) if clazz.respond_to?(:_t_initialize_has_one_association)
|
31
|
+
end
|
32
|
+
|
33
|
+
def _t_stringify_has_one_value(record, association_id)
|
34
|
+
record.send "#{association_id}_id=", record.send("#{association_id}_id").to_s
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|