This repository is private.
All pages are served over SSL and all pushing and pulling is done over SSH.
No one may fork, clone, or view it unless they are added as a member.
Every repository with this icon (
) is private.
Every repository with this icon (
This repository is public.
Anyone may fork, clone, or view it.
Every repository with this icon (
) is public.
Every repository with this icon (
commit 4b52e1516edd21bed7e1e0c0f175b9c642648bae
tree 56c973f7a0522f332ce9226ca17b12c1e0d72160
parent 3ad3dc49b65b70278176d6b4418aff485269a235
tree 56c973f7a0522f332ce9226ca17b12c1e0d72160
parent 3ad3dc49b65b70278176d6b4418aff485269a235
awesome_fields / README.rdoc
| c3b39ff4 » | shadowfiend | 2008-10-19 | 1 | = Awesome Fields | |
| 2 | Awesome fields is a plugin that adds an extension to the built-in Rails | ||||
| 3 | FormBuilder in the form of a new method, <tt>FormBuilder#field</tt>. This method | ||||
| 4 | magically determines what type of field to display for the corresponding method. | ||||
| 5 | It also adds a new form builder, +LinedBuilder+, and related methods, such as | ||||
| 6 | lined_form_for and lined_fields_for. Note that JS-related methods are not | ||||
| 7 | provided, since generally speaking I don't think Rails's JS helpers should be | ||||
| 8 | used (look into a library like LowPro instead). | ||||
| 9 | |||||
| 10 | == Overview of the +field+ method | ||||
| 11 | |||||
| 12 | So let's say you had a model MyModel with a migration that looked oddly like: | ||||
| 13 | create_table(:my_model) do |t| | ||||
| 14 | t.column 'magic', :string | ||||
| 15 | t.column 'number', :integer | ||||
| 16 | t.column 'hyperdate', :date | ||||
| 17 | t.column 'supertime', :time | ||||
| 18 | t.column 'incredidatetime', :datetime | ||||
| 19 | end | ||||
| 20 | |||||
| 21 | Then let's say we did this bit of magic: | ||||
| 22 | <% form_for :model, @model, :action => 'superplace' do |f| %> | ||||
| 23 | <%= f.field :magic %> | ||||
| 24 | <%= f.field :number %> | ||||
| 25 | <%= f.field :hyperdate %> | ||||
| 26 | <%= f.field :supertime %> | ||||
| 27 | <%= f.field :incredidatetime %> | ||||
| 28 | <% end %> | ||||
| 29 | In this situation, you would get two plain text boxes, one date selector, one | ||||
| 30 | time selector, and one datetime selector. | ||||
| 31 | |||||
| 32 | What if the `magic' field was really long (i.e., we generated a column with type | ||||
| 33 | :text instead of :string)? Then we'd probably prefer a textarea. In this | ||||
| 34 | situation, we pass the <tt>:long</tt> option to the +field+ method: | ||||
| 35 | <%= f.field :magic, :long => true %> | ||||
| 36 | Different field types may deal with this option differently, and some may ignore | ||||
| 37 | it entirely. | ||||
| 38 | |||||
| 39 | |||||
| 40 | == Overview of the +LinedBuilder+ | ||||
| 41 | |||||
| 42 | +LinedBuilder+ is a Rails form builder that adds support for labels and pretty | ||||
| 43 | error handling to forms. +LinedBuilder+ wraps each input element created by a | ||||
| 44 | call to a field helper in a div of CSS class +form_line+. It also gives it a | ||||
| 45 | label (by default, this contains the humanized name of the field) and, if an | ||||
| 46 | error exists, it provides a nested div within the +form_line+ of CSS class | ||||
| 47 | +field_error+ and the div's class is changed to | ||||
| 48 | <tt>form_line with_errors</tt>. More details are below. | ||||
| 49 | |||||
| 50 | A short example now. Assume there are three fields for a model -- `number', | ||||
| 51 | `date', and `name'. `name' is blank but should not be, and so has an error on | ||||
| 52 | it. The ERB code: | ||||
| 53 | |||||
| 54 | <% lined_form_for @model do |f| %> | ||||
| 55 | <%= f.field :name %> | ||||
| 56 | <%= f.text_field :number %> | ||||
| 57 | <%= f.field :date %> | ||||
| 58 | <% end %> | ||||
| 59 | |||||
| 60 | Will yield the HTML output: | ||||
| 61 | |||||
| 62 | <form ...> | ||||
| 63 | <div class="form_line with_errors"> | ||||
| 64 | <div class="field_error">Name should not be blank.</div> | ||||
| 65 | <label for="model_name">Name:</label> | ||||
| 66 | <input type="text" name="model[name]" id="model_name" value="" /> | ||||
| 67 | </div> | ||||
| 68 | <div class="form_line"> | ||||
| 69 | <label for="model_number">Number:</label> | ||||
| 70 | <input type="text" name="model[number]" id="model_number" /> | ||||
| 71 | </div> | ||||
| 72 | <div class="form_line"> | ||||
| 73 | <label for="model_date">Date:</label> | ||||
| 74 | <!-- A date selector. --> | ||||
| 75 | </div> | ||||
| 76 | </form> | ||||
| 77 | |||||
| 78 | See the section on +LinedBuilder+ below for more details. | ||||
| 79 | |||||
| 80 | == The +field+ Method | ||||
| 81 | |||||
| 82 | The field method automatically takes care of generating a field of the | ||||
| 83 | appropriate type for you in a form. It even takes care of a lot of the magic of | ||||
| 84 | collection fields. Some details on the inner workings follow. See also the | ||||
| 85 | documentation for the +AwesomeFieldHelpers+ for more information. | ||||
| 86 | |||||
| 87 | === Field Generation | ||||
| 88 | There are two steps to generating the field: first, we determine what type of | ||||
| 89 | field to generate, then we generate the actual HTML for it. | ||||
| 90 | |||||
| 91 | There are two ways we use to find the type of field to generate. First, we run | ||||
| 92 | the method itself and look for what the class of the object returned is. If we | ||||
| 93 | get a nil result from the method, then we use the actual database type as our | ||||
| 94 | determiner. | ||||
| 95 | |||||
| 96 | To generate the actual HTML, we call a helper method. For example, if we had a | ||||
| 97 | string field, then we would call +string_field+. Since there are already methods | ||||
| 98 | for most fields, we simply alias the existing methods to the relevant ones. | ||||
| 99 | Sometimes, the mapping isn't one-to-one. For example, in the case of strings, | ||||
| 100 | sometimes we'll need to make the field a text area and other times just a simple | ||||
| 101 | text field (see the situation where we're using the <tt>:long</tt> option | ||||
| 102 | above). In these cases, we can implement the actual method and have it dispatch | ||||
| 103 | to the relevant helper methods. | ||||
| 104 | |||||
| 105 | What if you want to specialize the behavior in one of your builders? Just | ||||
| 106 | override the relevant methods! Then there's the other situation -- one where | ||||
| 107 | maybe you've serialized an object to the database in YAML form, and you want to | ||||
| 108 | display a field for it. Since the returned value from the method will be of your | ||||
| 109 | class, we may be unable to resolve that class to an actual field type. In this | ||||
| 110 | case, you can either alias in your own helper or implement the relevant method | ||||
| 111 | in your own builder. The pattern of the methods called is simply the class name | ||||
| 112 | underscored (literally, the result of | ||||
| 113 | <tt>@object.send(method).class.underscore</tt>) followed by +_field+. So Strings | ||||
| 114 | go to +string_field+, Dates to +date_field+, and DateTimes to +date_time_field+. | ||||
| 115 | |||||
| 116 | == Collection Fields | ||||
| 117 | Basic fields are all well and good, but it'd be nice to be able to automatically | ||||
| 118 | generate select boxes based on collection fields, too, and have them behave as | ||||
| 807b48c2 » | shadowfiend | 2008-10-19 | 119 | expected. Awesome fields makes this easier to a certain extent, as well. First of | |
| c3b39ff4 » | shadowfiend | 2008-10-19 | 120 | all, if a field returns a value that responds to the +collect+ method, then | |
| 121 | the field is assumed to be a collection field (an exception is made for Strings, | ||||
| 122 | which do respond to +collect+, but are handled as regular text fields). | ||||
| 123 | |||||
| 124 | Then, we use +collection_select+ to generate the appropriate field (actually, we | ||||
| 125 | use +select+, because +collection_select+ doesn't allow us to easily indicate | ||||
| 126 | the multiple objects that should be preselected). By default, the +value_method+ | ||||
| d70c5452 » | Shadowfiend | 2008-11-11 | 127 | used to determine the value for the collection options is +to_param+. If a | |
| c3b39ff4 » | shadowfiend | 2008-10-19 | 128 | +text_method+ is not specified, then the +name+ or +to_s+ methods are used (they | |
| 129 | are attempted in that order). | ||||
| 130 | |||||
| 131 | For +select+, we also need an original collection -- basically, a list of all of | ||||
| 132 | the possible values -- to use with the list of selected values. If the objects | ||||
| 133 | inside the collection are AR objects, then we take their class and issue a | ||||
| f3ecbc2b » | shadowfiend | 2008-10-19 | 134 | <tt>find(:all)</tt> on it. If there are no available objects, then we attempt to | |
| 135 | reflect on the association for the given method to determine the right class. | ||||
| 136 | For example, with this call: | ||||
| c3b39ff4 » | shadowfiend | 2008-10-19 | 137 | ||
| 138 | f.field :collection_method | ||||
| 139 | |||||
| 2ebb2d71 » | shadowfiend | 2008-10-19 | 140 | If +collection_method+ returned a list of Post objects (or a single Post | |
| 141 | object), then we issue a <tt>Post::find(:all)</tt> to determine the full | ||||
| f3ecbc2b » | shadowfiend | 2008-10-19 | 142 | collection (of selected and unselected values). If an empty list is returned, or | |
| 143 | nil, then we look up the association for the object on +collection_method+ and | ||||
| 144 | try to invoke a <tt>find(:all)</tt> on that class. This guessing can be | ||||
| 145 | overridden by passing the <tt>:collection</tt> option with the desired | ||||
| 146 | collection. | ||||
| 2ebb2d71 » | shadowfiend | 2008-10-19 | 147 | ||
| 148 | Note also that the set of selected items (or the single selected item) can be | ||||
| 149 | overridden by providing a collection or object to use instead through the | ||||
| 150 | <tt>:selected</tt> option. If <tt>:collection</tt> is not provided, the class of | ||||
| 151 | this object or of the first item in the list will be used to run the find | ||||
| 152 | metnioned above. | ||||
| c3b39ff4 » | shadowfiend | 2008-10-19 | 153 | ||
| 154 | You can override both the method used for display text and that used for the | ||||
| 155 | option value by passing the +text_method+ and +value_method+ options to the | ||||
| 156 | +field+ helper. Further options and HTML options are passed on to | ||||
| 157 | +select+, as usual. | ||||
| 158 | |||||
| 159 | === What About Collections of Non-ActiveRecord Objects? | ||||
| 160 | Unfortunately, this convenience comes at a slight price when it comes to | ||||
| 161 | collections of non-AR objects. If you want to use +field+ with its collection | ||||
| 162 | field magic and you've got, say, integers in the collection, then you'll have to | ||||
| 163 | do a bit of extra work and specify both the value and text methods, like so: | ||||
| 164 | |||||
| 165 | f.field :numbers, :value_method => :to_int, :text_method => :to_int | ||||
| 166 | |||||
| 167 | In this case, since we're getting numbers out, we just use the +to_int+ method | ||||
| 168 | for both the value and the text. | ||||
| 169 | |||||
| 170 | === Notes | ||||
| 171 | Since Rails will typecast date and datetime fields to the Ruby +Time+ class, | ||||
| 172 | these typically won't be recognized appropriately. Currently, the +time_field+ | ||||
| 173 | method is implemented to double-check with the database the type that needs to | ||||
| 174 | be used. If you implement accessors for the relevant fields to return objects | ||||
| 175 | of the appropriate type (see http://www.railsweenie.com/forums/1/topics/936 for | ||||
| 176 | an example of how you could do this), then the appropriate methods will be | ||||
| 177 | called without the extra level of indirection. Sadly, this specialization means | ||||
| 178 | that any Time fields will always have their type checked twice. | ||||
| 179 | |||||
| 180 | Also, the presence of <tt>FormBuilder#field</tt> does NOT in any way mean the | ||||
| 181 | other helpers are not available for use. If the decisions +field+ makes don't | ||||
| 182 | float your boat, feel free to put in a direct call to the regular helpers. The | ||||
| 183 | purpose of +field+ is to try and reduce the repetition (it's a already a string, | ||||
| 184 | why say it again?), not to get in your way. If it's getting in your way, you | ||||
| 185 | probably need a different solution. | ||||
| 186 | |||||
| 187 | == The +LinedBuilder+ Class | ||||
| 188 | |||||
| 189 | +LinedBuilder+ is meant to take the pain out of creating forms whose fields fit | ||||
| 190 | on multiple lines and whose fields have labels and correlated errors. By | ||||
| 191 | default, Rails's +FormBuilder+ doesn't do this. This builder provides those | ||||
| 192 | capabilities transparently. | ||||
| 193 | |||||
| 194 | Because this builder is a self-contained class, the detailed documentation for | ||||
| 195 | it is in the <tt>AwesomeFields::LinedBuilder</tt> documentation. Go get it! | ||||
| 196 | |||||
| 197 | == License and Such | ||||
| 198 | |||||
| 199 | +awesome_fields+ is Copyright (c) 2008 Antonio Salazar Cardozo, released under | ||||
| 200 | the MIT license. | ||||







