forked from drnic/dr-nic-magic-models
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathREADME.txt
294 lines (217 loc) · 8.78 KB
/
README.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
See http://magicmodels.rubyforge.org/dr_nic_magic_models for pretty README
Ugly README (from website/index.txt in Textile format):
h1. Dr Nic's Magic Models
If you've used Ruby on Rails you'll have written at least one model class like this:
<pre syntax='ruby'>
class Person < ActiveRecord::Base
has_many :memberships
has_many :groups, :through => :memberships
belongs_to :family
validates_presence_of :firstname, :lastname, :email
end
</pre>
A few minutes later you'll have wondered to yourself,
<blockquote>
Why do I have write my own <code>has_many</code>, <code>belongs_to</code>, and <code>validates_presence_of</code>
commands if all the data is in the database schema?
</blockquote>
Now, for the very first time, your classes can look like this:
<pre syntax='ruby'>
class Person < ActiveRecord::Base
end
</pre>
or, if you are lazy...
<pre syntax='ruby'>
class Person < ActiveRecord::Base; end
</pre>
or, if you read right to the end of this page, this...
<pre syntax='ruby'>
# Go fish.
</pre>
Magic and mystery abound. All for you. Impress your friends, amaze your mother.
NOTE: The gratuitous use of *Dr Nic's* in the name should only enhance the mystical magikery,
for magic needs a magician; and I love magic. I always wanted to create my own magic trick.
So I shall be the magician for the sake of magic itself. I look a bit like Harry Potter too,
if Harry were 32 and better dressed.
h2. Installation
To install the Dr Nic's Magic Models gem you can run the following command to
fetch the gem remotely from RubyForge:
<pre>
gem install dr_nic_magic_models
</pre>
or "download the gem manually":http://rubyforge.org/projects/magicmodels and
run the above command in the download directory.
Now you need to <code>require</code> the gem into your Ruby/Rails app. Insert the following
line into your script (use <code>config/environment.rb</code> for your Rails apps):
<pre>
require 'dr_nic_magic_models'
</pre>
Your application is now blessed with magical mystery.
h2. David Copperfield eat your Ruby-crusted heart out
Let's demonstrate the magical mystery in all its full-stage glory. Create a Ruby on Rails app (example uses sqlite3, but use your favourite databas):
<pre syntax="ruby">
rails magic_show -d sqlite3
cd magic_show
ruby script/generate model Person
ruby script/generate model Group
ruby script/generate model Membership
</pre>
Update the migration <code>001_create_people.rb</code> with:
<pre syntax="ruby">
class CreatePeople < ActiveRecord::Migration
def self.up
create_table :people do |t|
t.column :firstname, :string, :null => false
t.column :lastname, :string, :null => false
t.column :email, :string, :null => false
end
end
def self.down
drop_table :people
end
end
</pre>
Similarly, update the <code>def self.up</code> method of <code>002_create_groups.rb</code>
with:
<pre syntax="ruby">
create_table :groups do |t|
t.column :name, :string, :null => false
t.column :description, :string
end
</pre>
and <code>003_create_memberships.rb</code> with:
<pre syntax="ruby">
create_table :memberships do |t|
t.column :person_id, :integer, :null => false
t.column :group_id, :integer, :null => false
end
</pre>
And run your migrations to create the three tables:
<pre>
rake db:migrate
</pre>
h3. And now for some "woofle dust":http://en.wikipedia.org/wiki/List_of_conjuring_terms ...
At the end of <code>config/environment.rb</code> add the following line:
<pre>
require 'dr_nic_magic_models'
</pre>
Now, let's do a magic trick. First, let's check our model classes (<code>app/models/person.rb</code> etc):
<pre syntax="ruby">
class Person < ActiveRecord::Base
end
class Group < ActiveRecord::Base
end
class Membership < ActiveRecord::Base
end
</pre>
Nothing suspicious here. We have no validations and no associations. Just some plain old model classes.
UPDATE: To turn on magic validations, you now need to invoke <code>generate_validations</code> on defined classes. So, update your model classes:
<pre syntax="ruby">
class Person < ActiveRecord::Base
generate_validations
end
class Group < ActiveRecord::Base
generate_validations
end
class Membership < ActiveRecord::Base
generate_validations
end
</pre>
For this trick, we'll need an ordinary console session. Any old one lying around the house will do.
<pre>
ruby script/console
</pre>
Now a normal model class is valid until you explicitly add <code>validates_xxx</code> commands.
With Dr Nic's Magic Models:
<pre syntax="ruby">
person = Person.new
=> #<Person:0x393e0f8 @attributes={"lastname"=>"", "firstname"=>"", "email"=>""}, @new_record=true>
person.valid?
=> false
person.errors
=> #<ActiveRecord::Errors:0x3537b38 @errors={
"firstname"=>["can't be blank", "is too long (maximum is 255 characters)"],
"lastname"=>["can't be blank", "is too long (maximum is 255 characters)"],
"email"=>["can't be blank", "is too long (maximum is 255 characters)"]},
@base=#<Person:0x3538bf0 @errors=#<ActiveRecord::Errors:0x3537b38 ...>, @new_record=true,
@attributes={"lastname"=>nil, "firstname"=>nil, "email"=>nil}>>
</pre>
*Kapoow!* Instant validation! (NOTE: not as instant as it used to be - remember - you need to call <code>generate_validations</code> on each class as required)
Because you specified the three columns as <code>:null => false</code>,
your ActiveRecord models will now automagically generated <code>validates_presence_of</code>
for each non-null field, plus several other validations (since version 0.8.0).
Ok, we're just warming up.
Your models normally require association commands (<code>has_many</code>, <code>belongs_to</code>, etc, as
demonstrated above) to have the brilliantly simple support that Rails/ActiveRecords are known for.
Let's just watch what Dr Nic's Magic Models can do without any effort at all...
<pre syntax="ruby">
person = Person.create(:firstname => "Nic", :lastname => "Williams", :email => "[email protected]")
group = Group.create(:name => "Magic Models Forum", :description => "http://groups.google.com/magicmodels")
membership = Membership.create(:person => person, :group => group)
person.memberships.length
=> 1
membership.person
=> <Person:0x38898e8 @attributes={"lastname"=>"Williams", "firstname"=>"Nic",
"id"=>"1", "email"=>"[email protected]"}>
group.memberships
=> [<Membership:0x3c8cd70 @attributes={"group_id"=>"1", "id"=>"1", "person_id"=>"1"}>]
</pre>
The final association trick is a ripper. Automatic generation of <code>has_many :through</code> associations...
<pre syntax="ruby">
>> person.groups
=> [<Group:0x39047e0 @attributes={"name"=>"Magic Models Forum", "id"=>"1", "description"=>nil}>]
>> group.people
=> [<Person:0x3c33580 @attributes={"lastname"=>"Williams", "firstname"=>"Nic",
"id"=>"1", "email"=>"[email protected]"}>]
</pre>
h3. Drum roll...
Ladies and gentlemen. For my final feat of magical mastery, I'll ask you to do
something you've never done before. This illusion is akin to the "floating lady":http://www.toytent.com/Posters/985.html
illusion that has been passed down through generations of magicians.
Exit your console session.
DELETE your three model classes: <code>person.rb, group.rb, and membership.rb</code> from the
<code>app/models</code> folder. (You can always get them back via the model generator... be fearless!)
<pre>rm app/models/*.rb</pre>
Re-launch your console.
*drums are still rolling...*
Be prepared to applaud loudly...
<pre syntax="ruby">
>> Person
=> Person
</pre>
You applaud loudly, but watch for more...
<pre syntax="ruby">
>> Person.new.valid?
=> false
>> person = Person.find(1)
=> <Person:0x3958930 @attributes={"lastname"=>"Williams", "firstname"=>"Nic",
"id"=>"1", "email"=>"[email protected]"}>
>> person.valid?
=> true
>> person.memberships
=> [<Membership:0x393a000 @attributes={"group_id"=>"1", "id"=>"1", "person_id"=>"1"}>]
>> person.groups
=> [<Group:0x390df60 @attributes={"name"=>"Magic Models Forum", "id"=>"1", "description"=>nil}>]
</pre>
h3. Tada!
The end.
h3. Use modules to scope your magic
Only want to pick up tables starting with <code>blog_</code>?
<pre syntax="ruby">module Blog
magic_module :table_name_prefix => 'blog_'
end
Blog::Post.table_name # => 'blog_posts'
</pre>
h2. Dr Nic's Blog
"http://www.drnicwilliams.com":http://www.drnicwilliams.com - for future announcements and
other stories and things.
h2. Articles about Magic Models
* "Announcement":http://drnicwilliams.com/2006/08/07/ann-dr-nics-magic-models/
* "BTS - Class creation":http://drnicwilliams.com/2006/08/10/bts-magic-models-class-creation/
h2. Forum
"http://groups.google.com/group/magicmodels":http://groups.google.com/group/magicmodels
h2. Licence
This code is free to use under the terms of the MIT licence.
h2. Contact
Comments are welcome. Send an email to "Dr Nic Williams":mailto:[email protected]
or via his blog at "http://www.drnicwilliams.com":http://www.drnicwilliams.com