can_be 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/CHANGELOG.md +14 -5
- data/Gemfile.lock +56 -0
- data/README.md +30 -48
- data/can_be.gemspec +1 -0
- data/docs/details.md +94 -0
- data/docs/history.md +71 -0
- data/docs/rspec_matcher.md +11 -0
- data/lib/can_be/builder/can_be.rb +24 -5
- data/lib/can_be/builder/can_be_detail.rb +62 -4
- data/lib/can_be/config.rb +30 -5
- data/lib/can_be/model_extensions.rb +3 -3
- data/lib/can_be/processor/instance.rb +106 -11
- data/lib/can_be/rspec/matchers.rb +9 -0
- data/lib/can_be/rspec/matchers/can_be_detail_matcher.rb +26 -0
- data/lib/can_be/rspec/matchers/can_be_matcher.rb +76 -0
- data/lib/can_be/version.rb +1 -1
- data/spec/can_be/config_spec.rb +42 -0
- data/spec/can_be/model_extensions_spec.rb +14 -187
- data/spec/can_be/rspec/matchers/can_be_detail_matcher_spec.rb +11 -0
- data/spec/can_be/rspec/matchers/can_be_matcher_spec.rb +57 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/can_be_detail_history_shared_examples.rb +17 -0
- data/spec/support/can_be_detail_shared_examples.rb +13 -0
- data/spec/support/can_be_history_shared_examples.rb +135 -0
- data/spec/support/can_be_shared_examples.rb +204 -0
- data/spec/support/models.rb +54 -0
- data/spec/support/schema.rb +55 -0
- metadata +43 -3
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,20 @@
|
|
1
|
-
## Version 0.
|
1
|
+
## [Version 0.3.0](https://github.com/mstarkman/can_be/tree/v0.3.0)
|
2
2
|
|
3
|
-
|
3
|
+
* Allowed the options to be specified inside the can_be method call block
|
4
|
+
* Added a block processor to each of the `change_to` methods
|
5
|
+
* Added the ability to configure the relationship name
|
6
|
+
* Implemented a set of custom RSpec matcher
|
7
|
+
* History can be kept to easily get back to data after switching can_be types
|
8
|
+
* Fixed issue where calling a change_to method didn't destroy the original details record upon save
|
9
|
+
|
10
|
+
## [Version 0.2.1](https://github.com/mstarkman/can_be/tree/v0.2.1)
|
11
|
+
|
12
|
+
Changed the way that the details models are added.
|
4
13
|
|
5
|
-
## Version 0.2.0
|
14
|
+
## [Version 0.2.0](https://github.com/mstarkman/can_be/tree/v0.2.0)
|
6
15
|
|
7
16
|
Added details functionality for storing custom fields per type.
|
8
17
|
|
9
|
-
## Version 0.
|
18
|
+
## [Version 0.1.0](https://github.com/mstarkman/can_be/tree/v0.1.0)
|
10
19
|
|
11
|
-
|
20
|
+
Initial release.
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
can_be (0.3.0)
|
5
|
+
activerecord (~> 3.1)
|
6
|
+
activesupport (~> 3.1)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activemodel (3.2.11)
|
12
|
+
activesupport (= 3.2.11)
|
13
|
+
builder (~> 3.0.0)
|
14
|
+
activerecord (3.2.11)
|
15
|
+
activemodel (= 3.2.11)
|
16
|
+
activesupport (= 3.2.11)
|
17
|
+
arel (~> 3.0.2)
|
18
|
+
tzinfo (~> 0.3.29)
|
19
|
+
activesupport (3.2.11)
|
20
|
+
i18n (~> 0.6)
|
21
|
+
multi_json (~> 1.0)
|
22
|
+
arel (3.0.2)
|
23
|
+
builder (3.0.4)
|
24
|
+
coderay (1.0.8)
|
25
|
+
database_cleaner (0.9.1)
|
26
|
+
diff-lcs (1.1.3)
|
27
|
+
i18n (0.6.1)
|
28
|
+
method_source (0.8.1)
|
29
|
+
multi_json (1.5.0)
|
30
|
+
pry (0.9.10)
|
31
|
+
coderay (~> 1.0.5)
|
32
|
+
method_source (~> 0.8)
|
33
|
+
slop (~> 3.3.1)
|
34
|
+
rake (10.0.2)
|
35
|
+
rspec (2.12.0)
|
36
|
+
rspec-core (~> 2.12.0)
|
37
|
+
rspec-expectations (~> 2.12.0)
|
38
|
+
rspec-mocks (~> 2.12.0)
|
39
|
+
rspec-core (2.12.0)
|
40
|
+
rspec-expectations (2.12.0)
|
41
|
+
diff-lcs (~> 1.1.3)
|
42
|
+
rspec-mocks (2.12.0)
|
43
|
+
slop (3.3.3)
|
44
|
+
sqlite3 (1.3.6)
|
45
|
+
tzinfo (0.3.35)
|
46
|
+
|
47
|
+
PLATFORMS
|
48
|
+
ruby
|
49
|
+
|
50
|
+
DEPENDENCIES
|
51
|
+
can_be!
|
52
|
+
database_cleaner
|
53
|
+
pry
|
54
|
+
rake
|
55
|
+
rspec (~> 2.0)
|
56
|
+
sqlite3
|
data/README.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
-
# CanBe [![Build Status](https://secure.travis-ci.org/mstarkman/can_be.png?branch=master)](https://travis-ci.org/mstarkman/can_be) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/mstarkman/can_be)
|
1
|
+
# CanBe [![Build Status](https://secure.travis-ci.org/mstarkman/can_be.png?branch=master)](https://travis-ci.org/mstarkman/can_be) [![Gem Version](https://badge.fury.io/rb/can_be.png)](http://badge.fury.io/rb/can_be) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/mstarkman/can_be)
|
2
2
|
|
3
|
-
CanBe allows you to track the type of your ActiveRecord model in a consistent simple manner. With just a little configuration on your part, each type of record can contain different attributes that are
|
3
|
+
CanBe allows you to track the type of your ActiveRecord model in a consistent simple manner. With just a little configuration on your part, each type of record can contain different attributes that are specific to that type of record. From a data modeling perspective this is preferred over [ActiveRecord STI](http://api.rubyonrails.org/classes/ActiveRecord/Base.html#label-Single+table+inheritance) since you will not have many columns in your database that have null values. Under the hood, CanBe uses one-to-one [Polymorphic Associations](http://guides.rubyonrails.org/association_basics.html#polymorphic-associations) to accomplish the different attributes per type.
|
4
|
+
|
5
|
+
Here is a blog post that will describe more of the rationale behind the CanBe gem: [http://blog.markstarkman.com/blog/2013/01/09/writing-my-first-rubygem-canbe/](http://blog.markstarkman.com/blog/2013/01/09/writing-my-first-rubygem-canbe/)
|
6
|
+
|
7
|
+
## Versioning
|
8
|
+
|
9
|
+
I will be following [Semantic Versioning](http://semver.org/) as closely as possible. The `master` branch will be the latest development version and may not match the version of the code you are using. There is a git tag for each released version. The [CHANGELOG.md](https://github.com/mstarkman/can_be/blob/master/CHANGELOG.md) will contain the correct links to each version.
|
4
10
|
|
5
11
|
## Installation
|
6
12
|
|
@@ -8,13 +14,21 @@ Add this line to your application's Gemfile:
|
|
8
14
|
|
9
15
|
gem 'can_be'
|
10
16
|
|
17
|
+
If you feel like living on the edge, you can add this to your applications' Gemfile:
|
18
|
+
|
19
|
+
gem 'can_be', git: "git://github.com/mstarkman/can_be.git"
|
20
|
+
|
11
21
|
And then execute:
|
12
22
|
|
13
23
|
$ bundle
|
14
24
|
|
15
|
-
|
25
|
+
## Documentation
|
26
|
+
|
27
|
+
The documentation for the basic implementation of CanBe can be found in this readme. Here is the documentation for the other features.
|
16
28
|
|
17
|
-
|
29
|
+
* [Different Attributes per CanBe Type (details)](https://github.com/mstarkman/can_be/blob/master/docs/details.md)
|
30
|
+
* [Keeping Details History When Changing CanBe Types](https://github.com/mstarkman/can_be/blob/master/docs/history.md)
|
31
|
+
* [Custom RSpec Matchers](https://github.com/mstarkman/can_be/blob/master/docs/rspec_matcher.md)
|
18
32
|
|
19
33
|
## Database Configuration (via migrations)
|
20
34
|
|
@@ -31,23 +45,7 @@ class AddCanBeTypeToAddresses < ActiveRecord::Migration
|
|
31
45
|
end
|
32
46
|
```
|
33
47
|
|
34
|
-
|
35
|
-
|
36
|
-
If you want to store different attributes (columns), there are some more columns that you will need to add to your model, `details_id` and `details_type`. These fields will be used to store the relationships to the details information. Indexing these columns is your choice.
|
37
|
-
|
38
|
-
Example migration:
|
39
|
-
|
40
|
-
```ruby
|
41
|
-
class AddCanBeDetailsToAddresses < ActiveRecord::Migration
|
42
|
-
def change
|
43
|
-
add_column :addresses, :details_id, :integer
|
44
|
-
add_column :addresses, :details_type, :string
|
45
|
-
add_index :addresses, [:details_id, :details_type]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
```
|
49
|
-
|
50
|
-
You will also need to create the models that will be used to represent the details attributes for each type. You will need to configure the model to be a details model be calling the `can_be_detail` method in your model. You do not need to specify a details model for each CanBe type if there are not any extra attributes required for that type.
|
48
|
+
**NOTE:** Examples of the database migrations can be found in the [`spec/support/schema.rb`](https://github.com/mstarkman/can_be/blob/master/spec/support/schema.rb) file.
|
51
49
|
|
52
50
|
## Model Configuration
|
53
51
|
|
@@ -73,44 +71,36 @@ class Person < ActiveRecord::Base
|
|
73
71
|
end
|
74
72
|
```
|
75
73
|
|
76
|
-
|
77
|
-
|
78
|
-
In order to wire up a model to be a CanBe details model, you will need to call the `can_be_detail` method on that model.
|
79
|
-
|
80
|
-
```ruby
|
81
|
-
class HomeAddressDetail < ActiveRecord::Base
|
82
|
-
can_be_detail :address
|
83
|
-
end
|
84
|
-
```
|
85
|
-
The `can_be_detail` method take in one parameter. The parameter is the link to the CanBe model. This must be a symbol that will reference the CanBe model. In order to create the proper symbol, you can execute the following into your Rails console: `<ModelName>.name.underscore.to_sym`. Here is an example: `Address.name.underscore.to_sym`. In the above example, this will be used for the `Address` CanBe model.
|
86
|
-
|
87
|
-
You will also need to call the `add_details_model` method in the `can_be` block, passing in the CanBe type and a symbol that represets the details model class.
|
74
|
+
Or you can set the options in a block when calling `can_be`.
|
88
75
|
|
89
76
|
```ruby
|
90
|
-
class
|
91
|
-
can_be :
|
92
|
-
|
77
|
+
class Person < ActiveRecord::Base
|
78
|
+
can_be :male, :female do
|
79
|
+
field_name :gender
|
80
|
+
default_type :female
|
93
81
|
end
|
94
82
|
end
|
95
83
|
```
|
96
84
|
|
85
|
+
**NOTE:** Examples of the model configurations can be found in the [`spec/support/models.rb`](https://github.com/mstarkman/can_be/blob/master/spec/support/models.rb) file.
|
86
|
+
|
97
87
|
## Usage
|
98
88
|
|
99
89
|
The CanBe gem will provide you a lot methods to handle your type processing in an easy and consistent manner.
|
100
90
|
|
101
91
|
### Instantiating New Models
|
102
92
|
|
103
|
-
You can continue to instantiate your CanBe models by using the `new` method. When you do, CanBe will ensure that the type of the record is assigned the
|
93
|
+
You can continue to instantiate your CanBe models by using the `new` method. When you do, CanBe will ensure that the type of the record is assigned the default CanBe type for your model.
|
104
94
|
|
105
95
|
There are also some helper methods put on your model to make it easier to instantiate the type of model that you want. These methods will take the form of `new_<CanBe type>`. For example, you can call `Address.new_home_address`. These methods will take the same parameters as the base `new` method provided by ActiveRecord.
|
106
96
|
|
107
97
|
### Creating New Models
|
108
98
|
|
109
|
-
You can continue to create your CanBe models by using the `create` method. When you do, CanBe will ensure that the type of the record is assigned the
|
99
|
+
You can continue to create your CanBe models by using the `create` method. When you do, CanBe will ensure that the type of the record is assigned the default CanBe type for your model.
|
110
100
|
|
111
101
|
There are also some helper methods put on your model to make it easier to create the type of model that you want. These methods will take the form of `create_<CanBe type>`. For example, you can call `Address.create_home_address`. These methods will take the same parameters as the base `create` method provided by ActiveRecord.
|
112
102
|
|
113
|
-
### Changing CanBe Types
|
103
|
+
### Changing CanBe Types (the "change_to" methods)
|
114
104
|
|
115
105
|
There are several ways to change the type of record that you are working with. You can access the `can_be_type` attribute (or other attribute if you specified the field to be used) and change the value directly.
|
116
106
|
|
@@ -120,9 +110,7 @@ You can change the type of record and not persist it immediately to the database
|
|
120
110
|
|
121
111
|
If you want to change the type of the record and persist it to the database immediately, you can call the appropriate `change_to_<CanBe type>!` method. For example, this method call will change the type of record to `:work_address` and persist the change to the database: `Address.create.change_to_work_address!`
|
122
112
|
|
123
|
-
There is a validator for the CanBe field, that will
|
124
|
-
|
125
|
-
NOTE: that when you are changing the type of record the details record will be changed to the correct CanBe details record. New records will only be persisted to the database when the CanBe model is persisted. If you change the CanBe model to a type that does not have a corresponding details model, `nil` will be stored for the details.
|
113
|
+
There is a validator for the CanBe field, that will ensure that the CanBe field is set to one of the CanBe types before persisting the record.
|
126
114
|
|
127
115
|
### Boolean Evaluation
|
128
116
|
|
@@ -134,12 +122,6 @@ There are two ways to find specific types of records. You can use the `find_by_
|
|
134
122
|
|
135
123
|
Methods are also defined on your CanBe model that will find all of the records for a specific CanBe type. These methods take the form of `<pluralized CanBe type>`. For example, `Address.home_addresses` would return all of the records with a type of `:home_address`.
|
136
124
|
|
137
|
-
### Accessing the Details
|
138
|
-
|
139
|
-
If you want to access the details model, you can call the `details` method on your instance and the instance of your model will be returned. If the type of model that you are using does not have a details model, `nil` will be returned.
|
140
|
-
|
141
|
-
When you persist your CanBe model to the database, your details model will automatically be persisted.
|
142
|
-
|
143
125
|
## Contributing
|
144
126
|
|
145
127
|
1. Fork it
|
data/can_be.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.add_development_dependency('sqlite3')
|
22
22
|
gem.add_development_dependency('database_cleaner')
|
23
23
|
gem.add_development_dependency('rake')
|
24
|
+
gem.add_development_dependency('pry')
|
24
25
|
|
25
26
|
gem.add_dependency("activerecord", "~> 3.1")
|
26
27
|
gem.add_dependency("activesupport", "~> 3.1")
|
data/docs/details.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# Different Attributes per CanBe Type (details) #
|
2
|
+
|
3
|
+
CanBe can all you to store different attributes (columns) for each CanBe type that you define. This document will show you the implementation details.
|
4
|
+
|
5
|
+
## Database Migrations ##
|
6
|
+
|
7
|
+
If you want to store different attributes (columns), there are some more columns that you will need to add to your model, `details_id` and `details_type`. These fields will be used to store the relationships to the details information. Indexing these columns is your choice. Example migration:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class AddCanBeDetailsToAddresses < ActiveRecord::Migration
|
11
|
+
def change
|
12
|
+
add_column :addresses, :details_id, :integer
|
13
|
+
add_column :addresses, :details_type, :string
|
14
|
+
add_index :addresses, [:details_id, :details_type]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
You will also need to create the models that will be used to represent the details attributes for each type. You will need to configure the model to be a details model be calling the `can_be_detail` method in your model. You do not need to specify a details model for each CanBe type if there are not any extra attributes required for that type.
|
20
|
+
|
21
|
+
If you planning to use a different `details_name` for the relationship, you will need to change the names of the database columns to have the appropriate `id` and `type` columns. For example, if you wanted to use `:address_details` as the `details_name`, you would do this.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
class AddCanBeDetailsToAddresses < ActiveRecord::Migration
|
25
|
+
def change
|
26
|
+
add_column :addresses, :address_details_id, :integer
|
27
|
+
add_column :addresses, :address_details_type, :string
|
28
|
+
add_index :addresses, [:address_details_id, :address_details_type]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
**NOTE:** Examples of the database migrations can be found in the [`spec/support/schema.rb`](https://github.com/mstarkman/can_be/blob/master/spec/support/schema.rb) file.
|
34
|
+
|
35
|
+
## Models ##
|
36
|
+
|
37
|
+
In order to wire up a model to be a CanBe details model, you will need to call the `can_be_detail` method on that model.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
class HomeAddressDetail < ActiveRecord::Base
|
41
|
+
can_be_detail :address
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
The `can_be_detail` method takes in one parameter. The parameter is the link to the CanBe model. This must be a symbol that will reference the CanBe model. In order to create the proper symbol, you can execute the following into your Rails console: `<ModelName>.name.underscore.to_sym`. Here is an example: `Address.name.underscore.to_sym`. In the above example, this will be used for the `Address` CanBe model.
|
46
|
+
|
47
|
+
You will also need to call the `add_details_model` method in the `can_be` block, passing in the CanBe type and a symbol that represets the details model class.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
class Address < ActiveRecord::Base
|
51
|
+
can_be :home_address, :work_address, :vacation_address do
|
52
|
+
add_details_model :home_address, :home_address_detail
|
53
|
+
end
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
If you are using a different `details_name` for the relationship, you will also need to add the configuration options like this.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
class Address < ActiveRecord::Base
|
61
|
+
can_be :home_address, :work_address, :vacation_address do
|
62
|
+
add_details_model :home_address, :home_address_detail
|
63
|
+
details_name :address_details
|
64
|
+
end
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class HomeAddressDetail < ActiveRecord::Base
|
70
|
+
can_be_detail :address, :address_details
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
**NOTE:** Examples of the model configurations can be found in the [`spec/support/models.rb`](https://github.com/mstarkman/can_be/blob/master/spec/support/models.rb) file.
|
75
|
+
|
76
|
+
## Accessing the Details
|
77
|
+
|
78
|
+
If you want to access the details model, you can call the `details` method on your instance and the instance of your model will be returned. If the type of model that you are using does not have a details model, `nil` will be returned.
|
79
|
+
|
80
|
+
When you persist your CanBe model to the database, your details model will automatically be persisted.
|
81
|
+
|
82
|
+
If you are using a different `details_name`, you will access the details by calling a method of the same name. For example, if you assigned `:address_details` to the `details_name, then you can access the details by calling the `address_details` method.
|
83
|
+
|
84
|
+
## Calling the "change_to" methods
|
85
|
+
|
86
|
+
When you are changing the type of record the details record will be changed to the correct CanBe details record. New records will only be persisted to the database when the CanBe model is persisted. If you change the CanBe model to a type that does not have a corresponding details model, `nil` will be stored for the details.
|
87
|
+
|
88
|
+
Changing the CanBe type with the "change_to" methods can also accept a block to allow you to set the data on the new details record.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
upload.change_to_image_upload do |details|
|
92
|
+
details.format = "jpeg"
|
93
|
+
end
|
94
|
+
```
|
data/docs/history.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Keeping Details History When Changing CanBe Types #
|
2
|
+
|
3
|
+
CanBe provides a history facility that will allow the [details](https://github.com/mstarkman/can_be/blob/master/docs/details.md) data to be preserved when switching between CanBe types. This way if you switch back to a CanBe type that was previously used, the specific data for the new CanBe type will still be available.
|
4
|
+
|
5
|
+
## Database Migrations ##
|
6
|
+
|
7
|
+
To implement this history facility, there are no modifications necessary to your existing CanBe tables. You will only need to create a table (via migration) that will store the references for the CanBe types. All of the attribute (column) names **must** be named as shown in the example below.
|
8
|
+
|
9
|
+
``` ruby
|
10
|
+
create_table :address_can_be_histories, :force => true do |t|
|
11
|
+
t.integer :can_be_model_id
|
12
|
+
t.string :can_be_type
|
13
|
+
t.integer :can_be_details_id
|
14
|
+
t.string :can_be_details_type
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
**NOTE:** Examples of the database migrations can be found in the [`spec/support/schema.rb`](https://github.com/mstarkman/can_be/blob/master/spec/support/schema.rb) file.
|
20
|
+
|
21
|
+
## Models ##
|
22
|
+
|
23
|
+
There are only a few changes that are required to wire up the history model to the CanBe and CanBe details models.
|
24
|
+
|
25
|
+
First, you must create an Active Record model for the history table.
|
26
|
+
|
27
|
+
``` ruby
|
28
|
+
class AddressHistory < ActiveRecord::Base
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
### CanBe Model ###
|
33
|
+
|
34
|
+
You will have to tell your current CanBe model to use the history model that you defined by adding a call to the `#keep_history_in` method.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
class Address < ActiveRecord::Base
|
38
|
+
can_be :home_address, :work_address, :vacation_address do
|
39
|
+
add_details_model :home_address, :home_address_detail
|
40
|
+
keep_history_in :address_history
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
### CanBe Details Models ###
|
46
|
+
|
47
|
+
For each of the details models, you will also have to pass in the history model when calling the `#can_be_detail` method.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
class HomeAddressDetail < ActiveRecord::Base
|
51
|
+
can_be_detail :address, history_model: :address_history
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
**NOTE:** If you also want to change the `details_name` for the CanBe model, you will also need to specify that in the `options` parameter of the `#can_be_detail` method call.
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class HomeAddressDetail < ActiveRecord::Base
|
59
|
+
can_be_detail :address, history_model: :address_history, details_name: :address_details
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
## Calling the "change_to" methods ##
|
64
|
+
|
65
|
+
When you are not storing history for a CanBe model and you call a "change_to" method, the details record that is no longer active will be destroyed. However, when you are storing the history, that record will *not* be destroy by default.
|
66
|
+
|
67
|
+
The "change_to" methods can now take in a parameter that, when set to `true`, will destroy the details record that is no longer active.
|
68
|
+
|
69
|
+
## Access the CanBe model from an inactive details model ##
|
70
|
+
|
71
|
+
You can access the CanBe model from any details model that is in the database. This is done in the same way as accessing it from the active details model.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Custom RSpec Matchers
|
2
|
+
|
3
|
+
Included in this gem are a set of matchers for RSpec that can be used to ensure the `can_be` and `can_be_detail` configuration in your models. To use these matchers, you will need to include this line in your `spec_helper.rb` file.
|
4
|
+
|
5
|
+
`require 'can_be/rspec/matchers'`
|
6
|
+
|
7
|
+
You can then use the `implement_can_be` matcher as follows. There are a number of fluent methods that you can use as well. These methods can be seen in the [`spec/can_be/rspec/matchers/can_be_matcher_spec.rb`](https://github.com/mstarkman/can_be/blob/master/spec/can_be/rspec/matchers/can_be_matcher_spec.rb) file.
|
8
|
+
|
9
|
+
`Address.should implement_can_be(:home_address, :work_address, :vacation_address)`
|
10
|
+
|
11
|
+
Examples of the `implement_can_be_detail` matcher can be found in the [`spec/can_be/rspec/matchers/can_be_detail_matcher_spec.rb`](https://github.com/mstarkman/can_be/blob/master/spec/can_be/rspec/matchers/can_be_detail_matcher_spec.rb) file.
|
@@ -15,6 +15,7 @@ module CanBe
|
|
15
15
|
define_class_methods
|
16
16
|
define_validations
|
17
17
|
define_details
|
18
|
+
define_history
|
18
19
|
end
|
19
20
|
|
20
21
|
private
|
@@ -47,12 +48,12 @@ module CanBe
|
|
47
48
|
can_be_processor.boolean_eval(t)
|
48
49
|
end
|
49
50
|
|
50
|
-
define_method "change_to_#{t}" do
|
51
|
-
can_be_processor.update_field(t)
|
51
|
+
define_method "change_to_#{t}" do |force_history_removal = false, &block|
|
52
|
+
can_be_processor.update_field(t, force_history_removal: force_history_removal, &block)
|
52
53
|
end
|
53
54
|
|
54
|
-
define_method "change_to_#{t}!" do
|
55
|
-
can_be_processor.update_field(t, true)
|
55
|
+
define_method "change_to_#{t}!" do |force_history_removal = false, &block|
|
56
|
+
can_be_processor.update_field(t, save: true, force_history_removal: force_history_removal, &block)
|
56
57
|
end
|
57
58
|
end
|
58
59
|
end
|
@@ -94,11 +95,29 @@ module CanBe
|
|
94
95
|
|
95
96
|
def define_details
|
96
97
|
@klass.class_eval do
|
97
|
-
belongs_to
|
98
|
+
belongs_to self.can_be_config.details_name.to_sym, polymorphic: true, autosave: true, dependent: :destroy
|
98
99
|
|
99
100
|
after_initialize do |model|
|
100
101
|
model.can_be_processor.initialize_details
|
101
102
|
end
|
103
|
+
|
104
|
+
after_save do |model|
|
105
|
+
model.can_be_processor.clean_details
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def define_history
|
111
|
+
return unless @klass.can_be_config.keeps_history?
|
112
|
+
|
113
|
+
@klass.class_eval do
|
114
|
+
after_save do |model|
|
115
|
+
model.can_be_processor.save_history
|
116
|
+
end
|
117
|
+
|
118
|
+
after_destroy do |model|
|
119
|
+
model.can_be_processor.destroy_histories
|
120
|
+
end
|
102
121
|
end
|
103
122
|
end
|
104
123
|
end
|