Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 370 lines (270 sloc) 15.255 kB
1ac6a8c @mig-hub Introduction paragraph
authored
1 CRUSHYFORM
2 ==========
3
e56100f @mig-hub More futile info on the README
authored
4 Every toolkit has a screwdriver and this one is a cruciform.
5
1ac6a8c @mig-hub Introduction paragraph
authored
6 Crushyform is a Sequel plugin that helps building forms.
7 It basically does them for you so that you can forget about the boring part.
8 The kind of thing which is good to have in your toolbox for building a CMS.
9
11917be @mig-hub Work on documentation
authored
10 We tried to make it as modular as possible but with sensible default values.
11
12 I am also aware that this documentation is new and might lack some crucial information
13 but feel free to drop me a line if you have any question.
14
e56100f @mig-hub More futile info on the README
authored
15 By the way, I'd like to thank [Jeremy Evans](https://github.com/jeremyevans) for answering so many questions on the #sequel IRC channel.
16
11917be @mig-hub Work on documentation
authored
17 HOW TO INSTALL ?
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
18 ================
11917be @mig-hub Work on documentation
authored
19
20 Crushyform is a Ruby Gem so you can install it with:
21
22 sudo gem install sequel-crushyform
23
24 HOW TO USE ? (THE BASICS)
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
25 =========================
11917be @mig-hub Work on documentation
authored
26
27 Crushyform is also a Sequel plugin so you can add the crushyform methods to all your models with:
28
29 ::Sequel::Model.plugin :crushyform
30
31 Or you can just add it to one model that way:
32
33 class BlogPost < ::Sequel::Model
34 plugin :crushyform
35 # More useful code from you
36 end
37
38 Once you have it, that is when the magic begins.
39 You already can have a form for it:
40
41 BlogPost.new.crushyform # Returns a nice form
42
43 This will return a form for your new model. Without any effort.
44 If you try with an existing entry, it works as well (wow!).
45 If you try with an entry that is not valid, error messages are incorporated (even more wow!).
46
47 Obviously you have a bit more control on that.
48 To start with, this method have arguments which are:
49
50 - List of columns (all of them by default)
51 - Action URL (when nil, which is the default option, the fields are not wrapped in a form tag)
52 - HTTP Method (POST by default)
53
54 So you can do that:
55
56 BlogPost.new.crushyform( [:title,:body], "/new_blog", "GET" ) # Returns a nice form
57
58 Which will return a form (wrapped this time) with only the 2 fields :title and :body.
59 Options give the action URL and method.
60
61 Now say you want to have all the default options, but you want a wrapping form tag, you can do that:
62
e2e26c5 @mig-hub Crushyform method guesses the enctype + switch to 0.0.5
authored
63 BlogPost.new.crushyform( BlogPost.crushyform_schema.keys, "/new_blog" ) # Returns a nice form (a crushy form to be precise)
11917be @mig-hub Work on documentation
authored
64
e2e26c5 @mig-hub Crushyform method guesses the enctype + switch to 0.0.5
authored
65 You have to put the default value `Model.crushyform_schema.keys` because in the order of priority, the list of columns is more important
11917be @mig-hub Work on documentation
authored
66
67 This is due to the fact that in a real case scenario we are more likely to use the version without a wrapping form tag.
68 Mainly because we want to add some other hidden inputs like a destination, a method override in order to generate a PUT request or a pseudo XHR value.
69
70 Another reason might be that you want to add other fields to the tag.
e2e26c5 @mig-hub Crushyform method guesses the enctype + switch to 0.0.5
authored
71 The default tag is pretty basic.
11917be @mig-hub Work on documentation
authored
72
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
73 CSS CLASSES
74 ===========
75
76 Here is the list of CSS classes used in order to style the forms.
77 That should be enough, drop me a line if you feel something is missing.
78
79 - crushyfield-required is the class for the default required flag
80 - crushyfield is used on the wrapping paragraph tag of every fields
81 - crushyfield-error is used on the wrapping paragraph tag of a field containing errors
82 - crushyfield-error-list is on the span that wraps the list of errors (is just a span, not an html list though)
83
11917be @mig-hub Work on documentation
authored
84 THE CRUSHYFIELDS
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
85 ================
11917be @mig-hub Work on documentation
authored
86
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
87 As mentioned before, the form is more like a way to gather all the fields we're interested to have in a form.
11917be @mig-hub Work on documentation
authored
88 Which means you can have more control than that.
89 You can have just one field at a time.
90 In order to do that, you have 2 methods:
91
92 - Model#crushyinput(column,options) which only gives you the input tag for the field
93 - Model#crushyfield(column,options) which does the same but wrapped in a paragraph tag with a label and an error list
94
95 Regarding the options, you have plenty of them.
96 We'll see later how we can set all of them in the crushyform schema but they all can be overriden when requesting the input tag.
97 Here is the list of schema-related options:
c7623a0 @mig-hub First commit - bases of crushyform schema
authored
98
f086f7b @mig-hub First crushyform_type instoring strategy
authored
99 - :type is the crushyform type that is used for the field (default is :string)
100 - :input_name is the name used for the input tag (default is model[columnname])
101 - :input_value is the input value used for the input tag
102 - :input_type is the input type used for the input tag (default is text when applicable)
103 - :input_class is the class value used for the input tag
b6b65d4 @mig-hub Documentation
authored
104 - :html_escape has to be set to false if you do not want the value to be escaped (default is true)
11917be @mig-hub Work on documentation
authored
105 - :required text that says that the field is required (default is just blank). A ready-made value for that field is also available if you put `true` instead of a text. It is an asterisk with span class `crushyfield_required`
106
107 As you can see, a lot of things can be overriden at the last level.
108 There is another option just for Model#crushyfield that is called :name.
109 This is basically the name of the field in the label tag.
110 By default, this is the name of the column in a human readable way, which means
111 there are no underscore signs and foreign keys like :author_id will have the name: Author.
112
113 Here is an example:
114
115 BlogPost[4].crushyfield( :title , { :name => "Enter Title", :required => true })
116
117 This will give you a full field for the column :title with a label saying "Enter Title" and an asterisk that says the field is required.
118 As mentioned before the :required can be the text to put, but for consistency, it is recommanded to wrap it in the same span with the class crushyfield-required.
119 So if you want to simply write required:
120
121 <span class='crushyfield-required'> required</span>
122
123 But really this is good only if the text is different for that specific field.
124 You usually want to override the class method Model::crushyfield_required.
125 The default implementation is:
126
127 def self.crushyfield_required
128 "<span class='crushyfield-required'> *</span>"
129 end
02019cb @mig-hub Date formating
authored
130
34bb875 @mig-hub Documentation
authored
131 TYPES OF FIELD
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
132 ==============
34bb875 @mig-hub Documentation
authored
133
134 - :string is the default one so it is used when the field is :string type or anyone that is not in the list like :integer for instance
135 - :none returns a blank string
136 - :boolean
137 - :text
138 - :date is in the format YYYY-MM-DD because it is accepted by sequel setters as-is
139 - :time is in the format HH:MM:SS because it is accepted by sequel setters as-is
140 - :datetime is in the format YYYY-MM-DD HH:MM:SS because it is accepted by sequel setters as-is
141 - :parent is a dropdown list to chose from
11917be @mig-hub Work on documentation
authored
142 - :attachment is for attachments (who guessed?).
5184d31 @mig-hub Add :select type
authored
143 - :select could be used for fields like String or Fixnum but giving a limited number of options
11917be @mig-hub Work on documentation
authored
144
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
145 MORE ABOUT DATE/TIME FIELDS
146 ---------------------------
147
11917be @mig-hub Work on documentation
authored
148 As you can see date/time/datetime field is a text input with a format specified on the side.
149 We used to deal with it differently in the past, but nowadays this is the kind of field that is better to keep basic and offer a better interface with javascript.
150 Better to give it a special :input_class through the options and make it a nice javascript date picker
151 instead of trying to complicate something that is gonna be ugly at the end anyway.
152
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
153 Also if you want to use a proper time field (just time with no date), don't forget to declare it all lowercase in your schema.
154 Otherwise it will use the Time ruby class which is a time including the date:
155
4371383 @mig-hub Fix identation on a piece of code in README
authored
156 set_schema do
157 primary_key :id
158 Time :opening_hour # type is :datetime
159 time :opening_hour # type is :time
160 end
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
161
f53cdee @mig-hub Switch to 0.0.2
authored
162 I wish I could use HTML5 date/time fields, but they are not implemented in many browsers yet, and
163 it does not allow to ask for a specific format, which is a not really nice.
164
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
165 MORE ABOUT ATTACHMENT FIELD
166 ---------------------------
167
11917be @mig-hub Work on documentation
authored
168 Regarding the :attachment type, it should be able to work with any kind of system.
169 We made it simple and customizable enough to adapt to many attachment solutions.
c85de9d @mig-hub Fix typo in README
authored
170 I called it :attachment because I never really use blobs, but it might be used with blobs as well.
11917be @mig-hub Work on documentation
authored
171 Once again because it is very basic.
172
173 This is typically the kind of field that cannot really be guessed by crushyform.
174 So you have to declare it as an :attachment.
175 We see how it is done in the following chapter.
176
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
177 Also when it can, crushyform tries to put a thumbnail of the attachment, above the file input when possible.
178 It is done with an instance method that can be overriden by you: Model#to_thumb( column ).
179 By default, it does the right job if you're using another Gem we've done called [Stash-Magic](https://github.com/mig-hub/stash_magic) .
180 Otherwise crushyform assumes that the column contains the relative URL of an image.
181
182 MORE ABOUT PARENT FIELDS
183 ------------------------
184
185 The :parent field type is quite straight foreward and there is not much to say in order to be able to use it.
186 It is interesting to see how it works though.
187 You have a dropdown with all parents name instead of just a crude ID number.
188 One interesting thing is that this dropdown is available for you to use for an Ajax update or whatever:
189
190 Author.to_dropdown( 3, "Choose your Author" )
191
192 Both options are optional. The first one is the ID of the author that is selected (default is `nil`).
193 And the second option is the text for the nil option (default is "** UNDEFINED **").
194
195 This dropdown is cached in `Model::dropdown_cache` and is automatically reseted when you create, update or destroy an entry.
196 Alternatively, you can do it with `Model::reset_dropdown_cache`.
197
198 Another interesting thing is the way crushyform comes up with names.
199 You rarely would have to do anything because it maintains an ordered list of columns that are appropriate for a name.
200 The current list is in a constant:
201
202 LABEL_COLUMNS = [:title, :label, :fullname, :full_name, :surname, :lastname, :last_name, :name, :firstname, :first_name, :caption, :reference, :file_name, :body]
203
204 In the worst case scenario, if it cannot find a column, crushyform will call it with the class name followed by the ID number.
205
206 Alternatively, you can specify your own column:
207
208 Author.label_column = :my_label_column
209
210 Or you can override the final instance method `Model::to_label`:
211
212 def to_label
213 self.my_label_column
214 end
215
5be81a6 @mig-hub Fix typos in README
authored
216 The good thing is that this method is very useful in many places of CMS of your application, and even the front end:
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
217
218 @author.to_label
219
220 It could even work with addresses.
221 Crushyform turns a multi-line text in a one liner if it is the label column.
222
5be81a6 @mig-hub Fix typos in README
authored
223 # Say the class Address has a column called :body which is the last choice for a label in LABEL_COLUMNS
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
224 #
225 # 4, Virginia Street
226 # Flat C
227
228 @address.to_label # => 4, Virginia Street Flat C
229
230 You get the idea.
231
5184d31 @mig-hub Add :select type
authored
232 MORE ABOUT SELECT FIELDS
233 ========================
234
235 This basically the kind of field you want when you have a text field but people are limited to a dropdown list of options.
236 Parent field could be in that category in fact. That is a Fixnum, but limited to available foreign keys.
237 Another example would be a list like your Favourite editor in a list:
238
239 - Emacs
240 - Vi
241 - Ed
242 - Sam
243 - Other
244
245 To achieve that, you can set something like that:
246
247 class Profile < ::Sequel::Model
248 plugin :schema
249 set_schema do
250 primary_key :id
251 String :fave_editor, :crushyform=>{ :type=>:select, :select_options=>['Emacs', 'Vi', 'Ed', 'Sam', 'Other'] }
252 end
253 end
254
255 This will create an appropriate dropdown instead of textfield. But the value is also what people see.
256 Maybe you want to display the name of an editor, but what you want to record is a score from 0 to 10.
257 This is not necessarily an integer as the purpose is just to show you how you make a dropdown with values different from what is displayed:
258
259 class Profile < ::Sequel::Model
260 plugin :schema
261 set_schema do
262 primary_key :id
263 Fixnum :how_much_you_worth, :crushyform=>{ :type=>:select, :select_options=>[['Emacs',5], ['Vi',5], ['Ed',10], ['Sam',9], ['Other', 0]] }
264 end
265 end
266
267 You simply put a key/value Array instead of the bare value. Pretty straight forward.
268 And you can also provide the name of an instance method instead as you might want an Array with dynamic content:
269
270 class Profile < ::Sequel::Model
271 plugin :schema
272 set_schema do
273 primary_key :id
274 String :hero, :crushyform=>{ :type=>:select, :select_options=> :draw_me_a_list }
275 end
276 def draw_me_a_list
277 # Produce an Array dynamically
278 end
279 end
280
281 That's all.
282
11917be @mig-hub Work on documentation
authored
283 CRUSHYFORM SCHEMA
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
284 =================
11917be @mig-hub Work on documentation
authored
285
286 So now some people might think that this is weird that you have to put the options each time you ask for a field.
287 Well, the good news is that you don't.
288 Most of the options on Model#crushyfield are just for specific cases where you want to override/force something.
289 Instead you have a crushyform_schema:
290
291 BlogPost.crushyform_schema
292 # returns something like:
293 # {
294 # :title => { :type => :string },
295 # :body => { :type => :text },
296 # :created_on => { :type => :date },
297 # :picture => { :type => :string }
298 # }
299
300 As you can see, it is already filled for you with the bare minimum.
301 Unfortunately the picture is a string, but a string that is really an image URL.
302 You can fix that with:
303
304 BlogPost.crushyform_schema[:picture].update({ :type => :attachment })
305
306 Alright now when you ask for the form or just the :picture field, it is gonna be an file upload field.
307 But you also want the :title to be displayed as a mandatory field:
308
309 BlogPost.crushyform_schema[:title].update({ :required => true })
310
311 You get the idea.
312
313 But there is even a better way if you use the :schema plugin at the same time.
314 You can add an option called :crushyform for each column.
315 For instance, in order to do the same thing as before:
316
317 class BlogPost < ::Sequel::Model
318 plugin :schema
319 plugin :crushyform
320 set_schema do
321 primary_key :id
322 String :title, :crushyform => {:required => true}
323 text :body
324 Date :created_on
325 String :picture, :crushyform => {:type => :attachment}
326 end
327 create_table unless table_exists?
328 end
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
329
330 CUSTOM TYPE OF FIELD
331 ====================
34bb875 @mig-hub Documentation
authored
332
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
333 You can obviously create a type of field that is not implemented in crushyform.
334 If this is a useful one, it is probably better to fork the project on Github and send me a pull request.
335 That way, you'll help crushyform being more interesting.
02019cb @mig-hub Date formating
authored
336
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
337 Otherwise, the list of types is a Hash. Key is the name, and the value is a Proc with a couple of arguments.
338 A dummy example could be:
02019cb @mig-hub Date formating
authored
339
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
340 Author.crushyform_types.update({
341 :dummy_type => proc do |instance, column_name, options|
342 "<p>You cannot change column: #{column_name}</p>"
343 end
344 })
e7b2d60 @mig-hub Work on field wrapper and form wrapper
authored
345
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
346 So it returns a string.
347 Pretty simple.
e7b2d60 @mig-hub Work on field wrapper and form wrapper
authored
348
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
349 CHANGE LOG
350 ==========
351
352 0.0.1 First version
f53cdee @mig-hub Switch to 0.0.2
authored
353 0.0.2 Use HTML5 attribute `required`
6c0f0cb @mig-hub Fix a bug on the default value for label :name and switch to 0.0.3
authored
354 0.0.3 Fix a bug on the default value for label :name
8d39efc @mig-hub Fix type :none and switch to 0.0.4
authored
355 0.0.4 Fix type `:none`
e2e26c5 @mig-hub Crushyform method guesses the enctype + switch to 0.0.5
authored
356 0.0.5 Crushyform method guesses the enctype
c6a8433 @mig-hub Human name for classes and label for new records
authored
357 0.0.6 Human name for classes and label for new records
0032667 @mig-hub Fix Model#to_label
authored
358 0.0.7 Fix `Model#to_label`
4d95cfc @mig-hub Fix bug with apostrophes
authored
359 0.0.8 Fix bug with apostrophe in text fields
78076af @mig-hub Make :parent type overridable through set_schema and switch to 0.1.0
authored
360 0.1.0 Add `:select` type and make `:parent` type overridable through `set_schema`
6a423fb @mig-hub Use strftime fordate/time (do not know why I did not !!!)
authored
361 0.1.1 Use strftime fordate/time (do not know why I did not !!!)
ec7d7e1 @mig-hub Prevent text areas instead of text fields with postgres
authored
362 0.1.2 Monkey patch, just prevent to have text areas instead of text fields when using PostgreSQL
fa3deef @mig-hub Still use the @schema value for :text type when :schema plugin is used
authored
363 0.1.3 Still use the @schema value for :text type when :schema plugin is used
c717df8 @mig-hub Do not raise when there is a mismatch between db_schema and schema
authored
364 0.1.4 Do not raise when there is a mismatch between db_schema and schema
b2c9895 @mig-hub More Documentation before releasing the first Gem
authored
365
366 COPYRIGHT
367 =========
11917be @mig-hub Work on documentation
authored
368
5be81a6 @mig-hub Fix typos in README
authored
369 (c) 2011 Mickael Riga - see file LICENSE for details
Something went wrong with that request. Please try again.