== Flagger * Version: 0.9.5 * Release date: 31st May 2007 Do you often find yourself writing repetitive collections of methods on your models that look like: class Order < ActiveRecord::Base def self.paid find_all_by_paid(true) end def self.unpaid find_all_by_paid(false) end def mark_as_paid update_attribute(:paid, true) # related tasks end def mark_as_unpaid update_attribute(:paid, false) # related tasks end end This is good practise, as it keeps your column names wrapped up in the model in case they need changing, rather than littering your controllers (or other models) with them. And it increases code legibility, which is also a Good Thing. The Flagger plugin allows ActiveRecord::Base to give you these methods without you having to write any code. It uses method_missing hooks to respond to methods not caught by ActiveRecord::Base's built-in method_missing code. It is designed to be used with boolean attributes, that is, attributes that contain +true+/+false+, 1/0 or "1"/"0" depending on column type. (Although, it is generally not a good idea to use string/text columns for this type of data. You may encounter problems if you attempt to do so, depending on which Rails version you are using.) === Boolean finders Flagger allows you to use dynamic finders on boolean attributes without using +find_all_by_+. So, using the above example, you can happily call Order.paid to get all your paid orders, without defining the method yourself. In addition, you can call Order.unpaid, and you will get back all the orders for which paid == false. The full list of allowed prefixes is: * +in+, +im+, +un+, +non+, +dis+, +de+, +ir+, and +not_+ If your model has an attribute whose name already begins with one of these, Flagger will take this into account. For example, TallStory.implausible returns all the TallStory records for which implausible == true. You can chop off the prefix as well: TallStory.plausible does what you'd expect. Only one prefix will be added to or removed from the attribute name you use to try and find matching attribute names. Fact.undeniable works if the +Fact+ model has an attribute called +undeniable+, +deniable+, +inundeniable+, +imundeniable+ ... or +not_undeniable+. Attribute names are always checked in this order, and Flagger will use the first one that exists. If no attribute match can be found, the exception raised by ActiveRecord::Base's built-in method_missing code is reraised. Attribute names can be chained together in a similar fashion to that allowed by +find_by_+ and friends. You can use +and+ and +but+ to separate names, so you could write: orders = Order.paid_and_delivered orders.first.paid? #=> true orders.first.delivered? #=> true martinis = Cocktail.shaken_but_not_stirred martinis.first.shaken? #=> true martinis.first.stirred? #=> false === Dynamic markers Attribute-based markers perform the converse task to boolean finders - they set boolean attributes rather than retrieving based on them. They mark (flag) records as having certain properties. Their syntax is very similar to that for finders: order = Order.find(:all).first order.mark_as_paid order.paid? #=> true order.mark_as_delivered_but_not_signed_for order.delivered? #=> true order.signed_for? #=> false These methods do not save the attributes to the database. If you want to save the attributes, end the method call with a !. +mark_as_+ methods detect the column type for each attribute and set values accordingly. +true+/+false+ are used for :boolean fields, 1/0 for numeric fields, and "1"/"0" for :string/:text fields. To perform tasks related to flagging, you can define +after_mark_as_+ methods on your models. Each callback can include one attribute name (with or without prefixes as appropriate) and can end with a ! to denote whether it should be called on database saves or not. For example, Order#after_mark_as_unpaid! will be called after mark_as_unpaid!, mark_as_not_paid! and mark_as_accepted_but_not_paid!, but not after mark_as_unpaid (no exclamation mark). All the existing callbacks that apply to a +mark_as_+ call will be called, but only if a change has been made to the relevant attribute. === Compatibility Flagger has been tested successfully using MySQL 5 with Rails 1.1.6 and 1.2.0 through 1.2.3. Bug reports and test reports for other databases are welcome - my email address is at the end of this file. === Notes Flagger is an adjusted version of a patch[http://dev.rubyonrails.org/ticket/7735] I submitted to Rails that didn't make it into the core. The source has been modified from that version in a few places. Thanks to +tomafro+ for pointing me in the right direction and plugging holes in my Ruby/Rails knowledge. Clearly this plugin will not cover all possible use cases for flaggable models. It is meant to try and provide some generally useful functionality out of the box, and to eliminate the need to write code for the simpler cases. If it doesn't quite do what you need, you can always roll your own methods to avoid hitting +method_missing+. One potentially useful addition would be support for OR-based finder conditions, as in Lorry.red_or_yellow, although I suspect that including that would be excessively complicating things - how would one handle Lorry.red_and_yellow_or_green_but_not_blue? Does that mean (red && yellow) || (green && !blue), or red && (yellow || green) && !blue? Flagger is (c) 2007 James Coglan and is released under the terms of the MIT license. Contact: james at jcoglan dot com