active_record_schema 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +211 -85
- data/VERSION +1 -1
- data/active_record_schema.gemspec +1 -1
- data/lib/active_record_schema/dsl.rb +4 -10
- metadata +2 -2
data/README.md
CHANGED
@@ -1,66 +1,86 @@
|
|
1
1
|
# ActiveRecordSchema
|
2
2
|
|
3
|
-
|
3
|
+
**ActiveRecordSchema** is an `ActiveRecord` extension that allows you to write database schema for a model within the model itself and to generate migrations directly from models.
|
4
4
|
|
5
5
|
Unlike other libraries (eg. mini_record) ActiveRecordSchema is not an alternative to Rails migrations, but rather a tool to simplify their use.
|
6
6
|
|
7
|
-
|
7
|
+
## Features
|
8
|
+
|
9
|
+
* Defining columns and indexes directly in model
|
10
|
+
* Generation of migration from the model taking into account the current state of the database
|
11
|
+
* Automatically add code to migrate associations:
|
12
|
+
* Foreign key for `belongs_to`
|
13
|
+
* Join table for `has_and_belongs_to_many`
|
14
|
+
|
15
|
+
* Automatic indexing of foreign keys for both `belongs_to` and `has_and_belongs_to_many` (configurable)
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Put this in your Gemfile
|
8
20
|
|
9
21
|
gem 'active_record_schema'
|
10
22
|
|
11
|
-
|
23
|
+
and update your bundle
|
12
24
|
|
13
25
|
bundle install
|
26
|
+
|
27
|
+
**NOTE:** ActiveRecordSchema depends on `rails ~> 3.0` and not only `ActiveRecord`
|
14
28
|
|
15
29
|
## Usage
|
16
30
|
|
17
|
-
Create a model
|
18
|
-
|
19
|
-
class Post < ActiveRecord::Base
|
20
|
-
field :title
|
21
|
-
field :body, :as => :text
|
22
|
-
belongs_to :author, :class_name => "User"
|
23
|
-
end
|
31
|
+
Create a model and use the class method `#field` to define columns
|
24
32
|
|
25
|
-
|
33
|
+
``` rb
|
34
|
+
class Post < ActiveRecord::Base
|
35
|
+
field :title
|
36
|
+
field :body, :as => :text
|
37
|
+
belongs_to :author, :class_name => "User"
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
Now run `rails g migration` with `--from` option
|
26
42
|
|
27
43
|
rails g migration init_posts_schema --from Post
|
28
44
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
45
|
+
and the following migration will be generated
|
46
|
+
|
47
|
+
``` rb
|
48
|
+
class InitPostsSchema < ActiveRecord::Migration
|
49
|
+
def change
|
50
|
+
add_column :posts, :title, :string
|
51
|
+
add_column :posts, :body, :text
|
52
|
+
|
53
|
+
add_column :author_id, :integer
|
54
|
+
index :author_id
|
55
|
+
end
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
Generating a migration for new columns is the same, lets add a new field to `Post` (eg. `pubdate`):
|
60
|
+
|
61
|
+
``` rb
|
62
|
+
class Post < ActiveRecord::Base
|
63
|
+
field :title
|
64
|
+
field :body, :as => :text
|
65
|
+
belongs_to :author, :class_name => "User"
|
44
66
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
belongs_to :author, :class_name => "User"
|
49
|
-
field :pubdate, :as => :datetime
|
50
|
-
end
|
67
|
+
field :pubdate, :as => :datetime
|
68
|
+
end
|
69
|
+
```
|
51
70
|
|
52
|
-
|
71
|
+
Now run
|
53
72
|
|
54
73
|
rails g migration add_pubdate_to_posts --from Post
|
55
74
|
|
56
|
-
|
57
|
-
|
58
|
-
class AddPubdateToPosts < ActiveRecord::Migration
|
59
|
-
def change
|
60
|
-
add_column :posts, :pubdate, :datetime
|
61
|
-
end
|
62
|
-
end
|
75
|
+
that will generate:
|
63
76
|
|
77
|
+
``` rb
|
78
|
+
class AddPubdateToPosts < ActiveRecord::Migration
|
79
|
+
def change
|
80
|
+
add_column :posts, :pubdate, :datetime
|
81
|
+
end
|
82
|
+
end
|
83
|
+
```
|
64
84
|
|
65
85
|
## Has and Belongs To Many (HBTM) associations
|
66
86
|
|
@@ -68,23 +88,26 @@ Lets try to add a HBTM association to our `Post` model
|
|
68
88
|
|
69
89
|
_ex._
|
70
90
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
91
|
+
``` rb
|
92
|
+
# content.rb
|
93
|
+
class Post < ActiveRecord::Base
|
94
|
+
field :title
|
95
|
+
field :body, :as => :text
|
96
|
+
belongs_to :author, :class_name => "User"
|
97
|
+
field :pubdate, :as => :datetime
|
77
98
|
|
78
|
-
|
79
|
-
|
99
|
+
has_and_belongs_to_many :voters, :class_name => "User"
|
100
|
+
end
|
101
|
+
```
|
80
102
|
|
81
103
|
|
82
104
|
Now running
|
83
105
|
|
84
106
|
rails g migration add_voters_to_posts --from Post
|
85
107
|
|
86
|
-
|
108
|
+
will generate:
|
87
109
|
|
110
|
+
``` rb
|
88
111
|
class AddVotersToPosts < ActiveRecord::Migration
|
89
112
|
def change
|
90
113
|
create_table :contents_users, :id => false do |t|
|
@@ -95,38 +118,41 @@ Will generate:
|
|
95
118
|
add_index :contents_users, "user_id"
|
96
119
|
end
|
97
120
|
end
|
121
|
+
```
|
98
122
|
|
99
123
|
## Single Table Inheritance (STI)
|
100
124
|
|
101
|
-
Call `#inheritable` inside the base class of your hierarchy to add the
|
125
|
+
Call `#inheritable` inside the base class of your hierarchy to add the inheritance column required by Single Table Inheritance.
|
102
126
|
|
103
127
|
_ex._
|
104
128
|
|
105
|
-
|
106
|
-
|
107
|
-
|
129
|
+
``` rb
|
130
|
+
# content.rb
|
131
|
+
class Content < ActiveRecord::Base
|
132
|
+
inheritable
|
108
133
|
|
109
|
-
|
134
|
+
field :title
|
110
135
|
|
111
|
-
|
112
|
-
|
136
|
+
has_and_belongs_to_many :voters, :class_name => "User"
|
137
|
+
belongs_to :author, :class_name => "User"
|
113
138
|
|
114
|
-
|
115
|
-
|
139
|
+
timestamps
|
140
|
+
end
|
116
141
|
|
117
142
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
143
|
+
# article.rb
|
144
|
+
class Article < Content
|
145
|
+
field :body, :as => :text
|
146
|
+
end
|
122
147
|
|
123
148
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
149
|
+
# video.rb
|
150
|
+
class Video < Content
|
151
|
+
field :url
|
152
|
+
end
|
153
|
+
```
|
128
154
|
|
129
|
-
|
155
|
+
Running
|
130
156
|
|
131
157
|
rails g migration init_contents --from Content
|
132
158
|
|
@@ -138,27 +164,128 @@ same as
|
|
138
164
|
|
139
165
|
rails g migration init_contents --from Video
|
140
166
|
|
141
|
-
|
167
|
+
will generate the following migration
|
168
|
+
|
169
|
+
``` rb
|
170
|
+
class InitContents < ActiveRecord::Migration
|
171
|
+
def change
|
172
|
+
add_column :contents, :type, :string
|
173
|
+
add_column :contents, :title, :string
|
174
|
+
add_column :contents, :author_id, :string
|
175
|
+
add_column :contents, :body, :text
|
176
|
+
add_column :contents, :url, :string
|
177
|
+
|
178
|
+
add_index :contents, :author_id
|
179
|
+
|
180
|
+
create_table :contents_users, :id => false do |t|
|
181
|
+
t.integer "content_id"
|
182
|
+
t.integer "user_id"
|
183
|
+
end
|
184
|
+
add_index :contents_users, "content_id"
|
185
|
+
add_index :contents_users, "user_id"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
```
|
142
189
|
|
143
|
-
class InitContents < ActiveRecord::Migration
|
144
|
-
def change
|
145
|
-
add_column :contents, :type, :string
|
146
|
-
add_column :contents, :title, :string
|
147
|
-
add_column :contents, :author_id, :string
|
148
|
-
add_column :contents, :body, :text
|
149
|
-
add_column :contents, :url, :string
|
150
190
|
|
151
|
-
|
191
|
+
## Mixins
|
152
192
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
end
|
157
|
-
add_index :contents_users, "content_id"
|
158
|
-
add_index :contents_users, "user_id"
|
159
|
-
end
|
160
|
-
end
|
193
|
+
Probably one of the most significant advantage given by ActiveRecordSchema is to allow the definition of fields in modules and reuse them through mixin
|
194
|
+
|
195
|
+
_ex._
|
161
196
|
|
197
|
+
``` rb
|
198
|
+
module Profile
|
199
|
+
extend ActiveSupport::Concern
|
200
|
+
included do
|
201
|
+
field :name
|
202
|
+
field :age, :as => :integer
|
203
|
+
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class User < ActiveRecord::Base
|
208
|
+
include Profile
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
class Player < ActiveRecord::Base
|
213
|
+
include Profile
|
214
|
+
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
|
219
|
+
## DSL (Domain Specific Language) reference
|
220
|
+
|
221
|
+
* ### `field(name, *args)`
|
222
|
+
|
223
|
+
Adds a new column with name `name` to the schema. The type of column can be passed either as second argument or as option, if not specified is intended to be `:string`
|
224
|
+
|
225
|
+
#### options
|
226
|
+
|
227
|
+
* **:as _or_ :type** : Specify the type of the column. The value can be a `String`, a `Symbol` or a `Class`, default to `:string`
|
228
|
+
* **:index** : Specify wether or not the field should be indexed, default to `false`
|
229
|
+
|
230
|
+
#### examples
|
231
|
+
|
232
|
+
``` rb
|
233
|
+
field :name
|
234
|
+
|
235
|
+
field :name, :string
|
236
|
+
field :name, "string"
|
237
|
+
field :name, String
|
238
|
+
|
239
|
+
field :name, :as => :string
|
240
|
+
field :name, :as => "string"
|
241
|
+
field :name, :as => String
|
242
|
+
|
243
|
+
field :name, :type => :string
|
244
|
+
field :name, :type => "string"
|
245
|
+
field :name, :type => String
|
246
|
+
|
247
|
+
field :age, :as => :integer, :index => true
|
248
|
+
```
|
249
|
+
|
250
|
+
|
251
|
+
* ### `belongs_to(name, options = {})`
|
252
|
+
|
253
|
+
Adds a new foreign key column for the association to the schema and then delegates to `ActiveRecord::Base.belongs_to`. If the association is polimorphic a column for foreign type is also generated.
|
254
|
+
|
255
|
+
#### options
|
256
|
+
|
257
|
+
* **:index** : Specify wether or not the foreing key column should be indexed, default to `true`. If the association is polimorphic creates an index on both foreign key and foreing type
|
258
|
+
|
259
|
+
|
260
|
+
* ### `has_and_belongs_to_many(name, options = {}, &extension)`
|
261
|
+
|
262
|
+
Adds a new join table for the association to the schema and then delegates to `ActiveRecord::Base.has_and_belongs_to_many`
|
263
|
+
|
264
|
+
* ### `index(column_name, options = {})`
|
265
|
+
|
266
|
+
Adds a new index for `column_name` column to the schema
|
267
|
+
|
268
|
+
* ### `timestamps`
|
269
|
+
|
270
|
+
Same as
|
271
|
+
|
272
|
+
``` rb
|
273
|
+
field :created_at, :datetime
|
274
|
+
field :updated_at, :datetime
|
275
|
+
```
|
276
|
+
|
277
|
+
* ### `inheritable`
|
278
|
+
|
279
|
+
Same as
|
280
|
+
|
281
|
+
``` rb
|
282
|
+
field :"#{inheritance_column}"
|
283
|
+
```
|
284
|
+
|
285
|
+
|
286
|
+
## Why do not also generate irreversible changes (change/remove columns or indexes)?
|
287
|
+
|
288
|
+
ActiveRecordSchema does not take into account the removal of columns and indexes or changes in the types of columns. The reason for this is that these changes are not reversible, so it's a better idea to introduce them by hand rather than let them be generated automatically. Anyway the need to resort to harsh measures such as irreversible changes is limited to non-routine situations.
|
162
289
|
|
163
290
|
|
164
291
|
## Contributing to active_record_schema
|
@@ -171,7 +298,6 @@ Will generate the following migration
|
|
171
298
|
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
172
299
|
* 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.
|
173
300
|
|
174
|
-
|
175
301
|
---
|
176
302
|
|
177
303
|
Copyright (c) 2012 mcasimir
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.2
|
@@ -17,7 +17,7 @@ module ActiveRecordSchema
|
|
17
17
|
# field :name, :string, :default => "Joe"
|
18
18
|
def field(name, *args)
|
19
19
|
options = args.extract_options!
|
20
|
-
type =
|
20
|
+
type = options.delete(:as) || options.delete(:type) || args.first || :string
|
21
21
|
type = type.name.underscore.to_sym if (type.class == Class)
|
22
22
|
index = options.delete(:index)
|
23
23
|
|
@@ -27,9 +27,6 @@ module ActiveRecordSchema
|
|
27
27
|
schema.add_index(name)
|
28
28
|
end
|
29
29
|
end
|
30
|
-
alias :key :field
|
31
|
-
alias :property :field
|
32
|
-
alias :col :field
|
33
30
|
|
34
31
|
def belongs_to(name, options = {})
|
35
32
|
options.symbolize_keys!
|
@@ -64,21 +61,18 @@ module ActiveRecordSchema
|
|
64
61
|
super(name, options, &extension)
|
65
62
|
end
|
66
63
|
|
67
|
-
def
|
64
|
+
def index(column_name, options = {})
|
68
65
|
schema.add_index(column_name, options)
|
69
66
|
end
|
70
|
-
alias :index :add_index
|
71
67
|
|
72
|
-
def timestamps
|
68
|
+
def timestamps
|
73
69
|
field :created_at, :datetime
|
74
70
|
field :updated_at, :datetime
|
75
71
|
end
|
76
|
-
alias :timestamps :timestamps!
|
77
72
|
|
78
|
-
def inheritable
|
73
|
+
def inheritable
|
79
74
|
field :"#{inheritance_column}"
|
80
75
|
end
|
81
|
-
alias :inheritable :inheritable!
|
82
76
|
|
83
77
|
end
|
84
78
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -89,7 +89,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
89
|
version: '0'
|
90
90
|
segments:
|
91
91
|
- 0
|
92
|
-
hash: -
|
92
|
+
hash: -4255216891486240966
|
93
93
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|