Rails plugins

From WhyNotWiki
(Redirected from Rails plugins and libraries)
Jump to: navigation, search

Libraries/plugins/tools/extensions/engines for Rails. (You might also be interested in Ruby libraries.)


Rails plugins and libraries  edit   (Category  edit) .


Rails plugins and libraries / Installing and using edit

Contents

Can plugins be installed as gems (system-wide)?

[Questions (category)]

Yes!

The Plugin Dependencies plugin[1], for example, can be installed as a gem.

Installation is simple:

> sudo gem install plugin_dependencies

config/environment.rb:
require 'plugin_dependencies'
Rails::Initializer.run do |config|
  ...

With gems, you can even take advantage of gem dependencies. So instead of installing 5 plugins via Subversion (which is a pain, partly because you have to look up / remember the full URL of each plugin), you can just do a single gem install and it will automatically install the 5 plugins it depends on!

> sudo gem install plugins_plus
Bulk updating Gem source index for: http://gems.rubyforge.org
Install required dependency loaded_plugins? [Yn]
Install required dependency appable_plugins? [Yn]
Install required dependency plugin_routing? [Yn]
Install required dependency plugin_assets? [Yn]
Install required dependency plugin_migrations? [Yn]

Efforts to include gem plugin loading into core Rails

The fact that the above examples are possible is, I believe, unrelated to any special code within the Rails system to deal with gem plugins. In other words, I guess this has been possible all along, but few people actually released plugins as gems.

But it does require adding a "require" at the top of your config/environment.rb, before the Initializer is even run. And that's not very Rails-y.

Ticket #6726 ([PATCH] Add support for RubyGem-based plugins) in the Rails tracker, however, plans to change that. It would add support so that you can specify gem-based plugins in your config.plugins array:

    config.plugins = ['foo', 'bar', 'baz', ['spam', '>0.9.0', '<=1.2.3'], 'eggs']

I, however, question the value of this ticket to people like me who would rather not use config.plugins in the first place, if possible, because it requires you to list out all your plugins...

Oh well, I'll keep watching this and see what comes of it...

http://dev.rubyonrails.org/ticket/6726

The trick with gem-based plugins is the fact that you might have many gem plugins installed, but might only want to use a small subset for any given application-- hence the use of config.plugins. Obviously using config.plugins is restrictive-- since if you are using "normal" path-based plugins you have to include them in the list for them to be enabled, but it is elective (and I consider the dependency-resolution mechanism that RubyGems offers well worth maintaining a config.plugins list). As to how it works: Gems are loaded, then their lib/ paths are added to load_paths and load_once_paths as with any plugin (so autoloading works as expected). init.rb is also loaded in the same way as it is with the current path-based plugins (no need to specifically set it to be autorequired by the gem)-- this is so that 'config', etc are available to the plugin.

It seems like to benefit from the "dependency-resolution mechanism that RubyGems offers", you'd have to be using all gem-based plugins... I wonder how well all this works when you have a mix of gem-based and non-gem-based plugins...

Going the other way: unpacking gems and putting them in vendor/

There's an interesting command-line tool/gem called, GemsOnRails, that seems to take the exact opposite approach of gem-based plugins: rather than turning everything (including plugins) into gems, it recommends unpacking all gems into your vendor/ directory so that you wouldn't even be using RubyGems (for those libraries that you unpack)...

"vendor everything"


Homepage: http://gemsonrails.rubyforge.org/









Link or freeze RubyGems into your rails apps, instead of just plugins. This allows you to ‘vendor everything’ – pushing all dependent gems into your rails app thus ensuring your application will be guaranteed to work when deployed. Your application is no longer dependent on the gems that are/aren’t available on your target deployment environment. ...

I actually fail to see what this has to do with Rails at all. Unpacking gems is a feature of RubyGems, not of Rails. All this plugin does (apparently) is provide some rake tasks to wrap the gem unpack command, and to enforce the convention that unpacked gems go into a vendor/gemsw subdirectory of your Rails app. Woop-de-doo.

Hmm, I guess another thing it does for Rails is auto-requires the library-that-was-formerly-a-gem-but-is-now-unpacked-under-vendor during app initialization. That's kind of handy. But still not very compelling. (It's not hard to add a require line to environment.rb...)

I'm not sure what this task actually does:

rake gems:link      # Link a RubyGem into this Rails application; init.rb will be loaded on startup.

What is this "linking" you speak of, Dr. Nic?

The possibility of unpacking gems for the purpose of "ensuring your application will be guaranteed to work when deployed" is one I have considered before (see Gems or svn:externals?), and I'm still not sure what the best solution is.

If I ever did decide that unpacking gems was the best way to go, then I'd definitely want to give GemsOnRails a second look...

Specifying load order

[Problem (category)]: Sometimes your plugins need to be loaded in a specific order, due to dependencies. The plugin_dependencies plugin helps with that, but still only if it is loaded first (before the plugins that use it).

[Solution (category)]: The Plugin Dependencies plugin[2]

Problem: If you have plugins that require the plugin_dependencies plugin, then you have to (unless the plugin happens to be alphabetically later than 'p') use the config.plugins = directive in your environment.rb and explicitly list out all the plugins you want to be loaded. The problem with that: You're duplicating the list of plugins that already exists in the file system as the list of entries in vendor/plugins.

Solution:

Rather than list out all your plugins...

  config.plugins = %W( plugin_dependencies annotate_models appable_plugins loaded_plugins ... )

You only need to explicitly the ones you want required first. Then you can say "then load the rest of the plugins using the default order" and it will...

  config.plugins = ['plugin_dependencies'] + Dir.new('vendor/plugins').entries.reject {|f| f =~ /^\./}

I've also heard that it's possible to use "*" to do the same thing (tell it to load "the rest of the plugins"):

  config.plugins = %W( plugin_dependencies * )

, but that didn't work for me with my version of Rails. I can't remember if they said it was available in edge Rails or with a certain plugin or what...

[Troubleshooting (category)] ./script/plugin install prompts you for a password

Example:

> ./script/plugin install whatever
Authentication realm: <svn://delynnberry.com:3690> DeLynn's Code Repository
Password for 'tyler':

Since you probably don't have a valid login to their repository (and never will), your available options are probably just one: "unsource" the offending plugin source.

First, you need to figure out the exact spelling of the source to remove:

> ./script/plugin sources | grep delynnberry.com
svn://delynnberry.com/code/plugins/

Then simply unsource it:

> ./script/plugin unsource svn://delynnberry.com/code/plugins/
removed: svn://delynnberry.com/code/plugins/
Removed 1 repositories.
 


Rails plugins and libraries / Lower-level edit

[Ruby-level (category)]

(Ruby support libraries that are packaged as Rails plugins (unfortunately), as well as some that are plain old gems...)

Injection

Categories/Tags: [dependency injection (category)]



Project/Development: http://rubyforge.org/projects/injection/


Description: Injection is a simple dependency injection plugin for rails which lets you inject objects into your controllers which have been declared in a YAML file.





ActiveSupport

...

star_full.gif star_empty.gif star_empty.gif Named Options

As listed in other directories: http://rubyfurnace.com/plugins/named_options






def user(*args)
  options = NamedOptions.new(:name, :age, args)
  options[:name] # => “maiha”
  options[:age] # => 14
end

Lets you call it using ordered arguments or with a hash of arguments/options...

user(“maiha”, 14)
user(:name => ‘maiha’, :age => 14)
user(“maiha”, :age => 14)

SandboxedMethods

http://rubyfurnace.com/plugins/sandboxed_methods

Avoid conflicting method and variable names between modules.

"We unconsciously prefer shorter names and tend to use well-conflictable method names such as ‘names’, ‘valid?’, ‘path’ for middle(internal) methods. Indeed it works sanely in your system, but how about outside of it?"

To use it, just change your module from this:

 1 module Foo
 2   def self.included(base)
 3     base.__send__ :include, InstanceMethods
 4   end
 5 
 6   module InstanceMethods
       ...
16   end
17 end

to this:

 1 module Foo
 2   def self.included(base)
 3     InstanceMethods.give(base, :foo)        # 1) use 'give' class methods
 4   end
 5 
 6   class InstanceMethods < SandboxedMethods  # 2) use SandboxedMethods class
       ...
16   end
17 end

It basically does this by prefixing each method with the name of the class ("class_name__method_name"?) and then delegating (?) all method calls...

http://wota.jp/svn/rails/plugins/trunk/sandboxed_methods/lib/sandboxed_methods.rb

    def give(base, *methods)
      target  = (methods.last.is_a?(Hash) && methods.pop[:class]) ? (class<<base; self end) : base
      methods = instance_methods - SandboxedMethods.instance_methods if methods.empty?
      methods << {:to=>"(@_#{name.underscore.gsub('/', '__')} ||= #{self}.new(self))"}
      target.delegate *methods
    end

[Ruby-level (category)]: Dates and times

relative_time_helpers

Rating:
Homepage: [3]
Source code: http://ar-code.svn.engineyard.com/plugins/relative_time_helpers/








http://ar-code.svn.engineyard.com/plugins/relative_time_helpers/init.rb

    # Used for getting multifield attributes like those generated by a 
    # select_datetime into a new Time object. For example if you have 
    # following <tt>params={:meetup=>{:"time(1i)=>..."}}</tt> just do 
    # following:
    #
    # <tt>Time.parse_from_attributes(params[:meetup], :time)</tt>
    def parse_from_attributes(attrs, field, method=:gm)
      attrs = attrs.keys.sort.grep(/^#{field.to_s}\(.+\)$/).map { |k| attrs[k] }
      attrs.any? ? Time.send(method, *attrs) : nil
    end

Con: They foist their date format preferences on you (Nov 15th, rather than 15 November or 11-15):

http://ar-code.svn.engineyard.com/plugins/relative_time_helpers/test/relative_time_helpers_test.rb

  def test_should_show_date_span_on_the_different_year
    assert_equal 'Nov 15th, 2006 - Dec 16th, 2007', relative_date_span([Time.utc(2006, 11, 15), Time.utc(2007, 12, 16)])
    assert_equal 'Nov 15th, 2006 - Dec 16th, 2007', relative_date_span([Time.utc(2007, 12, 16), Time.utc(2006, 11, 15)])
  end

star_full.gif star_empty.gif star_empty.gif interpolated_time_formats

Homepage: http://wiki.pluginaweek.org/Interpolated_time_formats
Source code: http://svn.pluginaweek.org/trunk/plugins/ruby/time/interpolated_time_formats


As listed in other directories: http://rubyfurnace.com/plugins/interpolated_time_formats






http://wiki.pluginaweek.org/Interpolated_time_formats

Rather than requiring the addition of helper methods, this plugin proposes creating such strings with strftime. For example,

>> Time.parse('12/31/2006').strftime('#{day.ordinalize} of %B')
=> "31st of December"


EZTime

http://users.webtest.wvu.edu/cbscharf/eztime/

puts d.eztime(":day :nmonth :year at :hour12::minute::second 
:lmeridian") 
=> 20 December 2003 at 5:30:00 pm

Date Finder

http://rubyfurnace.com/plugins/date_finder

Can find dates that match certain criteria. Eg: The next three Tuesdays: DateFinderBase.weekly.day(:tuesday).find(:max => 3) The last Monday for the next three months: DateFinderBase.monthly.day(:monday).day_occurrence(:last).find(:max => 3)

Note: This appears to have nothing at all to do with ActiveRecord searching (kind of deceptive, if you ask me, since it's packaged as a Rails plugin). Rather, it actually returns Date instances as the results of its "searches".

[library-level (category)]

object_id_session: Lets you store ActiveRecord models in the session using their IDs

http://rubyfurnace.com/plugins/object_id_session

A very simple plugin that allows to store ActiveRecord models over session using their IDs transparently.

session[:user] = User.find(id)
# After this, your session will have :user => id and ?__user_object_id_session? => User.

star_full.gif star_full.gif star_empty.gif [GnuPG (category)] plugin [API wrappers for command-line applications (category)]

Homepage: http://www.ahgsoftware.com/pages/erb_buffer
Source code: svn://ahgsoftware.com/gnupg/trunk


As listed in other directories: http://rubyfurnace.com/plugins/gnupg






passphrase = "uglydonkeys"

gnupg = GnuPG.new :binary=>"/opt/local/bin/gpg",
   :workdir=>workdir,
   :homedir_pub=>workdir,
   :homedir_sec=>workdir,
   :recipient=>"your uid"

plain_message = "my secret message"
encrypted_message = gnupg.encrypt(plain_message)

gnupg.load_key File.read("sec_key.asc")
decrypted_message = gnupg.decrypt(encrypted_message, passphrase)
gnupg.drop_key

RailMail

http://railmail.nullstyle.com/

Advantages:

  • Logs all outgoing e-mail to a database table. Much nicer to read/search than the log file, which is where it gets logged by default.
    • Why would you want to see what's been sent? Maybe if someone claims they never received an e-mail you sent, you could check the logs easily and see. (Even if it appears that you did already send it, this would make it easier to resend.)
  • Less dependencies on your development box. No need to set up outgoing mail on your box or even have an Internet connection. Just check the RailMail log to see if it went out.
  • Can test your application with addresses other than your own and not worry about bothering other people. (This could also be solved by using a much simpler plugin that just overrode ActionMailer to have it deliver all outgoing messages to you regardless of original recipient.)

Problems:

  • Don't fallaciously assume e-mail is going out successfully just because it is logged by RailMail. Manual testing of e-mails on live server will still be necessary.
  • Does having a message in the RailsMail log mean that it was sent? Apparently, you need to set railmail_settings[:passthrough] = :smtp in order for mail to actually be sent. So maybe it should log the value of passthrough for each logged message so you know if it was actually passed through to SMTP or not.

Conclusion: Seems like overkill to me. Maybe some applications would have more need of e-mail logging, but I probably typically wouldn't.



Permissions/Security

ModelSecurity

http://weblog.rubyonrails.com/2005/11/11/why-engines-and-components-are-not-evil-but-distracting McNewby, 2005-11-16 05:50:

However, from an infrastructural perspective, I like the thinking of ModelSecurity – in as much as permissions should at least begin in the Model (and hopefully ripple out to the UI). It should be possible to develop Rails such that permissions can be automatically ‘discovered’, e.g. for every attribute, there’s only three options: no access, read, write. Likewise for each method, there’s only two: can run, can’t run…

secure-action-plugin

http://rubyfurnace.com/plugins/secure_action_plugin

secure-action-plugin provides an easy to use interface for protecting your app against assumed logged in attacks
 


Rails plugins and libraries / Database-level edit

[ActiveRecord/database-level (category)]

ActiveWarehouse

http://activewarehouse.rubyforge.org/

Appable plugins: distribute models in your plugin

See Rails plugins and libraries / Plugin tools#Appable plugins

redhillonrails_core

http://www.redhillconsulting.com.au/rails_plugins.html

http://www.redhillconsulting.com.au/rails_plugins.html#redhillonrails_core

The plugin provides two mechanisms for adding foreign keys as well as preserving foreign keys when performing a schema dump.
t.foreign_key :customer_id, :customers, :id

ActiveRecord Defaults

http://rubyfurnace.com/plugins/activerecord_defaults

Allow you to easily specify default values for attributes on new model objects.

How does this compare to having the defaults stored in the database?



[ActiveRecord/database-level (category)]: Migrations

Migrate "development" and "test" databases simultaneously

When would you not want to?

I've had numerous occasions where I wonder why my test isn't passing, only to eventually find out that I hadn't migrated the test database yet, only development. I had done manual testing with the development environment, and everything had worked beautifully, so I was mystified why it wouldn't work in test.

(The plugin)

[To do: Soon to be released]



star_full.gif star_full.gif star_full.gif Transactional Migrations

Homepage: http://www.redhillonrails.org/#transactional_migrations
Source code: svn://rubyforge.org/var/svn/redhillonrails/trunk/vendor/plugins/transactional_migrations



Description: Transactional Migrations is a plugin that ensures your migration scripts—both up and down—run within a transaction. When used in conjunction with a database that supports transactional Data Definition Language (DDL)—such as PostgreSQL—this ensures that if any statement within your migration script fails, the entire script is rolled back.


License: [[:MIT license|MIT license]]


Authors: Red Hills Consulting


rake db:migrate:plugins # Migrates both acts_as_bunny and acts_as_chicken
rake db:migrate:plugins PLUGIN=acts_as_bunny
rake db:migrate:plugins PLUGIN=acts_as_bunny VERSION=2

star_full.gif star_full.gif star_empty.gif Plugin migrations

Homepage: http://wiki.pluginaweek.org/Plugin_migrations
Documentation: Readme
Source code: script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/active_record/migrations/plugin_migrations
Project/Development: http://dev.pluginaweek.org/browser/trunk/plugins/active_record/migrations/plugin_migrations
As listed in other directories: http://rubyfurnace.com/plugins/plugin_migrations
Description: plugin_migrations adds the abilities for all plugins to have the same migration capabilities that your Rails application has. It does this by adding a new table called plugin_schema_info to keep track of the migration version of each plugin.





Installation

script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/loaded_plugins/
script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/active_record/migrations/plugin_migrations

Usage

Just create a db/migrate directory within your plugin's directory and throw some plugin-specific migrations (creating tables, most likely) in it and you're set!

Then when the user installs your plugin, they can simply run rake db:migrate:plugins to run those migrations!

(Much better than creating a migration generator, I think.)

rake db:migrate:plugins
rake db:migrate:plugins # Migrates all loaded plugins
rake db:migrate:plugins PLUGIN=acts_as_commentable
rake db:migrate:plugins PLUGIN=acts_as_commentable VERSION=2


star_full.gif star_empty.gif star_empty.gif DSL-style migrations

Makes your migrations a little DRYer.

http://habtm.com/articles/2006/12/26/dsl-style-migration

class CreateAccounts < Special::Migrations::Table
  table_name :accounts
  column     :login,      :string
  column     :email,      :string
  column     :created_at, :datetime
  options[:force] = true
end

Pope Says: December 26th, 2006 at 07:10 AM

as for maintainable, it may not in the area you are thinking about. Since going down is just the opposite of going up, why try to make sure that you keep those two in sync? I have run into situations where going down broke something, most of the time due to a typo or because something was forgotten. Since this seems to look like it takes care of that, it becomes one less thing you have to maintain. I can see a complaint with it that it may be too customized. I have fallen in this pitfall of metaprogramming where i get so into it, that it becomes less readable. That is because this way of thinking about migrations solves the majority of the problems; however, for some of the other problems, a user would have to resort back to using the old system. That means that someone using this would have to be familiar with both ways to do it. That problem now falls on the user of this special system as to if he/she wants to use it or not.

David Says: December 26th, 2006 at 08:39 PM

> I usually rewrite migration files and remigrate database via > VERSION=0 again and again. Yeah, I do this a lot during initial development, so maintainability does count.

Jason Says: December 28th, 2006 at 12:43 AM

Wow, you guys really take the DRY concept way too far. DRY is nice and it’s one of the reasons I love rails but come on, “redundant temporary variable ‘t’ in ‘create_table’ block”? That’s just silly.

star_full.gif star_empty.gif star_empty.gif Migratory Shortcuts

Migrations are truly a great addition to Rails. That said, if you have a boat load of tables in your project it can be pretty tedious to keep repeating the same values [column specifications] again and again. Somewhere in the middle of doing this…

create_table :actors do |t|
  t.column "created_at", :datetime
  t.column "updated_at", :datetime
  t.column "deleted", :boolean, :null => false, :default => false
end

create_table :names do |t|
  t.column "name", :string, :null => false
  t.column "created_at", :datetime
  t.column "updated_at", :datetime
  t.column "created_by", :integer, :null => false
  t.column "updated_by", :integer, :null => false
  t.column "deleted", :boolean, :null => false, :default => false
end

create_table :actors_names do |t|
  t.column "actor_id", :integer, :null => false
  t.column "name_id", :integer, :null => false
  t.column "position", :integer, :null => false, :default => 0
  t.column "created_at", :datetime
  t.column "updated_at", :datetime
  t.column "created_by", :integer, :null => false
  t.column "updated_by", :integer, :null => false
  t.column "deleted", :boolean, :null => false, :default => false
end

for the tenth time, you begin to wonder if there is a better way.

Introducing.. a better way.

The above becomes this…

create_table :actors, :with => [:timestamps,:userstamps,:acts_as_paranoid]

create_table :names, :with => [:timestamps,:userstamps,:acts_as_paranoid] do |t|
    t.column "name", :string, :null => false
end

create_link_table :actors, :names, :with =>
    [:timestamps, :userstamps, :acts_as_paranoid, :acts_as_list]

This makes dealing with migrations just a bit more manageable, and you no longer need to remember all the “magic” column names. Just say “acts_as_list” and the “position” column is added for you.

Thus far the following options are supported:

  • acts_as_list
  • acts_as_tree
  • acts_as_nested_set
  • acts_as_paranoid
  • timestamps
  • userstamps


subverted_migrations

http://rubyfurnace.com/plugins/subverted_migrations

This plugin makes it easier to use Rails migrations with Subversion (when working with multiple branches). It has two main features:

  • Ensures unique version numbers across the trunk and branches
  • Keeps track of which migrations have been applied to the database, and applies new migrations when merged in to the branch.

[ActiveRecord/database-level (category)]: [Searching (category)] / query building

See also Ruby libraries#Database

acts_as_locateable

Categories/Tags: [searching (category)][acts_as_plugins (category)]
Homepage: http://www.baconbear.com/articles/2006/12/29/actsaslocateable-released
Source code: http://svn.baconbear.com/rails_plugins/acts_as_locateable/trunk/


As listed in other directories: http://rubyfurnace.com/plugins/actsaslocateable
Description: [[description := ActsAsLocateable is an easy way to give any model the ability to be found by location.[4]|ActsAsLocateable is an easy way to give any model the ability to be found by location.[5]]]





http://www.baconbear.com/articles/2006/12/29/actsaslocateable-released

ActsAsLocateable is an easy way to give any model the ability to be found by location. For instance, say you have a model Store which is associated with a zip code indicating where that Store is located. To find all the stores within a specific radius of another ZipCode, you can do a

Store.find_within_radius(10, 12345) # Find all stores within 10 miles of zip code 12345

Based on: the ZipCodeSearch plugin (heavily)


ZipCodeSearch

Categories/Tags: [searching (category)]
Homepage: http://zipcodesearch.rubyforge.org/
Source code: svn://rubyforge.org/var/svn/zipcodesearch/trunk


As listed in other directories: http://rubyfurnace.com/plugins/zipcodesearch






http://zipcodesearch.rubyforge.org/

ZipCodeSearch is a Rails plugin that makes implementing location-based searches a cinch. If you've ever wondered how to do location-based radius searches in your snazzy new Web 2.0 application, then this plugin might save you some time. This plugin will create a ZipCode model, which contains all the code for calculating distances and searching. This plugin will also create a migration that adds a zip code table to your database, complete with 45,000 zip codes and with their lat/lon and city/state information. Finally, this plugin will generate a fully functional controller/view that contains a simple example of how to use the ZipCode model for your location searches.

star_full.gif star_full.gif star_full.gif ez-where [DSLs (category)]

Very intuitive.

A couple neat examples (http://brainspl.at/articles/tag/where):

    options = Article.find_where_options do |article|
      article.comments.user.name == 'Fab'
      article.and( (article.c.title =~ 'A%') | (article.c.title =~ 'B%') )
      article.comments.any do 
        body =~ 'Lorem%'
        body =~ 'Ipsum%'
      end
    end

cond = c{ title =~ '%ruby%' }
cond += c{ description =~ '%ez-where%' }
cond |= c{ user_id === (1..5) }
cond -= c{ pub_date > Time.now.to_s(:db) }
Post.find :all, :conditions => cond
=> ["((title LIKE ?) AND (description LIKE ?)) 
    OR ((user_id IN (?)) AND NOT (pub_date > ?))",
    "%ruby%", "%ez-where%", [1, 2, 3, 4, 5], "2006-06-21 01:17:47

http://brainspl.at/articles/2006/01/30/i-have-been-busy

./script/plugin install http://opensvn.csie.org/ezra/rails/plugins/dev/ez_where/

http://rubyforge.org/projects/ez-where/

ez-where tag on Ezra's blog

star_full.gif star_full.gif star_full.gif CriteriaQuery [DSLs (category)]

Description [6]:

CriteriaQuery is an extension to the ActiveRecord find mechanism. It allows object-oriented construction of queries.

Examples: [7]

Person.query.name_like(‘name’).join(‘address’).city_like(‘city’).join(‘state’).name_eq(‘state’)

instead of

Person.find(:all, :conditions=>[‘people.name LIKE ? AND addresses.city LIKE ? AND states.name=?’, ‘name’, ‘city’, ‘state’], :include=>[:city=>[:state]])

[8]

 pq = Person.query
 pq.name_like('name')
 pq.join('address') do |address|
   address.or do |streets|
     streets.street_1_like('street).street_2_like('street)
   end
 end
 pq = Person.query
 pq.join(:lives_in)
 pq.join(:works_in)
 pq.or << pq.lives_in.street_eq('some_street') << pq.works_in.street_eq('some_street')

Features:

  • Available expressions:
    • Equals
    • Not equal
    • Like
    • Greater than
    • Greater than or equal
    • Less than
    • Less than or equal
    • Is null
    • Not null
    • In
  • Available subrestrictions
    • Disjunction (OR)
    • Conjunction (AND)
    • Negation
  • Supports joins across multiple associations
  • Supports joining the same table multiple times

acts_as_solr

Categories/Tags: [full-text search (category)][acts_as plugins (category)]
Homepage: http://acts-as-solr.rubyforge.org/
Source code: http://opensvn.csie.org/thiago/rails/plugins/acts_as_solr/


As listed in other directories: http://rubyfurnace.com/plugins/acts_as_solr






http://rubyfurnace.com/plugins/acts_as_solr:

This plugin adds full text search capabilities using Solr to any Rails model.

Live search

(very "cool"!)

http://www.recentrambles.com/pragmatic/view/59

Query by example

http://blog.codahale.com/2006/02/04/a-rails-howto-query-by-example/

Squirrel

http://giantrobots.thoughtbot.com/2006/9/29/an-improvement-for-querying-in-rails

Query builder

http://rubyfurnace.com/plugins/query_builder

This plugin enables you to define finder methods that bypass the overhead of construct_finder_sql. Inside an ActiveRecord model definition,

define_finder query_name, query_type, options_hash

will create a SQL query method called query_name from a given options_hash. query_type can be :first or :all.

The plugin supports all options except :include, but ignores with_scope options.

Example:

class Recipe
  define_finder :find_all_of_user, :all,
                     :conditions => 'user = :user AND priv < :priv'
end

This defines a query method which can be called like so:

Recipe.find_all_of_user :user => 'martin', :priv => 1

This call is equivalent to

Recipe.find :all, :conditions =>
         ['user = :user AND priv < :priv', {:user => 'martin', :priv => 1}]


star_full.gif star_empty.gif star_empty.gif Condition Builder

http://rubyfurnace.com/plugins/condition_builder

Book.find(:all,
  :include => {:content_pointer => :invitees},
  :conditions => Condition.block { |c|
    c.and "invitees.user_id", self.id
    c.and "content_pointers.created_by_id", self.id
    c.and "content_pointers.company_id", company.id if company
  })

conditioner

http://www.bigbold.com/snippets/posts/show/2510

Converts arrays of this form:

[['user_id', 3], ['job_id', 4]

into ActiveRecord conditions form:

["user_id=? AND job_id=?", 3, 4]

SodaSearch

Homepage: http://sodasearch.rubyforge.org/
Source code: svn://rubyforge.org/var/svn/sodasearch
Project/Development: http://rubyforge.org/projects/sodasearch/


Description: SodaSearch is a drop-in full text indexer plugin for Ruby on Rails. It allows coders to add full text indexing to their models with minimal effort. The index is stored as two regular tables in your project's existing RDBMS.





Soda Search is a medium-performance full-text indexing system. It is loosely based on the same principles as Xapian (www.xapian.org/). The system is relatively simple. It consists of two database tables per class being indexed, plus some ActiveRecord extensions shared by all classes that use the Indexer. The database tables are deliberately NOT normalized completely, to cut back on the computational overhead required to do searches and updates. This system is quite useable as it is, but the index format it provides is also the foundation for a much more robust searching system. We will eventually implement phrase matching, term weighting, Boolean term combination, etc. This can all be accomplished with the current index format; all that needs to be done is modify the searching code.

 


Rails plugins and libraries / Model-level edit

[Model-level (category)]

http://wiki.rubyonrails.org/rails/pages/Model+Extensions


SemanticAttributes

SemanticAttributes edit


Rating: star_full.gif star_full.gif star_empty.gif
Categories/Tags: [Validations (category)][ActiveRecord / Attributes (category)]



Project/Development: http://code.google.com/p/semanticattributes/


Description: Provides meaningful model attributes for the Ruby on Rails world.



Authors: Lance Ivy
Readiness: not even in beta


http://code.google.com/p/semanticattributes/. Retrieved on 2007-05-11 11:18.


ActiveRecord's attributes are not very friendly to programs that want to automatically and intelligently adapt behavior based on column types. Even once the dev has added validations to the attributes, other plugins are unable to reflect on the attributes and customize their behavior. The basic problem is that attributes in ActiveRecord have no semantic meaning. Validations only describe what to do with a field, not what the field means. But if you know what the field means, then you (and other plugins) can easily infer what to do! So the built-in validations are really tackling the problem backwards. It sounds impossible to describe the meaning every attribute may have, but if we accept the 80/20 guideline then we can package up 20% of the descriptions that classify 80% of the attributes, and provide a way for devs to build the rest as needed. Consider how common the following fields are:

  • phone number
  • email address
  • url
  • filename
  • zip code
  • us_state
Given semantically meaningful descriptions of these (and other) fields, we can not only automatically generate validation logic but also provide methods for standard database/human formatting and provide a reflection API for other plugins (e.g. ActiveScaffold). Some work has been done in this field already, but the other projects don't seem to realize their entire potential. For comparison, see:
 



composed_of_conversion

Source code: http://source.collectiveidea.com/public/rails/plugins/composed_of_conversion








Brandon (2006-11-15). Making #composed_of more useful (http://www.opensoul.org/2006/11/16/making-code-composed_of-code-more-useful). Retrieved on 2007-05-11 11:18.


Active Record allows you to abstract fields into an aggregate object by using the composed_of declaration. This is handy, but the current implementation can be a real pain. The first and somewhat trivial issue is the composed_of declaration builds a string and evals it to define the attribute accessors. It’s not a big deal, but it’s dirty. The second issue is that aggregate objects are not easy to manipulate in Rails, especially in forms.

Fixing it

So, I’ve written a plugin that overrides the Active Record implementation of composed_of, which allows you to specify a block to convert incoming parameters to the correct type.

Personally, this has been most helpful when using the Money gem:

class Account < ActiveRecord::Base
  composed_of :balance, :class_name => "Money", :mapping => %w(cents cents) do |amount|
      amount.to_money
  end
end

If #balance= receives anything besides a Money object, it will call the block to try to convert the parameter to a Money object.

>> account = Account.new :balance => 100
>> account.balance
=> #<Money:0x2612770 @cents=10000, @currency="USD">

And now it can transparently be used in forms:

  <%= text_field :account, :balance %>

This can even be used for more advanced aggregations:

class User < ActiveRecord::Base
  composed_of :address, :class_name => "Address" 
        :mapping => [%w(street street), %w(city city), %w(state state), %w(zip zip)] do |addr|
    Address.new(addr[:street], addr[:city], addr[:state], addr[:zip])
  end
end

A user can now be created from a hash:

  User.new(:address => {:street => "123 A Street", :city => "Somewhere", :state => "NO", :zip => 12345})

I didn’t quite realize all the implications of this extension until I was writing up the docs for this plugin. Active Record magically does type casting for a limited set of types, namely dates and numbers. But this essentially allows you to have a form of type casting for any attribute. Interesting…


has_many_polymorphs

Homepage: http://blog.evanweaver.com/articles/2006/06/02/has_many_polymorphs
Source code: svn://rubyforge.org/var/svn/polymorphs/has_many_polymorphs
Project/Development: http://rubyforge.org/projects/polymorphs/
As listed in other directories: http://rubyfurnace.com/plugins/has_many_polymorphs




Authors: Evan Weaver


http://blog.evanweaver.com/pages/has_many_polymorphs

This plugin for ActiveRecord gives you the ability to define easy-to-use self-referential polymorphic associations with full array-like behavior (.push, .delete, <<) in your models. “Polymorphic” means an association can freely point to any of several disparate model classes, instead of being tied to one particular class.

Example [9]:

# this is the (typed) class that accepts the (untyped) polymorphic objects as children
class Petfood < ActiveRecord::Base
  has_many_polymorphs :eaters, :from => [:dogs, :cats, :birds]
end

# this is the join table
class EatersPetfood < ActiveRecord::Base
  belongs_to :petfood
  belongs_to :eater, :polymorphic => true
end

# this is an example of one of the child classes
class Dog < ActiveRecord::Base
  # nothing
end

petfood.eaters << Cat.create
petfood.cats.size # => 4
petfood.eaters.size # => 6

Association Scope

Source code: http://soen.ca/svn/plugins/rails/association_scope/trunk/


As listed in other directories: http://rubyfurnace.com/plugins/association_scope






http://rubyfurnace.com/plugins/association_scope

Allows scoping of association definitions. - Makes your code more DRY - Works with belongs_to, has_one, has_many, has_and_belongs_to_many

Example

class Post < ActiveRecord::Base
  with_association_scope :order => "created_at DESC", :dependent => :delete_all do
    # Both of these are ordered by created_at
    has_many :posts
    has_many :comments
    # And yes we can override default behaviour
    has_many :milestones, :order => "priority" 
  end
end


:dependent => :protect option

http://rubyfurnace.com/plugins/%3Adependent_%3D%26gt__%3Aprotect_opti

Adds a new option :protect for the parameter :depends from has_many method. This option forbids destroying records with associated records in a association created with :dependent => :protect option, more or less like ON DELETE RESTRICT SQL statement. If you try to destroy a record with associated records it will raise a ActiveRecord::ReferentialIntegrityProtectionError (defined also in this plugin).


[Data formats (category)][CSV (category)]: convertible_to_csv

http://rubyfurnace.com/plugins/convertible_to_csv

class Customer < ActiveRecord::Base
  acts_as_convertible_to_csv :header => true, 
                             :fields => %w(id firstname lastname email_address)
end
Customer.find(:all).to_csv
Customer.find(:first).to_csv

Comments:

  • Doesn't seem good that you have to / can only specify the list of fields to include once per model.

[Data formats (category)][CSV (category)]: to_csv

http://rubyfurnace.com/plugins/to_csv

This plugin provides support for responding to the CSV format, as well as exporting a collection of ActiveRecord objects to CSV. You can simply take a collection of ActiveRecord objects and apply the to_csv method to them:

@users = User.find(:all) @users.to_csv

cached_model

http://seattlerb.rubyforge.org/cached_model/

CachedModel stores Rails ActiveRecord objects in memcache allowing for very fast retrievals. CachedModel uses the ActiveRecord::Locking to ensure that you don‘t perform multiple updates.
CachedModel only accelerates simple finds for single rows.

star_full.gif star_empty.gif star_empty.gif ScopedProxy

Categories/Tags: [with_scope (category)]
Homepage: http://www.jackchristensen.com/article/4/scopedproxy-plugin-for-ruby-on-rails



As listed in other directories: http://rubyfurnace.com/plugins/scopedproxy
Description: ScopedProxy uses with_scope and proxy objects to make it easy to find and count different types of records.



Authors: Jack Christensen


Example [10]

class Person < ActiveRecord::Base
  scoped_proxy :female, :conditions => 'gender = "female"'
  scoped_proxy :single, :conditions => 'married = 0'
  # ...
end

Person.single.find :all
Person.single.female.find :all     # They can also be chained together.


[Model-level (category)]: [Pagination (category)]

Some might argue that this is a controller-level feature, but I don't think so. Half the challenge is getting it to limit your database query so that it returns the correct page of rows and only those rows...

Paginator gem

Template loop detected: Template:Include with edit link

paginating_find

Categories/Tags: [Pagination (category)]
Homepage: http://cardboardrocket.com/pages/paginating_find
Source code: http://svn.cardboardrocket.com/paginating_find


As listed in other directories: http://rubyfurnace.com/plugins/paginating_find






http://rubyfurnace.com/plugins/paginating_find

Got 15,842 records that you'd like to export to a file? Using the standard Rails ActiveRecord::Base#find method will load all 15,842 into memory all at once and return them all in an array. If your app is running on a shared host, or if you?re keeping your app on a memory budget, this is a big problem for you. So you could load each record one by one, but that'll kill your DB server. Wouldn't it be sweet if #find could return an Enumerable that would load your records in batches of say 1,500 records? Well with my new nifty-jifty paginating_find plugin, it can.






star_full.gif star_full.gif star_full.gif acts_as_breadcrumbs

Homepage: http://breadcrumbs.rubyforge.org/ http://actsasflinn.com/articles/2007/05/02/acts_as_breadcrumbs
Source code: svn://rubyforge.org/var/svn/breadcrumbs/trunk/acts_as_breadcrumbs


As listed in other directories: http://agilewebdevelopment.com/plugins/acts_as_breadcrumbs
Description: This plugin uses an acts_as_tree model and creates a breadcrumbs trail attribute using a base attribute.



Authors: Flinn Mueller - actsasflinn.com


class WebPage < ActiveRecord::Base
  include ActionView::Helpers::TagHelper

  acts_as_tree
  acts_as_breadcrumbs(:attr => :url, :basename => :slug, :separator => "/")
  acts_as_breadcrumbs(:basename => :link, :separator => " > ")

  # from urlnameable
  def slug
    t = self.title.to_s.downcase.strip.gsub(/[^-\s[:alnum:]]/, ’’).squeeze(’ ‘).tr(’ ‘, ‘‘)
    (t.blank?) ? ’_’ : t
  end

  def link
    content_tag ‘a’, self.title, :href => "#{self.url}"
  end
end

baz = WebPage.create(:title => "Baz", :parent => bar)
baz.url         #=> ‘foo/bar/baz’
baz.breadcrumbs #=> ’<a href="foo">Foo</a> > <a href="foo/bar">Bar</a> > <a href="foo/bar/baz">Baz</a>’






[Model-level (category)]: [acts_as plugins (category)]

(This categorization has a rather low order of precedence. I'm not even sure if it's a very good category to have, since there are some plugins that certainly work similarly to some of these, but don't have "acts_as" in their name (convertible_to_csv could have just as easily been called acts_as_convertible_to_csv ... except that would be rather verbose; cached_model could have been called acts_as_cached_model; ...). Should they be included here too?)

Why they're cool

Bruce Tate (2007-03-13). Crossing borders: Extensions in Rails: The anatomy of an acts_as plug-in (http://www-128.ibm.com/developerworks/java/library/j-cb03137/index.html). Retrieved on 2007-03-14 10:15.

If you've spent any time at all with Rails, you've doubtless noticed the acts_as commands in ActiveRecord. Though ActiveRecord deals with persistence, you often want to add behavior to your [models] beyond database storage and retrieval. For example, by using acts_as_tree, you can add tree-like behavior to a class with a parent_id attribute. By saying nothing more than acts_as_tree in your ActiveRecord model, you can dynamically add methods to manage the tree, such as methods that retrieve the parent record or child record. Over the past month, I've been able to find Rails plug-ins to handle voting, versioning, Ajax, composite keys, and all manner of features that basic Rails doesn't support. Using the plug-in, I can decorate my class object directly, using a DSL to represent the various states, transitions between them, and the events that fire those transitions. [...] ... You might think it would be simpler just to build a state machine and use it as a library. The acts_as plugin is much nicer. It [acts_as_state_machine] lets you effectively add a state-machine column to your database. Other plug-ins let you do versioning, build in audit histories, handle images, and perform hundreds of other simple tasks, just as if those tasks were a seamless integration between the Rails environment and the database.


ActsAsScheduled

Project/Development: http://code.google.com/p/actsasscheduled/


Description: Plugin for Ruby on Rails that enables scheduling of a model



Authors: Lance Ivy
Readiness: not even in beta


http://code.google.com/p/actsasscheduled/. Retrieved on 2007-05-11 11:18.


Lets you plot some model or record into the future. Lets you define the record as a repeated event. Provides an API to let you navigate the future occurrences.


acts_as_geocodable

Have used: no
Rating: star_full.gif star_full.gif star_full.gif
Categories/Tags: [Geocoding (category)]
Documentation: Readme
Source code: http://source.collectiveidea.com/public/rails/plugins/acts_as_geocodable








brandon (2007-02-13). Geocoding as easy as 1-2... (http://www.opensoul.org/2007/2/13/geocoding-as-easy-as-1-2). Retrieved on 2007-05-11 11:18.


...

event = Event.create :street => "777 NE Martin Luther King, Jr. Blvd.",
  :city => "Portland", :region => "Oregon", :postal_code => 97232

# how far am I from RailsConf 2007?
event.distance_to "49423" #=> 1807.66560483205

# Find our new event, and any other ones in the area
Event.find(:all, :within => 50, :origin => "97232")

# Find the nearest restaurant with beer
Restaurant.find(:nearest, :origin => event, :conditions => 'beer = true')

...

Why did you write this when there’s already several geocoding plugins?

The Ruby geocoding space is pretty fragmented right now. There’s all kinds of geocoders available, and none of them provide everything. We’re determined to fix that with Graticule and acts_as_geocodable.

We believe that all the heavy lifting of geocoding, distance calculations, etc., should be left to a gem, and only code that is directly related to Rails should be a Rails plugin. Even more, all the different geocoders should be available in the same package and have the same interface. A plugin should then be built on top of the gem that makes your apps geo-capabilities seem like voodoo.

We started our own projects because we didn’t think anyone else got it right. Recently, Bill Eisenhaur and Andre Lewis did a pretty good job, and we borrowed some of their ideas, but I still have issues with their approach and code, mainly that it’s all tied up into a Rails plugin.

Did you get it right?

I think we have a great foundation. It’s not perfect, nor does it have all the features of the other packages, but I think it is [well architected (category)].

Why don’t you work together?

Excellent idea! We would love to.


star_full.gif star_full.gif star_empty.gif acts_as_cached

Categories/Tags: [acts_as plugins (category)]
Homepage:  ?









DRY association sweeping with acts_as_cached (http://blog.methodmissing.com/2007/1/11/dry-association-sweeping-with-acts_as_cached). Retrieved on 2007-03-29 11:48.

Cherry picking exactly which models and associations to cache with Acts as Cached is dead simple.However, cached object associations quickly result in repetitive sweeping snippets. ... But there's a better way...

Add to acts_as_cached's InstanceMethods:

        def expire_cache_with_associations( *associations_to_sweep )
          ((self.class.cache_options[:include] || []) + associations_to_sweep).flatten.uniq.compact.each do |assoc|
            macro = self.class.reflect_on_association(assoc.to_sym).macro
            macro == :has_many ? self.send(assoc.to_sym).each{|r| r.expire_cache unless r.nil? } : self.send(assoc.to_sym).expire_cache unless self.send(assoc.to_sym).nil?
          end 
          expire_cache
        end
class Address < ActiveRecord::Base
  acts_as_cached :version => 1, :include => [:country] 
  belongs_to :addressable, :polymorphic => true 
  belongs_to :country, :class_name => 'Globalize::Country', :foreign_key => 'country_id'

  after_save     :cache_sweeper
  before_destroy :cache_sweeper

  protected  

  #sweep the related addressable entity
  def cache_sweeper; expire_cache_with_associations(:addressable) end
end

star_full.gif star_full.gif star_empty.gif acts_as_versioned

Categories/Tags: [acts_as plugins (category)]


Source code: http://svn.techno-weenie.net/projects/plugins/acts_as_versioned/
Project/Development: http://rubyforge.org/projects/ar-versioned
As listed in other directories: http://agilewebdevelopment.com/plugins/acts_as_versioned
Description: This library adds simple versioning to an ActiveRecord module.
Depends on: ActiveRecord






[11] kpr 1 Jun 2006

This plugin does not work at all with join tables.


star_full.gif star_full.gif star_empty.gif acts_as_audited

Categories/Tags: [acts_as plugins (category)]
Homepage: http://opensoul.org/2006/07/21/acts_as_audited/
Source code: http://source.collectiveidea.com/public/rails/plugins/acts_as_audited


As listed in other directories: http://rubyfurnace.com/plugins/acts_as_audited






http://opensoul.org/2006/07/21/acts_as_audited/

acts_as_audited is an Active Record plugin that logs all modifications to your models in an audits table. It uses a polymorphic association to store an audit record for any of the model objects that you wish to have audited. The audit log stores the model that the change was on, the “action” (create, update, destroy), a serialized hash of the changes, and optionally the user that performed the action.

class ApplicationController < ActionController::Base
  audit User, List, Item
end

brandon (2007-06-18). Revisioning with acts_as_audited (http://www.opensoul.org/2007/6/18/revisioning-with-acts_as_audited). Retrieved on 2007-05-11 11:18.


When I first created acts_as_audited over a year ago, I intended to add versioning/revisioning capabilities, but found I never really had a need. Well, it just so happened that I finally had a need on an app that we are working on. So, acts_as_audited now allows you to revert back to previous revisions. You can get all the revisions of a model:

article.revisions.each |revision|
  puts revision.class   #=> Article
  puts revision.version #=> 7, 6, 5, 4...
end

or a specific revision:

revision = article.revision(5)
puts revision.title     #=> "Old Title"

or the previous revision. Reverting is as simple as saving a revision:

previous = article.revision(:previous)
previous.save           # revert to previous revision

See the original post for more details about installing and using the plugin.

...

Upgrading

To use the versioning support, you must add a version field in the audits table:

add_column :audits, :version, :integer, :default => 0

Note: if you already have audit records, the version field will have to be initialized.

Feedback

This code is fairly specific to what I needed, so if you’re using it, I would love to hear how it is working for you. Suggestions and patches welcome.

acts_as_audited / acts_as_audited comparison

brandon (2007-06-18). Revisioning with acts_as_audited (http://www.opensoul.org/2007/6/18/revisioning-with-acts_as_audited). Retrieved on 2007-05-11 11:18.


How is this different from acts_as_versioned?

I’ve never used acts_as_versioned1 (because I’ve never had a need to do versioning), but I do know that it has a few annoying limitations: 1) it requires a separate table (and model) for each model that you want to version, and 2) it saves every attribute, even if it’s not changed.

acts_as_audited already stories all the changes (and only the changes) in one table, so adding versioning was rather trivial. Revisions are created by walking backward through the audits, collecting the changes, and returning an instance of the model.

...

acts_as_changed

Categories/Tags: [monkey patches (category)]


Source code: http://svn.viney.net.nz/things/rails/plugins/acts_as_changed/


As listed in other directories: http://rubyfurnace.com/plugins/acts_as_changed
Description: Specifies only the changed fields when updating the database record.





http://svn.viney.net.nz/things/rails/plugins/acts_as_changed/lib/acts_as_changed.rb

ActiveRecord::Base.send(:include, ActiveRecord::Acts::Changed)


star_full.gif star_full.gif star_empty.gif ActsAsList

acts_as_list

Part of: Rails




Documentation: * http://www.rubyonrails.org/api/classes/ActiveRecord/Acts/List/ClassMethods.html
Source code: /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/acts/list.rb








How it works: insert_at

[Code dissections (category)]

/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/acts/list.rb

        def insert_at(position = 1)
          insert_at_position(position)
        end

          def insert_at_position(position)
            remove_from_list
            increment_positions_on_lower_items(position)
            self.update_attribute(position_column, position)
          end

        def remove_from_list
          decrement_positions_on_lower_items if in_list?
        end

          def decrement_positions_on_lower_items
            return unless in_list?
            acts_as_list_class.update_all(
              "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} > #{send(position_column).to_i}"
            )
          end

          # This has the effect of moving all the lower items down one.
          def increment_positions_on_lower_items(position)
            acts_as_list_class.update_all(
              "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} >= #{position}"
           )
          end

Sometimes it's hard to read past all the abstractions (metaprogramming, methods that call many other methods, etc.) and see what's actually going on. This was one of those cases (it was for me, anyway). A couple specific examples that let me see what was going on would just help me tremendously to get a picture in my mind of what's going on and how this code works.

So if we started with this list:

        # 1. lilac
        #(2. pansy)       
        # 3. daffodil    
        # 4. rose         

and applied pansy.insert_at(1), then this is sort of how the transformation would take place:

pansy.insert_at_position(position = 1)
  (self.position == 2)

  remove_from_list
    decrement_positions_on_lower_items
      update_all(
        "position = (position - 1)", "position > 2"
      )
        # 1. lilac
        # 2. daffodil    * moved /\
        # 3. rose        * moved /\
        #
        #(2. pansy)      
        # It's as if pansy is no longer in the list. The other items moved up to take its place.

  increment_positions_on_lower_items(position = 1)
    update_all(
      "position = (position + 1)", "position >= 1"
    )
        # 1. (empty)
        # 2. lilac       * moved \/
        # 3. daffodil    * moved \/
        # 4. rose        * moved \/
        #
        # Hey cool, that just opened up a slot for pansy!
        #(3. pansy)      * moved \/
        #   Oops, we're moving further away from our goal, but it doesn't really matter because 
        #   the next step will always fix it...

  self.update_attribute(:position, 1)
        # 1. pansy       * moved directly to 1
        # 2. lilac       
        # 3. daffodil    
        # 4. rose        

It worked, but I still don't understand why it was implemented that, why we went through all the trouble of decrementing those rows, only to increment them as the very next thing we do! When really, the only record that needed to be updated was the one at position #1 (lilac) (move it to position #2)! Seems kind of inefficient in this case.

I guess it does have the advantage that it makes the logic easier to follow:

  1. first, we remove the item from the list;
  2. then we make room for it;
  3. then we put it in the slot we just created.

Let's try another example and see if that changes our opinion of this algorithm any.

        # 1. lilac
        #(2. pansy)       
        # 3. daffodil    
        # 4. rose         

pansy.insert_at_position(position = 3)
  (self.position == 2)

  remove_from_list
    decrement_positions_on_lower_items
      update_all(
        "position = (position - 1)", "position > 2"
      )
        # 1. lilac
        # 2. daffodil    * moved /\
        # 3. rose        * moved /\
        #
        #(2. pansy)      
        # It's as if pansy is no longer in the list. The other items moved up to take its place.

  increment_positions_on_lower_items(position = 1)
    update_all(
      "position = (position + 1)", "position >= 3"
    )
        # 1. lilac       
        # 2. daffodil    
        # 3. (empty)
        # 4. rose        * moved \/
        #
        # Hey cool, that just opened up a slot for pansy!
        #(2. pansy)      

  self.update_attribute(:position, 3)
        # 1. lilac       
        # 2. daffodil    
        # 3. pansy       * moved directly to 3
        # 4. rose        

I think my confidence in this algorithm has gone up since when I first stumbled upon this code -- thoroughly confused. Yep, it makes sense. It may not be the most efficient way, but it's easy to see how the algorithm will always work.


star_full.gif star_full.gif star_empty.gif ActsAsListOf

Homepage:  ???
Documentation: http://pastie.caboo.se/31232.txt
Source code:  ???






Authors: Ezra


http://pastie.caboo.se/31232 [12]

[Modified quotation (category)][Paraphrase (category)]
This plugin uses a has_many :through relationship to setup ordered collections of models. By adopting a HABTM-like join table we can keep the code clean and simple, as opposed to a general table for any acts_as_list_of join table.

Category   has_list_of :images

Creates the following setup:

Image           belongs_to_list_of :categories   # (The relationships set up behind the scenes are bi-directional)

ImageCategoryListing            belongs_to :category
ImageCategoryListing            belongs_to :image
ImageCategoryListing            acts_as_list (scoped by Category)

And provides the following association methods:

Category.find(1).images.create(*args, &block)
Category.find(1).images.push(*items)
Category.find(1).images.unshift(*items)
Category.find(1).images.replace(*items)
Category.find(1).images.clear(*args)
Category.find(1).images.remove(*items)
Category.find(1).images.remove_at_position(*range_or_array)
Category.find(1).images.reorder(*items)
Category.find(1).images.insert_at(index_or_obj, position = 1)
Category.find(1).images.move_to_top(index_or_obj)
Category.find(1).images.move_higher(index_or_obj)
Category.find(1).images.move_lower(index_or_obj)
Category.find(1).images.move_to_bottom(index_or_obj)
Category.find(1).images.entries_at_position(*range_or_array)

...

Image.find(1).categories.create(*args, &block)
Image.find(1).categories.push(*categories)
Image.find(1).categories.unshift(*categories)
Image.find(1).categories.replace(*categories)
Image.find(1).categories.clear(*args)
Image.find(1).categories.remove(*categories)

has_filtered_list_of

You can also create a filtered list with some conditions:

class Category < ActiveRecord::Base
  has_filtered_list_of :images, :active_images, :conditions => 'categories_images.active = 1'
end

This implicitly creates the base has_list_of association as well, so it's equivalent to:

class Category < ActiveRecord::Base
  has_list_of :images
  has_filtered_list_of :images, :active_images, :conditions => 'categories_images.active = 1'
end

Required schema

create_table "categories", :force => true do |t|
  t.column "name", :string
  t.column "description", :string
  t.column "position", :integer
end

create_table "images", :force => true do |t|
  t.column "path", :string
  t.column "description", :string
  t.column "created_at", :datetime
  t.column "updated_at", :datetime
end

The join table has a 'position' column to add acts_as_list behaviour. Any additional column you add will be available as well; note that although this looks like a regular HABTM relationship we actually have a full has_many :through join model: CategoryImageListing Where 'Category' is the entry_keeper and Image is the entry_item The alphabetical order of both tables is used for the join table as well as for the *Listing join model.

create_table "categories_images", :force => true do |t|
  t.column "category_id", :integer
  t.column "image_id", :integer
  t.column "position", :integer
  t.column "comment", :string
end



acts_as_reportable

http://stonecode.svnrepository.com/acts_as_reportable/trac.cgi :

acts_as_reportable is a Rails plugin that allows you to convert a query on an ActiveRecord model object into a Ruport::Data::Table for easy integration with Ruport's formatting capabilities.

>> puts Book.report_table(:all).as(:csv)
id,title,author_id
1,Whys (Poignant) Guide to Ruby,1
2,"Flow My Tears, The Policeman Said",2
3,Farenheit 451,3
>> puts Book.report_table(:all, :columns => ['title','author.name']).as(:text)
+----------------------------------------------------+
|               title               |  author.name   |
+----------------------------------------------------+
|  Why's (Poignant) Guide to Ruby   |      _why      |
| Flow My Tears, The Policeman Said | Philip K. Dick |
|           Farenheit 451           |  Ray Bradbury  |
+----------------------------------------------------+

acts_as_state_machine

Rubyist - Acts As State Machine

I’ve been noticing a pattern in several of my projects where I’m having a model object keep track of its state. Sometimes it’s a simple boolean flag, and this presents little problem. Other times, it gets more complex. In a current project, things started out simply. Then the model evolved and finally I realized that I was using three boolean variables to keep the state. To make matters worse, these three flags were being distilled into one state. Needless to say, this collapsed under its own tremendous weight fairly quickly. So I stood at my newly hung whiteboard and thought and thought. I realized that this object was not just in a state, but moving from state to state, in a well defined series of steps, throughout its lifetime. I do believe this is what them academicals calls a “finite automaton” or “state machine” for those of us who doodled or slept during class.

Can I relate to that! There is a need for this plugin.

Good, it looks like a model can have more than one state machine (just give each one a different column name). [Update: On second thought, if that's stored as a class variable (state_column), then you can probably only have one per model.]

http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk/lib/acts_as_state_machine.rb :

      module ActMacro
        # Configuration options are
        #
        # * +column+ - specifies the column name to use for keeping the state (default: state)
        # * +initial+ - specifies an initial state for newly created objects (required)
        def acts_as_state_machine(opts)

A pretty good example of how to use it -- pretty detailed example: http://blog.methodmissing.com/2006/11/16/beyond-callbacks-for-complex-model-lifecycles/

acts_as_flaggable

Homepage: http://www.baconbear.com/articles/2006/12/04/acts-as-flaggable-released
Source code: http://svn.baconbear.com/rails_plugins/acts_as_flaggable/trunk


As listed in other directories: http://rubyfurnace.com/plugins/acts_as_flaggable
Description: Acts As Flaggable is a model modifier which allows flag records to be associated with records. Authors of community driven sites may find this useful for quickly adding the ability to mark records as "spam" or "inappropriate". It also facilities in a way to automatically take a specific action automatically if a record has been flagged a certain way too many times (Think auto-removing posts that have been marked as "spam").





acts_as_clusterable

Homepage: http://cuttingtheredtape.blogspot.com/2006/08/actsasclusterable.html
Source code: http://opensvn.csie.org/acts_as_clusterable/


As listed in other directories: http://rubyfurnace.com/plugins/acts_as_clusterable






http://rubyfurnace.com/plugins/acts_as_clusterable

This plugin makes it very easy to cluster active record objects. It can be used for grouping search results (see http://demo.carrot-search.com/carrot2-webapp/main). This plugin requires the clusterer Ruby gem. Add the following lines to your model:

acts_as_clusterable :fields  => ['title','text']

if no fields are given then it will use all text and string fields present in the model. Now, doing clustering is as easy as:

Joke.hierarchical_clustering()
Joke.kmeans_clustering()


acts_as_activated

Categories/Tags: [acts_as_plugins (category)]
Homepage: http://www.baconbear.com/articles/2006/12/29/actsaslocateable-released
Source code: http://svn.webwideconsulting.com/svn/acts_as_activated/


As listed in other directories: http://rubyfurnace.com/plugins/acts_as_activated
Description: Basically the opposite of acts_as_paranoid, this plugin hides records until the is_active method returns true.





acts_as_activity_logged

Homepage: http://aaal.fearoffish.co.uk/
Source code: svn://svn.fearoffish.co.uk/acts_as_activity_logged/trunk


As listed in other directories: http://rubyfurnace.com/plugins/acts_as_activity_logged






http://rubyfurnace.com/plugins/acts_as_activity_logged

The plugin is designed to track the event that occurred on a model (create/update/destroy) and allow you to see what models were affected. So if you need “Jamie added a comment to ‘My First Post’” kind of functionality, then it’s easy to get with this plugin.

acts_as_rated

http://rubyfurnace.com/plugins/acts_as_rated

Though similar to other rating plugins, this one has a ton of options to customize, while still making it very easy to use. And most important for my use, can cache the statistics of the ratings (total/count/average) in the model itself or an external statistics table, eliminating the need to call sum/count/avg on the ratings table itself.

acts_as_list for habtm relationships

There is a acts_as_habtm_list plugin, but I couldn't get it to work.

Perhaps better to convert the habtm's to has_many :through relationships.

http://www.archivesat.com/Ruby_on_Rails_developers_help/thread783283.htm


acts_as_favorite

http://rubyfurnace.com/plugins/acts_as_favorite

This plugin provides a simple way to track users favorites within the system using ActiveRecord models.


acts_as_view

Categories/Tags: [with_scope (category)]
Homepage: http://habtm.com/articles/2006/07/23/acts_as_view
Source code: http://wota.jp/svn/rails/plugins/branches/stable/acts_as_view/


As listed in other directories: http://rubyfurnace.com/plugins/acts_as_view
Description: Allows an ActiveRecord model to act as a view table.
Depends on: [[:MethodScoping class)]]





http://rubyfurnace.com/plugins/acts_as_view

class ActiveMember < Member
  acts_as_view :deleted => false
end

ActiveMember.find(:all)
# => SELECT * FROM members WHERE (( deleted = 'f' ))

ActiveGrade2Member.create(:name=>"chinako")
# => #"chinako", "grade"=>2, "id"=>5, "deleted"=>false}>

Comments:

  • Implemented using ActiveRecord's “with_scope” feature, so it inherits the benefits and problems of "with_scope".
  • Doesn't actually create a view as far as the DB is concerned. You can't actually do select * from my_view, so it's not helpful when you need to do find_by_sql.


acts_as_slugable [Permalinks (category)]

Homepage: http://multi-up.ca/code/
Source code: http://multi-up.ca/code/acts_as_slugable/


As listed in other directories: http://wiki.rubyonrails.org/rails/pages/Model+Extensions
Description: Generates URL slugs (permalinks) based on a specified field





http://wiki.rubyonrails.org/rails/pages/Model+Extensions

For example, generate a URL slug based on the title of a Page record and store it in url_slug. Slug will be unique within the parent.id.

class Page < ActiveRecord::Base
  acts_as_slugable :source_column => :title, :target_column => :url_slug, :scope => :parent
end



Rails plugins and libraries / Model-level / Validation

Rails plugins and libraries / Model-level / Validation edit


star_full.gif star_full.gif star_empty.gif Validation Reflection

Rating: star_full.gif star_full.gif star_empty.gif
Categories/Tags: [Validations (category)]
Documentation: Readme
Source code: svn://rubyforge.org//var/svn/valirefl/validation_reflection/trunk http://www.schuerig.de/michael/rails/validation_reflection/


As listed in other directories: http://agilewebdevelopment.com/plugins/validation_reflection http://rubyfurnace.com/plugins/validation_reflection




Authors: Michael Schuerig



http://agilewebdevelopment.com/plugins/validation_reflection

This plugin provides reflective access to validations

  • ModelClass.reflect_on_all_validations
  • ModelClass.reflect_on_validations_for(:property)

star_full.gif star_full.gif star_full.gif ValidationReflection (by Yossef)

Homepage: http://www.rubybyraeli.org/blog/articles/2007/04/06/36-reflections-on-validity







Authors: Yossef


Yossef (April 06, 2007). Reflections on Validity (http://www.rubybyraeli.org/blog/articles/2007/04/06/36-reflections-on-validity). Retrieved on 2007-05-11 11:18.


[...] All of these are covered by the Rails built-in validation helpers, but there’s a bit of a catch. That catch is reflection. Ruby is one of those languages where reflection abounds. Rails, built with Ruby, takes advantage of this fact in some areas. It does not, however, when it comes to validation. And that’s yet another problem I have with how Rails handles validation. It’d be so wonderful if there was validation reflection. It’d be so nice to just query a model to see what it considers valid. It’d make a lot of interface problems easier to deal with. It’d make things more DRY. This idea started my journey into the bowels of ActiveRecord validation. My first step this time was to see if anyone else had looked into this. It turns out Michael Schuerig did. He wrote a validation reflection plugin that seemed nice, but it wasn’t exactly what I wanted. That problem seems to come up from time to time. Is it me or everyone else? So I built on his idea, learning a good bit in the process, and came up with something that did what I wanted. ... Some of the differences are cosmetic or more on the line of “syntactic sugar”. [...] And one of the differences is just something I wanted to make it a little more explicit. Where he used a plain MacroReflection object, I created a new class specifically for this purpose: ValidationReflection.

module ActiveRecord::Reflection
  class ValidationReflection < MacroReflection
    attr_accessor :block alias_method :klass, :active_record
    alias_method :attr_name, :name
    alias_method :validation, :macro
    alias_method :configuration, :options
  end
end

As you can see, it’s pretty much the same thing with a few aliases added for convenience. Even if that was the only difference, I’d want to have this class. It’s explicit. I lets me know exactly what type of reflection this is. I mean, there are AssociationReflection and AggregateReflection, so why use the abstract class for validations? I think they deserve more. And, of course, there’s more to this class. It includes another attribute, the block of code that composes this validation. The actual Proc object is stored within the reflection. But why?

Most of my problems with validation have to do with the messiness under the surface. Nothing (Hardly anything) is done centrally. Each individual validation repeats much of the same work done by all the rest: get the options, explicitly get the default message, create a block of code, do something to install the block of code. The actual validation process (simplified somewhat) involves getting a list of these blocks of code, running them, and checking for errors. There’s really no tie between validation-as-idea and validation-as-code. I mean, look at how validations are stored internally.

...


Validates Unchangeable

Have used: no
Rating: star_full.gif star_full.gif star_empty.gif
Homepage: http://locusfoc.us/2007/2/1/validates_unchangeable-plugin
Source code: svn://svn.locusfoc.us/plugins/trunk/validates_unchangeable


As listed in other directories: http://rubyfurnace.com/plugins/validates_unchangeable







http://rubyfurnace.com/plugins/validates_unchangeable

Sometimes you want to allow users to save data only once to a field. For example, Ebay only allows you to change the price of an item if there are no bids and it is within a certain date range. I created the validates_unchangeable for similar situations.

validates_as_email

Have used: yes
Rating: star_full.gif star_full.gif star_full.gif


Source code: https://svn.greenpeace.org/repositories/rails_plugins/validates_as_email






Authors: Ximon Eighteen, Dan Kubb, Thijs van der Vossen


validates_email_format_of

Have used: no. How does this compare to validates_as_email??


Homepage: http://multi-up.ca/code/
Source code: http://multi-up.ca/code/validates_email_format_of/


As listed in other directories: http://rubyfurnace.com/plugins/validates_email_format_of




Authors: Alex Dunae


http://rubyfurnace.com/plugins/validates_email_format_of

Validate email addresses against RFC 2822


Before Assignment: add a before_assignment callback to a belongs_to association

Source code: http://obiefernandez.com/svn/plugins/before_assignment


As listed in other directories: http://rubyfurnace.com/plugins/before_assignment http://wiki.rubyonrails.org/rails/pages/Model+Extensions
Description: * Adds support for a before_assignment callback to belongs_to relationships. Allows validation of the object being assigned to the relationship at the time of assignment, instead of having to depend on validations or before_save callbacks on the parent object.
  • Complements the :conditions option of belongs_to





http://rubyfurnace.com/plugins/before_assignment

Plugin makes it possible to add a before_assignment callback to a belongs_to association, which enables things such as type and validity checking at the time of assignment instead of having to rely on later validation. The idea came up while researching the :conditions option for belongs_to. I realized that Rails doesn’t prevent you from assigning a bogus value—even worse, you will be confused when you try to retrieve it later and nothing is there. Some caboosers argued that this is not needed, because you can check the validity of the assignment as part of the validation rules for the model with the belongs_to association. To which I say: “Not always!” Sure, there might be cases where it makes sense to check the validity of an assignment to belongs_to as part of the validation routines of the model. But in cases where a wrong assignment is NOT a state that is reachable normally by the end user, then I believe that it is better to fail fast! If there is a programmer error or a hacker trying to breach my security, I want to know about it right away and in an explicit fashion. Example:

class Approvable < ActiveRecord::Base
  belongs_to :approver,
             :class_name => 'User',
             :foreign_key => 'approver_id',
             :conditions => ['authorized_approver = ?', true],
             :extend => CheckApproverExtension  
end
module CheckApproverExtension
  def before_assignment(approver) 
    raise UnauthorizedApproverException unless approver.authorized_approver 
  end
end

Note: Rails (as of rev 5523) supports extension (:extend =>) of a belongs_to association, but it isn’t documented. I believe that it’s perfectly valid to extend a belongs_to relationship, and that belongs_to should accept a block parameter for extension methods, exactly how other associations do.

Name Nanny

Categories/Tags: [Censoring (category)] [Filtering offensive content (category)] [Bleeping (category)] (Useful for but not limited to: [Users (category)] [Sign-up forms (category)] [User registration/enrollment (category)])
Homepage: http://locusfoc.us/2007/2/13/name-nanny-plugin
Source code: svn://svn.locusfoc.us/plugins/trunk/name_nanny/


As listed in other directories: http://rubyfurnace.com/plugins/name_nanny






http://locusfoc.us/2007/2/13/name-nanny-plugin

I needed functionality to encourage user’s to be on their best behavior when they choosing a username or filling out a form. Bad behavior can come in many forms but specifically, I wanted to prevent people from registering usernames like “administrator”, “root”, “abuse”,”support” etc. I also didn’t want people to pick names like “whore” or even “hoar”,”h0ar”,”wh0r3” (you get the picture). It occurred to me that others would like this functionality too, so I created the name_nanny plug-in which can be employed in a couple of ways. In the model you can use:

  validates_wholesomeness_of :login

This will check the login against values in two text files in the plug-in directory “badwords.txt”, and “restrictedwords.txt”. By default a match returns an non-descript error like “this username is already taken”. I chose a generalized error to dissuade users from trying to hack around the filter and find a word i missed.

If you are filtering the body of text you may want to allow words like “administrator” in the body of the document. Therefore namenanny has a second method called “bleeptext”, which you can use thusly:

  def before_save
    %w(description, title, author, tags).each do |column| 
      if self[column.to_sym]
        self[column.to_sym] = bleep_text(self[column.to_sym])
      end
    end
  end

A sample output might look like this:

p = Post.new
p.description = "Step two: put your dick in a box."
p.save
puts p.description # => "Step two: put your bleeep in a box."
 
 


Rails plugins / Controller-level edit

[model-level (category)]/[controller-level (category)]

star_full.gif star_full.gif star_empty.gif Acts As Image

This plugin takes a simple approach to saving images. It will scale images and save them to the file system, but it can’t be used to save other types of files. It can handle all the types of images that RMagick can, and will differentiate between normal images and animations, saving them as JPEG and GIF respectively. You can specify as many different sizes as you want and whether they will be scaled or cropped.

You can control which path the images will be written to, and what sizes the image will be resized to. Here’s an example model definition:

  class Image < ActiveRecord::Base

    acts_as_image #Must come first

    self.image_sizes = {
      :original => '100%x100%',
      :large => '>800x600',
      :medium => '>640x480',
      :small => '>320x200',
      :thumb => ['100x100!', :crop]
    }

    self.image_save_path = File.join(RAILS_ROOT, 'public', 'images', 'uploads')
    self.image_read_path = ['images', 'uploads'].join('/')

  end

[model-level (category)]/[controller-level (category)]: [Syndication (category)] (RSS/Atom)

Resource Feeder

Example [13]:

module Awesome::Controllers

  class FeedMe 
    include ResourceFeeder::Atom

    def get
      @things_to_eat = ThingsToEat.find(:all, :limit => 15, :order => "created_at DESC")
      @things_to_eat = [ThingsToEat.new(:title=>"No results", :id => 0)] if @things_to_eat.blank?
      @headers['Content-Type'] = "application/xml"
      atom_feed_for @things_to_eat, 
        {:feed => {:title => "Things to eat 4 u", # feed title
                    :ttl => 40}, # time-to-live in minutes
         :items => {:title => :title,
                    :pub_date => :created_at}}
    end


[model-level (category)]/[controller-level (category)]: Web services / REST

rc-test

http://seattlerb.rubyforge.org/rc-rest/

This is an abstract class for creating wrappers for REST web service APIs.

PayPal plugin

http://www.elctech.com/ruby/paypal/README

Acts As Amazon

http://rubyfurnace.com/plugins/acts_as_amazon

ActsAsAmazon allows a developer to declare a mapping between an ActiveRecord model and a product listed on Amazon. It uses the Ruby/Amazon library to add functionality so that models can be created from a search (by ASIN) through the amazon e-commerce services and provides directives to describe how database fields map to the data in a Ruby/Amazon SearchResult object.

Amazon in Red

Project/Development: http://rubyforge.org/projects/air/


Description: Seeing the Amazon Web Services (AWS) through Ruby--a pure Ruby API for AWS.





Maps: Google Maps

http://jystewart.net/process/archives/2006/09/abstracting-mapping-with-ym4r

http://thepochisuperstarmegashow.com/2006/06/02/ym4r-georuby-spatial-adapter-demo/

http://rubyfurnace.com/plugins/gmaps-on-rails Google Maps on Rails

Project/Development: http://rubyforge.org/projects/cartographer/







[model-level (category)]/[controller-level (category)]: E-commerce

Overlaps with Web services? A little bit, perhaps...

See Rails / E-commerce

[model-level (category)]/[controller-level (category)]: Authentication

acts_as_authenticated

Have used: Yes.
Rating: star_full.gif star_full.gif star_empty.gif


Documentation: Wiki
Source code: http://svn.techno-weenie.net/projects/plugins/acts_as_authenticated



Description: Acts As Authenticated is a simple authentication generator plugin for Ruby on Rails.





Installing

> ./script/plugin install http://svn.techno-weenie.net/projects/plugins/acts_as_authenticated
...

> ./script/generate authenticated USERMODEL CONTROLLERNAME
> ./script/generate authenticated user account
      create  app/models/user.rb
      create  app/controllers/account_controller.rb
      create  lib/authenticated_system.rb
      create  lib/authenticated_test_helper.rb
      create  test/functional/account_controller_test.rb
      create  app/helpers/account_helper.rb
      create  test/unit/user_test.rb
      create  test/fixtures/users.yml
      create  app/views/account
      create  app/views/account/index.rhtml
      create  app/views/account/login.rhtml
      create  app/views/account/signup.rhtml
      create  db/migrate/002_create_users.rb
> rake db:migrate

Customizing

Changes I like to make:

  • %s/login/username/cg in db/migrate/*_create_users.rb app/views/account/*.rhtml app/models/user.rb
  • login => log_in, logout => log_out
  • app/views/account/login.rhtml : Have a link to sign_up in case they don't yet have a login. (Useful if other pages link directly to the login page.)
  • Modify current_user to return nil if they are not logged in instead of :false. It just seems wrong that I can write this code and it will break because :false will evaluate to true: current_user.name if current_user. I can't think of any drawbacks to switching to nil, and it seems like a much more sensible way to go...
<p>
  Don't have an account? <%= link_to 'Create one', :controller => 'account', :action => 'signup' %> now.
</p>

I may want to simply create my own derivative plugin that has these changes: http://svn.tylerrick.com/public/rails/plugins/acts_as_authenticated.

To do: Import changes made in http://svn.tylerrick.com/public/projects/personal_tracker .

Using/Configuring

Move from app/controllers/account_controller.rb to app/controllers/application_controller.rb

  include AuthenticatedSystem
  before_filter :login_from_cookie   # "remember me" functionality

What to put in app/views/account/index.rhtml?

<%= flash[:notice] %>

<p>
  Logged in as: <%= current_user.username %>
</p>

<p>
  Existing users:
  <%= User.find(:all).map {|u| u.username } %>
</p>

To require the user to be logged in: before_filter :login_required

To check if the user is logged in: logged_in? returns true or false

To identify the current user: current_user returns User object or :false

store_location

redirect_back_or_default(:controller => '/account', :action => 'index')

In your layout, you probably want some kind of indication of whether the visitor is logged in or not. If they are not, they should see a link to log_in. If they are, they should see a link to log_out. At a minimum, something like this:

  <p>
    <% if logged_in? %>
      Logged in as: <%= current_user.username %>. <%= link_to 'Log out', :controller => 'account', :action => 'logout' %>
    <% else %>
      You are not logged in. <%= link_to 'Log in', :controller => 'account', :action => 'login' %> now.
    <% end %>
  </p>



RoleRequirement

Name: RoleRequirement


Rating: star_full.gif star_full.gif star_empty.gif


Source code: http://rolerequirement.googlecode.com/svn/tags/role_requirement/
Project/Development: http://code.google.com/p/rolerequirement/


Depends on: acts_as_authenticated





http://code.google.com/p/rolerequirement/. Retrieved on 2007-05-11 11:18.


Basic Features:

  • Implement role security system using an enum field or a habtm collection (user can have one or many roles)
  • Full Test Helpers to make it easy to test your controllers.
  • Squeaky Clean implementation so you don't have to repeat yourself.
...
class Admin::Users < ApplicationController
  require_role "admin"
end
class Admin::Listings < ApplicationController
  require_role "contractor"
  require_role "admin", :only => :destroy # don't allow contractors to destroy

  # leverage ruby to prevent contractors from updating listings they don't have access to.
  require_role "admin", :only => :update, :unless => "current_user.authorized_for_listing?(params[:id]) "
end


Restful Authentication

http://rubyfurnace.com/plugins/restful_authentication

This is a basic restful authentication generator for rails, taken from acts as authenticated. Currently it requires Rails 1.2 (or edge). To use: ./script/generate authenticated user sessions The first parameter specifies the model that gets created in signup (typically a user or account model). A model with migration is created, as well as a basic controller with the create method. The second parameter specifies the sessions controller name. This is the controller that handles the actual login/logout function on the site. From here, you will need to add the resource routes in config/routes.rb. map.resources :users, :sessions


OpenID

OpenID  edit   (Category  edit)


http://wiki.rubyonrails.org/rails/pages/OpenID

http://www.openidenabled.com/openid/libraries/ruby/about/

Homepage:  ?


Project/Development: http://dev.rubyonrails.org/browser/plugins/open_id_authentication





Authors: DHH


http://www.bencurtis.com/archives/2007/05/openid-sample-application/

Here’s a follow-up to my instructions on integrating OpenID with ActsAsAuthenticated: a full, sample Ruby on Rails application that provides an example of how to use OpenID. Much like the caboose sample app(s), this is intended to be a good starting point for building your own application with OpenID baked in from the beginning. This OpenID sample application uses DHH’s open_id_authentication plugin, which has been tweaked to not require the current edge Rails. In other words, you can use this application on Rails 1.2.3 without any modifications. I modified the sample controller code from the plugin to automatically create user accounts with an OpenID login, and to only update the SRE fields for the user when first creating an account. I’m also using Rick’s restful_authentication plugin with the activation email observer commented out in environment.rb, and with the User model tweaked to allow accounts to be created without a login and password if the account is created via an OpenID login. The controller code does ask the OpenID provider for a nickname (mapped to login) and email address, but they aren’t required and some OpenID providers may not provide the ability to get that extra data, so you can’t really depend on the OpenID provider to provide those. I’ll leave it as an exercise to the reader to figure out a way to collect an email address if responding to an activation email is desired.


acts_as_google_account

http://rubyfurnace.com/plugins/acts_as_google_account

A plugin for authenticating users objects against the Google Authentication API.

      class User < ActiveRecord::Base end

      acts_as_google_account

      def self.login(username, password)
        if username.include? "@gmail.com" then
            if self.GoogleLogin(username, password) then
                find_by_email(username)
            end
        else
            hashed_password = hash_password(password || "")
            find(:first, :conditions  => ["username = ? and hashed_password = ?", username, hashed_password])
        end
      end

      def try_to_login
        User.login(self.username, self.password)
      end

[Controller-level (category)]

RefreshTo

Project/Development: http://rubyforge.org/projects/refresh-to/


Description: RefreshTo provides a way to redirect from a secure (SSL) page to an insecure page, without seeing an annoying security warning in some browsers. It adds two methods to the Rails controller system: refresh_to and refresh_back_or_default.





double_submit_protection

http://rubyfurnace.com/plugins/double_submit_protection

This plugin prevents multiple submits by intercepting requests with identical parameters.

[Controller-level (category)]: SSL

ssl_requirement

Rating: star_full.gif star_full.gif star_full.gif


Documentation: Readme



As listed in other directories: http://agilewebdevelopment.com/plugins/ssl_requirement
Description: This plugin lets you declare which actions you want to be accessed via https.



Authors: DHH


If your server doesn't let you set HTTP_X_FORWARDED_PROTO, you can rely on port number instead

This is a [patch (category)] to the ssl_requirement plugin.

http://kb.mediatemple.net/article.php?id=252. Retrieved on 2007-05-11 11:18.

[...] because mod_rewrite doesn't set the HTTP_X_FORWARDED_PROTO header when making the request over to mongrel, the Rails (and the ssl_requirement plugin) can't determine if the request was made over https. To make the ssl_requirement plugin function correctly, replace the ensure_proper_protocol method (ssl_requirement.rb, line 49) with the following (changes highlighted): def ensure_proper_protocol return true if ssl_allowed? if ssl_required? && !(request.ssl? || request.port == 443) redirect_to "https://" + request.host + request.request_uri return false elsif (request.ssl? || request.port == 443) && !ssl_required? redirect_to "http://" + request.host + request.request_uri return false end end The new method extends the check to see if the request came in on port 443, which would mean it's an SSL request.


secure_actions

Rating: star_full.gif star_empty.gif star_empty.gif


Documentation: Readme



As listed in other directories: http://agilewebdevelopment.com/plugins/secure_actions




Authors: Ian Warshak



Caveat: causes default_url_options to always generate full URLs, which can affect caching

http://svn.ianwarshak.com/plugins/secure_actions/README. Retrieved on 2007-05-11 11:18.

This plugin generates overrides default_url_options to *always* generate full urls instead of relative urls. Otherwise we would never be able to switch modes from http -> https. So if are linking to a secure action with link_to, the link you get is an https:// link. The one issue that I have found with this approach is that page caching relies on url_for to generate the location on the filesystem for the cached pages.


Comparison

I think I prefer ssl_requirement over secure_actions for most cases, because it is simpler and it doesn't have the caveat that secure_actions has.

And I honestly don't understand the benefit/necessity of having it change the links to the secure pages to be https instead of http so that it doesn't need to redirect once the user arrives at the page (since they'd normally arrive there with http).

http://svn.ianwarshak.com/plugins/secure_actions/README. Retrieved on 2007-05-11 11:18.

The benefit to this is: If you are only relying on the http to https redirection for security then by the time you are redirecting the user to use https, data has already been transmitted insecurely.

What "data" has been transmitted insecurely?

Request:
GET http://example.com/some_page
(no data)

Response:
Location: https://example.com/some_page
(no data)

Request (using SSL):
GET https://example.com/some_page
(no data)

Response (using SSL):
(the contents of the page -- possibly a form, where the user will enter in confidential information)

Request (using SSL):
(some confidential/private/top-secret data, transferred securely using SSL)

I fail to see how that is a problem.

[Controller-level (category)]: Sessions/cookies

CookieStore

http://rubyfurnace.com/plugins/cookiestore

This is a session store for Rails that store the session data in the session cookie itself instead of storing an ID in a cookie and relying on external storage to store the data.

Authenticated Cookie

Homepage: http://www.mathewabonyi.com/articles/2006/07/29/authenticated-cookie-safe-fast



As listed in other directories: http://rubyfurnace.com/plugins/authenticated_cookie






http://rubyfurnace.com/plugins/authenticated_cookie

The system introduced by Technoweenie in his Acts as Authenticated design is quite good, but unfortunately it relies on sessions and it is the author’s opinion that doubling the cookie and sess_id is just plain foolish. If you are interested in doubling the speed of your application by going session-less, follow the instructions in this article.

http://www.mathewabonyi.com/articles/2006/07/29/authenticated-cookie-safe-fast

Before anyone balks at this form of authentication, take just a second to think what storing a session ID is doing… that’s right. The same bloody thing. So why waste so much memory, CPU, table space and requests/sec to reprocess whether someone is logged in.

Permanency (“[Remember me (category)]”)

The implementation is a trifle. For the User model, add a custom expiry time to create_login_key which is much longer if the user wants to be remembered. Add ‘attr_accessor :remember’ and ‘def remember?; @remember != “0”; end’ to User and add a f.check_box :remember to your login view. Be sure to pass the value of :remember from new users to authenticated users. That’s all.

Comments:

  • Maybe I'm just missing something, but I don't see what this gains us. This implementation still does a table lookup (in the users table, on the login_key stored in cookies[:ack])... so how is it any faster again? — Tyler (2007-03-12 14:57)

star_full.gif star_full.gif star_empty.gif EdgesoftNoCookie [cookieless sessions (category)]

http://rubyfurnace.com/plugins/edgesoftnocookie

This plugin provides no-cookie session support for Rails applications.

[Controller-level (category)]: [Form processing (category)]

Rails plugins and libraries / Model validation and form processing  edit


[Controller-level (category)]: [Caching (category)]

fragment_cache_extensions

http://rubyfurnace.com/plugins/fragment_cache_extensions

The extended_fragment_cache plugin provides content interpolation and an in-process memory cache for fragment caching. It also integrates the features of Yan Pritzker's memcache_fragments plugin since they both operate on the same methods.

Versioned URLs

http://rubyfurnace.com/plugins/versioned_urls

Makes it easy to improve the cache-efficiency of a Rails website, completely eliminating repeat HTTP requests for things like javascript files and stylesheets until they actually change.

http://blog.dannyburkes.com/2006/11/2/versioned-urls-for-rails/

One of the great "for free" features in Rails is asset timestamping. This feature, built into most of the methods in ActionView::Helpers::AssetTagHelper, automatically appends the timestamp of the referenced asset to generated URLs. So, when you write something like

<%= javascript_include_tag 'application' %>

it actually generates something like this

<script src="/javascripts/application.js?1161807361" type="text/javascript"></script>

where the 1161807362 parameter is the file modification time for /javascripts/application.js.

The theory is that, as long as applicaiton.js remains unchanged, the timestamp and URL remain the same, and the browser caches application.js. When application.js changes, the timestamp and URL change, and the browser refetches application.js. But, in fact, this is just the theory- not the reality.

In reality, the browser only halfway caches application.js. When the browser encounters the next

<script src="/javascripts/application.js?1161807361" type="text/javascript"></script>

it will actually send an HTTP GET request for /javascripts/application.js?1161807361, but it will include an If-Modified-Since header to notify the server that it should only return the requested data if it has changed since it was last requested. If application.js hasn't changed, the server sends a 304 Not Modified response, with no response body.

This is all well and good in that it saves the download time for application.js, but we still pay the TCP setup and teardown time, even when the asset hasn't changed. For many web applications, the number of javascripts, stylesheets, images, etc., included via asset tags is quite large. Thus, the cumulative penalty we pay in TCP setup/teardown to request unchanged assets can grow to a significant (read- noticeable) amount.

...

[...] The main issue is that some browsers will not cache resources referenced by URLs that contain parameters (e.g.- ?1161807361). What we need is a way to move the asset version token into the path part of the URL. In other words, we need to produce code like this:

<script src="/javascripts/application.js.v1161807361" type="text/javascript"></script>

...

But, with versioned URLs, the server will receive requests for things like /javascripts/application.js.v1161807361, which it has no idea how to satisfy.

How can we solve this? We can use URL rewriting.

...

This tells lightty to interpret a request for /javascripts/application.js.v1161807361 as a request for /javascripts/application.js, so, everyone is happy again.

[Controller-level (category)]/[View-level (category)]

RTRails: RealTime on Rails

Source code: cvs -d :pserver:anonymous@rubyforge.org:/var/cvs/rtrails checkout
Project/Development: http://rubyforge.org/projects/rtrails/


Description: A RoR app using Ajax HTTP streaming to update browsers from the server. Includes: A HTTPD for mediating the push connections, a JS Window system and two demo apps: Chat/IM with rich text editing (Dojo) MP3 player with shared playlist (using AFLAX).





Juggernaut

Categories/Tags: [Push server (category)]
Homepage: http://rubyfurnace.com/plugins/juggernaut
Source code: svn://rubyforge.org//var/svn/juggernaut/trunk/juggernaut


As listed in other directories: http://rubyfurnace.com/plugins/juggernaut
Depends on: Adobe Flash player





http://juggernaut.rubyforge.org/

The Juggernaut plugin for Ruby on Rails aims to revolutionize your Rails app by letting the server initiate a connection and push data to the client. In other words your app can have a real time connection to the server with the advantage of instant updates. Although the obvious use of this is for chat [a la meebo.com], the most exciting prospect is collaborative cms and wikis.

  • Allows a real time connection with a client - Rails can literally push javascript in real time to the client which is then evaluated.
  • Push server - written in Ruby.
  • Integrated, as a plugin, into Rails.
  • Subscribers can subscribe to multiple channels, and broadcasters can broadcast to multiple channels. Channels are sent as a base64 encoded array - from the session.
  • Uses Flash 6 - installed on more than 95% of computers.
  • Supports all the major browsers (uses fscommand): Firefox 1+, IE 6+ and Safari 2+.

PDF Render

http://rubyfurnace.com/plugins/pdf_render

"Hierarchical Access" / PersistentCheckBox / PersistentOption

http://rubyfurnace.com/plugins/hierarchical_access

PersistentCheckBox appears to load its value from the session (session["#{option}::#{name}"]) and uses onClick to set the value using Ajax.

PersistentOption actually handles the creation of the the set_whatever action method of the controller that gets called by the checkbox's onClick.

WithHierarchicalAccess appears to simply be a helper module that lets you access the session (or any other Hash?) "hierarchically" -- session["level1::level2::key"]. Not sure why that's necessary, though, considering hashes can already be nested.

Feeds

Project/Development: http://rubyforge.org/projects/feeds/


Description: Feeds is an open source Ruby on Rails feed reader application. Features include: No full-page reloads, 2 different views, publish a RSS feed of starred items, search function, import OPML, sortable tree of feeds, complete unread counts for each feed





[Controller-level (category)]/[View-level (category)]: Full user-interface solutions for tables/models

Fully-functional alternatives to Rails's scaffolds...


ActiveScaffold

ActiveScaffold edit


Homepage: http://activescaffold.com/
Documentation: http://demo.activescaffold.com/docs/
Source code: http://activescaffold.googlecode.com/svn/tags/activescaffold
Project/Development: http://code.google.com/p/activescaffold/



License: [[:MIT license|MIT license]]




http://activescaffold.com/

  • Generates a production-ready, fully-styled interface for managing models
  • Automatically handles model associations on forms and in the table display (including automatic nested scaffold support)
  • Includes RESTful API that supports XML, YAML and JSON
  • Guaranteed to work on Firefox 1+, IE 6+ and Safari 2+
  • Gracefully degrades when Javascript is not available

How to add revision tracking to your ActiveScaffold

Here's a not very good attempt: http://wiki.activescaffold.com/wiki/show/AuditTrail

http://groups.google.com/group/activescaffold/browse_thread/thread/e934693ee4657fff/4747542d2071ca0b

  1. Install the acts_as_versioned gem.
  2. Create/run migrations for versions tables
  3. Add updated_by and created_by ActiveRecord extension, use either:
  4. Create/run migration to add created_by and updated_by to
<model>_versions tables
  1. Restart and test.
 


Rails Datagrid

Project/Development: http://rubyforge.org/projects/rails-datagrid/


Description: A full-featured (unobtrusive) Ajax-Datagrid for Rails. - Uses to UJS to fall back to a javascript-free paginated table when javascript is not available - Can sort and filter your dataset - With activated Javascript: just scroll through your data




Readiness: Registered: 2007-01-26 03:17, This Project Has Not Released Any Files 2007-03-23 17:25


Scaffolding Extensions

Adds limited has_and_belongs_to_many support.

Scaffolding Extensions Tutorial in Ruby on Rails

http://wiki.rubyonrails.org/rails/pages/Scaffolding+Extensions+Plugin

How to use Scaffolding Extensions as a generator

Toffee

http://rubyfurnace.com/plugins/toffee

Toffee is a Rails Plugin that allows management of Active Record models without the need for extra controllers/views. Say for example you had a very-normalized application, with dozens of simple tables with just a few simple fields or relations, then the last thing you want is dozens of controllers

Lance 2007-03-06:

It's neat that they don't need controllers to exist. But they have pretty limited use because of it - you can't customize the model presentation for different situations. It's purely for admin use, like the routing suggests.

autoDB Admin Console

Source code: http://svn.visualjquery.com/admin_console/trunk/admin_console/vendor/plugins/admin_console/
Project/Development: http://trac.visualjquery.com/admin_console
As listed in other directories: http://rubyfurnace.com/plugins/autodb_admin_console






http://rubyfurnace.com/plugins/autodb_admin_console

AdminConsole is an application that allows you to quickly and easily get a CRUD interface for any ActiveRecord model. It supports:

  • Associations
  • Configurable forms
  • A slew of widgets, including:
    • file-uploads and images (via iframes)
    • regular text boxes
    • time select boxes (via my own plugin)
    • date select boxes
    • checkboxes for boolean columns
It uses:
  • AJAX
  • Information that’s already in your models


Streamlined

http://streamlined.relevancellc.com/

Pretty nice, handles has_many relationships... But it's generated code.

 


Presentation-level (model-level? view-level?)

Rails / ModelFormatter plugin edit

ModelFormatter

Formatting stuff in and out of the models

Homepage: http://brad.folkens.com/formatting-data-in-rails-models
Source code: https://hattenschwetter.com/svn/hattenschwetter/rails_plugins/model_formatter/trunk


As listed in other directories: http://agilewebdevelopment.com/plugins/modelformatter




Authors: Brad Folkens


http://agilewebdevelopment.com/plugins/modelformatter

The ModelFormatter module allows you to easily handle fields that need to be formatted or stripped of formatting as the are set or retrieved from the database. You can designate one or more of your columns as "formatted columns" like in this example:

  class Widget < ActiveRecord::Base
    # Set an integer field as a symbol
    format_column :some_integer, :as => :integer

    # Specify the type as a class
    format_column :sales_tax, :as => Formatters::FormatCurrency
    format_column :sales_tax, :as => Formatters::FormatCurrency.new(:precision => 4)

    # Change the prefix of the generated methods and specify type as a symbol
    format_column :sales_tax, :prefix => 'fmt_', :as => :currency, :options => {:precision => 4}

    # Use specific procedures to convert the data +from+ and +to+ the target
    format_column :area, :from => Proc.new {|value, options| number_with_delimiter sprintf('%2d', value)},
                         :to => Proc.new {|str, options| str.gsub(/,/, '')}

    # Use a block to define the formatter methods
    format_column :sales_tax do
      def from(value, options = {})
        number_to_currency value
      end
      def to(str, options = {})
        str.gsub(/[\$,]/, '')
      end
    end

    ...
  end

Brad Folkens. Formatting data in Rails Models (http://brad.folkens.com/formatting-data-in-rails-models). Retrieved on 2007-05-03 14:04.

[...] We’ve got lots of database columns that need to be formatted/un-formatted. View helpers are great for formatting things on the way out, but what happens when users need to enter that data in the same format, or in an auto-detected format? To begin, take our Widget example, with a column called weight. Weight is just an integer and we want it formatted all pretty, so we use a helper. But later we decide the user needs to enter data using the same format, so the controller accepts the input and can strip it, or we can throw that in the model too. Eventually though, we end up with a lot of the same code, un-formatting things in a model or controller that we’ve formatted already in the view. Seems a little un-DRY to me… Ideally, we’d have this code formatting stuff on the way into and out of a model, as with something like the code below:

class Widget < ActiveRecord::Base
  include ActionView::Helpers::NumberHelper

  def formatted_weight
    number_with_delimiter weight
  end

  def formatted_weight=(value)
    weight = value.nil? ? nil : value.gsub(/,/, '').to_i
  end
end

Ok, not so bad – we’ve got some basic stuff in place to format an attribute in the model and then something to accept formatted text, un-format it and set the weight attribute.

...

Install the model_formatter:

script/plugin install -x \
  https://hattenschwetter.com/svn/hattenschwetter/rails_plugins/model_formatter/trunk/

Then we can change our Widget to the following:

class Widget < ActiveRecord::Base
  format_column :weight, :as => :integer
end

[...] Now, what happens when we want to change the way weight is formatted? Let’s pass some options.

format_column :weight, :as => :integer, :delimiter => '.'

Now, instead of formatting our weight with something like 1,425,321 we return 1.425.321. You can pass options like this to all the formatters (and custom formatters too, as you’ll see further down). For example, the :decimal formatter takes :precision and the :currency formatter just passes options on the number_to_currency – so all your freedom is preserved.

Each formatter is just a small class which extends Formatters::Format. The super class contains a very simple set of methods: initialize, from, and to. It names the formatters, by default, with the ‘formatted_’ prefix [It gives you both a formatted_weight reader and a formatted_weight= writer.]. [...]

So far, all we’ve used are the included formatters in the Formatters module, which are conveniently resolved with the symbolized shortcuts. So for example, :as => :integer expands to Formatters::FormatInteger. Fortunately, we can provide any Formatters::Format code to model_formatter in the same way as the shortcuts:

format_column :weight,
  :as => Formatters::FormatInteger.new(:delimiter => '.')

So there it is, the simple way to format things coming out of and going back into the model. We can customize the model_formatter even more though.

What if we wanted to provide our own formatting functionality? Easy – we can do this several different ways. Either provide a class like the above, or you can provide a Proc directly:

format_column :weight,
  :from => Proc.new {|value, options| number_with_delimiter(value) + 'lbs.'},
  :to => Proc.new {|str, option| str.gsub(/,/, '')}

[We can] do the same thing with a block.

format_column :weight do
  def from(value, options = {})
    number_to_delimiter value
  end
  def to(str, options = {})
    str.gsub(/,/, '')
  end
end

We already know we can do things like the following to our Widget instance:

>> widget.weight = 1000
=> 1000
>> widget.formatted_weight
=> 1,000
>> widget.formatted_weight = '1,100'
=> '1,100'
>> widget.weight
=> 1100

[...] We typically need to do things which access the same formatters, but not necessarily through an instantiated [model] object. When the format_column method accepts our :as => :integer option, it creates an instance of the integer formatter. If you’ve specified a Proc pair or a block, you still get the same benefits, since it will wrap your Procs or block and expose them in a similar way, using (in our :to and :from, or block custom example) a CustomFormatWeight class. With the block, you get the added benefit of optionally adding an initialize method. In any case, you can access this formatter class in the following way:

>> Widget.formatted_weight_formatter 1000
=> 1,000
>> Widget.formatted_weight_unformatter '1,100'
=> 1100

You can also access the options passed to the formatter directly, which can be very helpful to piggy-back meta attributes with an attribute. See the :display_size option:

>> Widget.formatted_weight_formatting_options
=> {:to=>nil, :from=>nil, :options=>{},
:prefix=>"formatted_", :as=>:integer, :display_size => '12pt',
:formatter=>#<Formatters::FormatInteger:0x2601110 @delimiter=",">,
:formatted_attr=>"formatted_weight", :attr=>"weight"}
 


Rails plugins and libraries / View-level edit

[View-level (category)]

Presentation layer. Includes presentation logic. Includes layouts...

star_full.gif star_full.gif star_empty.gif RecordSelect

Project/Development: http://code.google.com/p/recordselect/


Description: Rails plugin to replace <select> boxes with a paginated, searchable list.



Authors: Lance Ivy


http://code.google.com/p/recordselect/. Retrieved on 2007-05-11 11:18.


This plugin is a streamlined listing tool with a dedicated purpose: to let you select a record from a possibly large record set in a friendly fashion. It will report the selected record(s) to a given method on the controller or to a JavaScript function on the client. Included is a +link_to_record_select+ helper to assist with embedding a RecordSelect popup in your page. Also included is a +record_select_field+ helper. This helper ties RecordSelect into your form by making it set a hidden input field. Think of it as a paginated and searchable autocomplete dropdown. Or think of it as a <select> replacement that won't bog down with large recordsets. ...

  class UsersController < ApplicationController
    record_select :per_page => 5, :search_on => 'username'
  end


star_full.gif star_full.gif star_full.gif Simply Presentable

Source code: script/plugin install http://richcollins.net/svn/simply_presentable/
Project/Development: http://rubyforge.org/projects/presentable/


Description: Simply Presentable wraps user defined presenter objects around models so you can get helper-like functionality in an OO style: present!(foo); foo.url, foo.form, ... etc. MVC principles are preserved as the implementation of your model is not altered.




Readiness: Registered: 2007-01-05, This Project Has Not Released Any Files 2007-03-23


http://wiki.rubyonrails.org/rails/pages/Model+Extensions

Save keystrokes and stay DRY with SimplyPresentable:

< present!(foo).form do |f| >
  <= f.text_field :bar >
< end >

Instead of

<% form_for(
     foo.new_record? ? {
       :url => 'http://example.com/foos',
       :html => { :method => 'post', :id => 'new_foo', :class => 'new_foo' }
     } :
     {
        :url => "http://example.com/foos/#{foo.id}",
        :html => { :method => 'put', :id => 'foo_1', :class => 'foo' }
      } :
    ) do |f| %>
  <= f.text_field :bar >
< end >

SimplyPresentable is a plugin for that introduces the idea of presenters to Rails.

star_full.gif star_empty.gif star_empty.gif Resource on Demand

Homepage: http://agilewebdevelopment.com/plugins/resource_on_demand
Documentation: Readme
Source code: http://svn.devjavu.com/liquid/resource_on_demand/lib/resource_on_demand.rb the meat



Description: This includes javascript and stylesheet information for external resource files from anywhere in your views as needed. These can be deeply nested in partials or in layouts. The stylesheets/javascripts are only included if you have requested them in your view somewhere.



Authors: Daniel Neighman


Within the head tag of the layout:

<%= require_on_demand %>

Then from anywhere in you views or partials:

<% require_javascript "my", "javascript", "files", :defaults %>

This will add the specified javascripts and to the head tag without duplicates.

<% require_stylesheet 'my_stylesheet' %>

MenuEngine

Categories/Tags: [Engine (category)]
Homepage: http://www.muermann.org/ruby/menu_engine/
Documentation: http://www.muermann.org/ruby/menu_engine/
Source code: http://svn.rails-engines.org/plugins/menuengine


As listed in other directories: http://rubyfurnace.com/plugins/menuengine






http://www.muermann.org/ruby/menu_engine/

MenuEngine is a small Rails engine that can generate templated drop-down DHTML menus commonly used for web site navigation. screenshot MenuEngine supports creation of menus from a YAML file, from code and from pre-configured HTML. The javascript library can also be used outside of Rails.

Sample code [15]:

---
- !ruby/object:MenuItem 
  controller: users
  action: list
  items: []
  - !ruby/object:MenuItem 
    text: List
    controller: users
    action: list
  - !ruby/object:MenuItem 
    text: New User<br/><span style=%"font-size:80%">Add a new user</span>
    controller: users
    action: new
- !ruby/object:MenuItem 
  controller: images
  items: []
  - !ruby/object:MenuItem 
    text: View Images
    controller: images
    action: list

or:

<div id="item_0">
        <%=link_to "Menu Item 0", :controller=>'some_controller' %>
        <div id="sub_menu_0_0">
                <div id="item_1"><%=link_to "Menu Item 1", :controller=>'some_controller', :action=>'list' %></div>
                <div id="item_2"><%=link_to "Menu Item 2", :controller=>'some_controller', :action=>'new' %></div>
        </div>
</div>
<div id="item_0">
        <%=link_to "Menu Item 3", :controller=>'some_other_controller' %>
</div>

<script>
        <%= menu_item 'item_0' %>
                <%= sub_menu 'sub_menu_0_0', 'item_0' %>
                <%= menu_item 'item_1', 'item_0' %>
                <%= menu_item 'item_2', 'item_0' %>
        <%= menu_item 'item_3' %>
</script>

Client-Side Validation

Source code: svn://rubyforge.org//var/svn/clientsidevali/client_side_validation/trunk


As listed in other directories: http://rubyfurnace.com/plugins/client_side_validation
Description: The plugin reflects validations to generated HTML elements and comes with a client-side JavaScript validator.
Depends on: Validation Reflection plugin



Authors: Michael Schuerig


http://rubyfurnace.com/plugins/client_side_validation

This plugin is only a tool, it leaves some work for you to do. The plugin happily handles the validation part, but it is your job to handle the notification. Let’s look at the simplest case first. In public/javascripts/application.js put: Form.Validator.installForAllValidatedForms(); This installs a validator for each form on the page which has the class “validated”. If any of the form’s input elements are or become invalid, they are marked with the class “invalid”. If you have something like this .invalid { border: 1px solid #f00; } somewhere in your stylesheet(s), invalid fields will be marked with a red border. This works for

  •  :validates_presence_of
  •  :validates_length_of
  •  :validates_numericality_of
  •  :validates_inclusion_of
  •  :validates_format_of – as far as regular expressions are matched the same in Ruby and JavaScript

Redbox

As listed in other directories: http://rubyfurnace.com/plugins/redbox , http://www.agilewebdevelopment.com/plugins/redbox






http://rubyfurnace.com/plugins/redbox

Redbox is a very simple lightbox library, which is a way of displaying a modal popup window which may contain any HTML, while the rest of the page is faded out behind it.

NestedLayouts

Plugin allows to specify outer layouts for particular layout thus creating nested layouts. Let’s assume you have controller which action ‘hello’ just was called. Controller was set up to use ‘inner’ layout:

  app/controllers/hello_controller.rb

    class HelloController < ApplicationController
      layout 'inner'

      def hello
        render :text => 'Hello, world!'
      end
    end

  app/views/layouts/inner.rhtml

    <% inside_layout 'outer' do -%>
      <div class="hello">
        <h1>Greetings</h1>
        <%= yield %>
      </div>
    <% end -%>

  app/views/layouts/outer.rhtml

    <html>
    <body>
      <div class="content">
        <%= yield %>
      </div>
    </body>
    </html>

Result will look like this (formatted for better reading):

    <html>
    <body>
      <div class="content">
        <div class="hello">
          <h1>Greetings</h1>
          Hello, world!
        </div>
      </div>
    </body>
    </html>

Concept of layout nesting here is based on the assumption that every inner layout is used only to customize it’s outer layout and thus every inner layout is used only with one specific outer layout. With this in mind we can conclude that every layout must know its outer layout and thus information about outer layout must be embeded directly into inner layout. Controller doesn’t need to know about the whole stack of layouts, so you should just specify the most inner layout in it. Passing data

You can pass data from inner layout to outer one, e.g.:

  layouts/inner.rhtml

    <% content_for 'menu' do -%>
      <ul>
        <li><a href="about_us">About Us</a></li>
        <li><a href="products">Products</a></li>
      </ul>
    <% end -%>

    <% inside_layout 'outer' do -%>
      <% @other_data_for_outer_layout = 'foo' -%>
      <%= yield %>
    <% end -%>

  layouts/outer.rhtml

    <%= yield 'menu' %>
    <br/>
    The data was: <%= @other_data_for_outer_layout %>
    <br/>
    <%= yield %>

star_full.gif star_full.gif star_full.gif ErbBuffer: Painless Nested output buffering [ERb (category)]

<% @contents_surface = capture_buffer do %>
        Top level goodies
        <% @contents_shallow = capture_buffer do %>
                Mid level content
                <% @contents_deep = capture_buffer do %>
                        deeper deeper, i say, deepah
                <% end %>
        <% end %>
<% end %>

<%= @contents_surface %>
<%= @contents_shallow %>
<%= @contents_deep %>

star_full.gif star_empty.gif star_empty.gif Elemental: Call XHTML elements as methods in your ERb templates [ERb (category)]

http://rubyfurnace.com/plugins/elemental

Call XHTML elements as methods in your ERb templates:

<%= p @item.content %>
becomes
<p>Your Content</p>


<%= span "some content", :id => "54" %>
becomes
<span id="54">some content</span>


<% ul do ['one', 'two', 'three'].each do |item| %>
  <%= li item %>
<% end end %>

becomes

<ul>
  <li>one</li>
  <li>two</li>
  <li>three</li>
</ul>

[autocompletion (category)]: select_autocompleter

http://rubyfurnace.com/plugins/select_autocompleter

Similar to Autocompleter functionality except it pops up a listbox instead of a list. To do an incremental search on the ‘name’ field of the ‘product’ table: In your template:

<%= text_field_with_select_auto_complete :product, :name, {}, { :row_count => 4, :min_chars => 2, :redirect_url => {:action => ‘show’, :id => ’??’}} %>

In your controller:

select_auto_complete_for :product, :name

Simple Object Tag Generator

http://www.ahgsoftware.com/pages/simple_object

"works just like an ActionView helper, and generates my embed tags intelligently from the filetype that I pass in!"

# In a 'view', with just default parameters
simple_object_tag "/example.mp3"

# with some additional parameters, real ones, and crazy ones..
simple_object_tag "/flashgame.swf",:scale=>"tofit",:junk=>"shizzle"

Shiny Render

Homepage: none
Documentation: This plugin extends the render method of ActionView to allow an additional HTML tag to surround the existing output from rendering a partial with a collection so that an entire logical collection can be rendered on one line.


Project/Development: http://rubyforge.org/projects/shiny-render/







<h1>Greetings</h1>
        <%= yield %>
      </div>
    <% end -%>

  app/views/layouts/outer.rhtml

    <html>
    <body>
      <div class="content">
        <%= yield %>
      </div>
    </body>
    </html>

Result will look like this (formatted for better reading):

    <html>
    <body>
      <div class="content">
        <div class="hello">
          <h1>Greetings</h1>
          Hello, world!
        </div>
      </div>
    </body>
    </html>

Concept of layout nesting here is based on the assumption that every inner layout is used only to customize it’s outer layout and thus every inner layout is used only with one specific outer layout. With this in mind we can conclude that every layout must know its outer layout and thus information about outer layout must be embeded directly into inner layout. Controller doesn’t need to know about the whole stack of layouts, so you should just specify the most inner layout in it. Passing data

You can pass data from inner layout to outer one, e.g.:

  layouts/inner.rhtml

    <% content_for 'menu' do -%>
      <ul>
        <li><a href="about_us">About Us</a></li>
        <li><a href="products">Products</a></li>
      </ul>
    <% end -%>

    <% inside_layout 'outer' do -%>
      <% @other_data_for_outer_layout = 'foo' -%>
      <%= yield %>
    <% end -%>

  layouts/outer.rhtml

    <%= yield 'menu' %>
    <br/>
    The data was: <%= @other_data_for_outer_layout %>
    <br/>
    <%= yield %>

star_full.gif star_full.gif star_full.gif ErbBuffer: Painless Nested output buffering [ERb (category)]

<% @contents_surface = capture_buffer do %>
        Top level goodies
        <% @contents_shallow = capture_buffer do %>
                Mid level content
                <% @contents_deep = capture_buffer do %>
                        deeper deeper, i say, deepah
                <% end %>
        <% end %>
<% end %>

<%= @contents_surface %>
<%= @contents_shallow %>
<%= @contents_deep %>

star_full.gif star_empty.gif star_empty.gif Elemental: Call XHTML elements as methods in your ERb templates [ERb (category)]

http://rubyfurnace.com/plugins/elemental

Call XHTML elements as methods in your ERb templates:

<%= p @item.content %>
becomes
<p>Your Content</p>


<%= span "some content", :id => "54" %>
becomes
<span id="54">some content</span>


<% ul do ['one', 'two', 'three'].each do |item| %>
  <%= li item %>
<% end end %>

becomes

<ul>
  <li>one</li>
  <li>two</li>
  <li>three</li>
</ul>

[autocompletion (category)]: select_autocompleter

http://rubyfurnace.com/plugins/select_autocompleter

Similar to Autocompleter functionality except it pops up a listbox instead of a list. To do an incremental search on the ‘name’ field of the ‘product’ table: In your template:

<%= text_field_with_select_auto_complete :product, :name, {}, { :row_count => 4, :min_chars => 2, :redirect_url => {:action => ‘show’, :id => ’??’}} %>

In your controller:

select_auto_complete_for :product, :name


[Controller-level (category)]/[View-level (category)]: Graphics / graphing

See also: Ruby_libraries#Graphics

ZiYa

http://rubyfurnace.com/plugins/ziya

The ZiYa is a rails charting plugin that is easy to integrate with your existing rails app and provide for amazing charting capabilities.



[View-level (category)]: In the context of [ActionMailer (category)]

Categories/Tags: [ActionMailer (category)][Layouts (category)]
Homepage: http://cardboardrocket.com/archives/2007/1/14/the_action_mailer_layouts_plugin/
Source code: http://svn.cardboardrocket.com/action_mailer_layouts



Description: A plugin that makes it easy to use layouts in your ActionMailer templates



Authors: Alex Wolfe


http://cardboardrocket.com/archives/2007/1/14/the_action_mailer_layouts_plugin/

I've put together a plugin that makes it easy to use layouts in your ActionMailer templates. I found myself writing very un-DRY (wet?) email templates recently and decided it was time to fix that.


[View-level (category)]: Trees

LiveTree

Homepage: http://www.epiphyte.ca/code/live_tree.html
Documentation: RDoc



Description: LiveTree implements a JavaScript/DHTML tree (hierarchical list) widget that can load data asynchronously as-needed (using AJAX). This makes it ideal for cases where the dataset is too large to load to the browser all at once.


License: MIT


Authors: Emanuel Borsboom


[16]

    class FamilyController < ApplicationController
        live_tree :family_tree, :model => :person
        def show_tree
            @root = Person.find(params[:id]);
        end
    end

    <div style="width:300px;height:415px">
        <%= live_tree(:family_tree, {
            :initial_data_root => @root,
            :on_click_item => "alert('You clicked on ' + item.name)",
        }) %>
    </div>

Features

  • Can load data asynchronously as-needed (so only the parts of the tree the user needs are sent to the client).
  • Data can be provided in the HTML page as well, in which case no asynchronous loading is needed, making this widget suitable for standalone client-side use.
  • Ideal for large/deep data sets (such as navigating a file system, or complete table of contents of a book).
  • Intelligently pre-loads parts of the tree that it anticipates the user will want to look at, so delays for the user are minimized.
  • Customizable using CSS, snippets of HTML, event handlers, and many options.
  • Controllable from JavaScript.
  • Supports deep linking - can jump to a part of the tree that has not been loaded yet, and it will search for that item and load its parents.
  • Supports an "active" (highlighted) item.
  • Automatically scrolls the tree so that what the user is interested in is on the screen.
  • Can Use acts_as_tree or acts_as_nested_set model for data from Rails.
  • Easy to integrate into your application.
  • Can be used standalone (client-side only without server support).


[View-level (category)]: Date/time user interfaces / Calendars

DHTML Calendar

Homepage: http://dry.4thebusiness.com/info/dhtml_calendar
Source code: svn://rubyforge.org//var/svn/dhtmlcalendar/dhtml_calendar


As listed in other directories: http://rubyfurnace.com/plugins/dhtml_calendar
Description: Adds Ruby on Rails engine plugin support for “Dynarch DHTML/JavaScript Calendar”



Authors: Edwin Moss


http://dry.4thebusiness.com/info/dhtml_calendar

<%= calendar 'person', 'birthday',
      { :class => 'date' },
      { :firstDay => 1,
        :range => [1920, 1990],
        :step => 1,
        :showOthers => true }
%>

Dynarch DHTML / JavaScript Calendar

http://www.dynarch.com/projects/calendar/

  • Popup or flat DHTML calendar
  • Suitable for selecting date/time

http://www.dynarch.com/projects/calendar/ Demo


datepicker_engine [Engine (category)][Dates and times (category)]

http://rubyfurnace.com/plugins/datepicker_engine

DatepickerEngine is a collection of helpers for creating datepicker boxes in your views. You can create a datepicker popup box like this:

<%= datepicker_popup ‘person’, ‘birthday’, { :class => ‘date’, :field_title => ‘Birthday’, :button_title => ‘Show calendar’ }, { :firstDay => 1, :range => [1920, 1990], :step => 1, :showOthers => true, :cache => true } %>




[View-level (category)]: [Helpers (category)]

Simply Helpful

Categories/Tags: [helpers (category)]


Source code: http://dev.rubyonrails.org/svn/rails/plugins/simply_helpful/


As listed in other directories: http://rubyfurnace.com/plugins/simply_helpful






Various helpers for views.

For example:

<% content_tag_for(:li, @person, :class => “bar”) %>
=>
<li>id=”person_123” class=”person bar”< /li>

Microformat Helper [helper (category)]

Categories/Tags: [helpers (category)][microformats (category)]
Homepage: http://blog.labnotes.org/2006/08/25/microformats-helper-for-ruby-on-rails/
Source code: http://labnotes.org/svn/public/ruby/rails_plugins/microformat_helper


As listed in other directories: http://rubyfurnace.com/plugins/microformat_helper






A helper to output things in standard microformat[17] format.

http://blog.labnotes.org/2006/08/25/microformats-helper-for-ruby-on-rails/

Try it out with an hAtom feed:

<% render_hfeed do
  posts.each do |post|
    render_hentry "post-#{post.id}" do %>
      <%= hentry_title post.title %>
      <%= hentry_content post.content %>
      <p>Published on <%= post.created_on.microformat :published %> by
        <%= hcard :fn=>post.author, :url=>post.author_url, :class=>"author" %>
      </p><%
    end
  end
end %>

The plugin currently provides helper methods for hAtom, basic hCard, and the datetime design pattern.

[View-level (category)]: User-interfaces/form helpers

Helpers for generating form elements for models, etc.

confirmation_field

Categories/Tags: [helpers (category)]
Homepage: http://blog.ardes.com/articles/2006/11/09/rails-plugin-confirmation_field
Source code: http://svn.ardes.com/rails_plugins/confirmation_field


As listed in other directories: http://rubyfurnace.com/plugins/confirmation_field






http://svn.ardes.com/rails_plugins/confirmation_field/init.rb ([View logic is okay sometimes (category)])

Moves the logic of dealing with confirmation fields into the view where it belongs. A confirmation field is a virtual attribute that is used with

  validates_confirmation_of :email

, :email_confirmation being the virtual attribute in the above example.

There's a small but annoying view logic issue with this, when you are presenting an update view of a model with a confirmation attribute, the confirmation field will initially be left blank. When the form is submitted, the above validation will fail, unless the user types in the confirmation field - very annoying for when you're only updating your phone number for example.

This means that you have to write some view logic to deal with this (a worse idea would be to change the *model* to deal with this view issue).

With this plugin you can do this in your views:

  <%= text_field :customer, :email %>
  <%= confirmation_text_field :customer, :email %>

  <%= password_field :customer, :pass %>
  <%= confirmation_password_field :customer, :pass %>

or

  <% form_for :customer, @customer do |f| %>  
    <%= f.text_field :email %>
    <%= f.confirmation_text_field :email %>
  <% end %>

[user interface for associations/lists (category)]: associated_list

Categories/Tags: [helpers (category)]
Homepage: http://blog.craigambrose.com/articles/2006/10/09/associated-list-a-little-has-many-widget-for-rails
Source code: http://www.tinboxsoftware.com/plugins/show/associated_list/


As listed in other directories: http://rubyfurnace.com/plugins/associated_list






http://rubyfurnace.com/plugins/associated_list

If you are producing a form for a rails model object and it has a has_many or has_and_belongs_to_many relationship of some other simple objects (which can be identified by name), then this plugin might be for you. It uses a select box to add items to the list, and delete buttons to remove them. It's all client side, using hidden fields, until you submit the form and it saves the relationships in your model.

Related select forms

Categories/Tags: [helpers (category)]
Homepage: http://retro.dvisionfactory.com/projects/related-select-forms/readme
Source code: svn://dvisionfactory.com/rails/plugins/related_select_forms


As listed in other directories: http://rubyfurnace.com/plugins/related_select_forms






http://retro.dvisionfactory.com/projects/related-select-forms/readme

Example: Two related select forms

tables

car_companies: id, name
car_models:    id, name, car_company_id

view

<%= collection_select(
      :car_company, :id, CarCompany.find(:all), :id, :name) %>
<%= related_collection_select(
      :car_model, :id, [:car_company, :id], 
        CarModel.find(:all), :id, :name, :car_company_id) %>

The code above will create two drop-down select tags. The 1st allows the selection of a car company. Based on this decision the 2nd select tag shows company specific car models.

star_full.gif star_empty.gif star_empty.gif Multiple Select Helper

Categories/Tags: [helpers (category)]
Homepage: http://ruido-blanco.net/blog/rails-multiple-select-helper-plugin
Source code: http://svn.ruido-blanco.net/multiple_select/trunk/


As listed in other directories: http://rubyfurnace.com/plugins/multiple_select_helper






http://rubyfurnace.com/plugins/multiple_select_helper Selecting multiple elements in a list is sometimes tricky. You may click inadvertently on one item of the list and lost all your previous selection. You are forced to use Ctrl (or Command) clicks to select more than one element.

Multiple Select Helper allows you to create an easy-to-use list for multiple selections from array, hashes, collections or trees. The list is built using checkboxes so you can click easily and you will not lost the elements you clicked before. As a drawback you lose the use of the keyboard in the “list”.

This multiple selections are very useful in many to many relationships (has_and_belongs_to_many or has_many :through with no obligatory fields) where a “add and remove” solution would be cumbersome.

Comments:

  • Probably a better (more robust; less finicky; less susceptible due to browser quirks) solution than what we implemented for the Mask (multi-select list box without using Ctrl-Click) — Tyler (2007-03-08 17:10)



[View-level (category)]: [Captchas (category)]

BrainBuster

http://rubyfurnace.com/plugins/brainbuster

BrainBuster is a logic captcha—a test to try and tell computers and humans apart via a simple logic puzzle, math problem, or word problem. The big benefit over typical image based captchas is that a logic captcha is fully accessible for visually-impaired users who use screen readers.


[View-level (category)]: JavaScript/RJS

[View-level (category)]: Alternative templating languages

Template loop detected: Template:Include with edit link

RJS if/unless blocks

Allows you to generate (JavaScript) if/unless blocks in RJS templates

page.if page[element_id].visible do
  page[element_id].hide
end


[View-level (category)]: CSS repetition removers / pre-processors / with embedded Ruby

Comparison

CSS Dryer Nested selectors, variables
RCSS ERB, server-side constants, server-side classes and command line execution. No nesting as such, though server-side classes offer a form of inheritance.
DCSS http://myles.id.au/2006/11/20/introducing-dcss/ . server-side constants, different syntax. Descendant selectors only.
Styleaby Creates CSS with Ruby syntax. “An experimental, unauthorized mashup of Scott Barron’s stillborn Builder::CSS templates and Why The Lucky Stiff’s Markaby templates.”
Dirt Simple .rcss Templates by Josh Susser No nesting, just variables.

(Based on: [18])

star_full.gif star_full.gif star_full.gif CSS Dryer

http://rubyfurnace.com/plugins/css_dryer

Eliminate Repetition In Your Stylesheets Cascading style sheets (CSS) are wonderful but repetitive. Rails strongly discourages repetition, the don’t repeat yourself (DRY) principle, so writing CSS feels ungainly in Rails. There are two sources of repetition in CSS:

  • nested selectors
  • lack of variables
Nested selectors lead to CSS like this:
div           { font-family: Verdana; }
div#content   { background-color: green; }
div#content p { color: red; }

Note the triple repetition of div and the double repetition of #content.

The lack of variables leads to CSS like this:

.sidebar { border: 1px solid #fefefe; }
.content { color: #fefefe; }

Note the repeated color #fefefe.

The CssDryer eliminates both of these sources allowing you to write DRY, pleasing stylesheets. The examples above become:

<% dark_grey = '#fefefe' %>

div {
  font-family: Verdana;
  #content {
    background-color: green;
    p { color: red; }
  }
}

.sidebar { border: 1 px solid <%= dark_grey %>; }
.content { color: <%= dark_grey %>; }


Simple RCSS

Homepage: http://blog.integralimpressions.com/articles/2006/08/20/simplercss-plugin
Source code: http://svn.integralserver.com/plugins/simple_rcss


As listed in other directories: http://rubyfurnace.com/plugins/simple_rcss


Based on: based on code from Josh Susser http://blog.hasmanythrough.com/articles/2006/03/23/dirt-simple-rcss-templates


Authors: Chris Abad


This plugin provides support for RCSS templates to the rails application environment. These operate the same as standard CSS files, but also allow the addition of ERb within the file. ... When run in production mode, it will automatically cache the stylesheets so that the web-server will deliver them in subsequent requests. Or you can pre-cache all of the stylesheets by using the included rake tasks.

DCSS: CSS pre-processor

http://rubyfurnace.com/plugins/dcss

A pre-processor for css that allows you to reduce duplication and simplify your css files. DCSS is also available as a ruby gem.

http://myles.id.au/2006/11/20/introducing-dcss

[...] It becomes problematic as stylesheets start to get larger and more special cases are introduced:

body.home-page #archives h3, body.home-page #favorites h3 { text-align: center; font-family: Georgia, serif; }
body.home-page #archives li, body.home-page #favorites li { list-style: square; }
body.home-page #archives li a, body.home-page #favorites li a { color: green; }
body.home-page #archives li a:hover, body.home-page #favorites li a:hover { color: orange; }

In a situation like the above, adding a class to each element isn’t really an option as these styles should only apply to the home page (which has body element that looks like <body class="home-page">). Plus adding a class still doesn’t add any semantic meaning to the document, it’s a design issue, not a markup one.

DCSS is a small ruby library that solves this problem by extending the CSS syntax with a new construct: {{ }}

body.home-page { } {{
  #archives, #favorites { } {{
    h3 { text-align: center; font-family: Georgia, serif; }
    li { list-style: square; } {{
      a { color: green; }
      a:hover { color: orange; }
    }} 
  }}
}}



[View-level (category)]: Themes/Skins

Vision

http://vision.shopify.com/ Vision - A Designers toolkit for Shopify themes (proprietary)


[Timelines (category)]

Simile Timeline Helper

http://rubyfurnace.com/plugins/similetimelinerailshelper

The Simile Timeline for Rails project provides a set of tools for Ruby generally, and Rails specifically to generate Simile Timeline DHTML controls in pages, and produce and consume events for display within those timelines.

 


Rails plugins / Plugin tools edit

Plugins for creating plugins / plugin tools/extensions / more powerful plugins

Alternative to Engines: plugin_dependencies, loaded_plugins, plugin_migrations, plugin_assets, appable_plugins, and plugin_routing

http://www.pluginaweek.org/2006/12/14/rails-engines-vs-6-plugins/

Our plugins aren’t meant to altogether replace Engines. They are a means of appealing to those who don’t like Engines so that we can all continue to develop plugins that add migrations, models, controllers, helpers, etc. and everyone can use them, engine-lovers and engine-haters alike. If you’ve come so far as to like each of our 6 plugins and use them all together, then this boils down to close to the same functionality that Engines offers.

You can either install them individually or all at once using the "Plugins plus" plugin bundle.

star_full.gif star_full.gif star_full.gif Plugins plus

Homepage: http://wiki.pluginaweek.org/Plugins_plus [19]
Source code: gem install plugins_plus or http://svn.pluginaweek.org/trunk/plugins/rails/plugins_plus








I've been using most of the plugins contained in plugins_plus individually for a while now, so I was excited to see a single plugin that would save me from installing each one individually!

Installation:

gem install plugins_plus

config/environment.rb
  require 'plugins_plus'
  ...
  Rails::Initializer.run do |config|
  ...

Problem: Can't load as gem

[link to mailing list...]

First I tried the gem version, because gems seem the most convenient to me... I started a brand-new Rails application so that there could be no other variables.

 > ./script/about
About your application's environment
Ruby version                 1.8.5 (i386-linux)
RubyGems version             0.9.2
Rails version                1.2.3
Active Record version        1.15.3
Action Pack version          1.13.3
Action Web Service version   1.2.3
Action Mailer version        1.3.3
Active Support version       1.4.2
Application root             /home/tyler/code/applications/t
Environment                  development
Database adapter             mysql

> gem list plugins_plus
plugins_plus (0.1.0)

Following the simple instructions at http://svn.pluginaweek.org/trunk/plugins/rails/plugins_plus/README , I added this near the top of my environment.rb:

  require 'plugins_plus'

This is what I got when I did ./script/server:

NameError: undefined method `initialize_schema_information' for module `ActiveRecord::ConnectionAdapters::SchemaStatements'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/core_ext/module/aliasing.rb:28:in `alias_method'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/core_ext/module/aliasing.rb:28:in `alias_method_chain'
/usr/lib/ruby/gems/1.8/gems/plugin_migrations-0.1.0/lib/plugin_migrations/extensions/schema_statements.rb:13
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:342:in `new_constants_in'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
/usr/lib/ruby/gems/1.8/gems/plugin_migrations-0.1.0/lib/plugin_migrations.rb:3
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:342:in `new_constants_in'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
/usr/lib/ruby/gems/1.8/gems/plugins_plus-0.1.0/lib/plugins_plus.rb:2
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `gem_original_require'
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `require'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:342:in `new_constants_in'
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
/home/tyler/code/applications/t/config/environment.rb:13

As you know, initialize_schema_information is defined in: /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/abstract/schema_statements.rb:235

So it looks like somehow it ended up trying to load the plugin before active_record/connection_adapters/abstract/schema_statements.rb ever got called, which is kind of curious...

Sure enough, I threw some debug output in /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/abstract/schema_statements.rb and tried starting the server but DIDN'T SEE the debug output.

Suspecting that perhaps the reason it wasn't loading active_record/connection_adapters/abstract/schema_statements.rb was because I didn't have any models that _used_ AR in my app, I tried to generate a model... but got a DIFFERENT error:

> ./script/generate model whatever
/usr/lib/ruby/gems/1.8/gems/loaded_plugins-0.1.0/lib/loaded_plugins/loaded_plugins.rb:4: undefined method `mattr_accessor' for PluginAWeek::LoadedPlugins:Module (NoMethodError)
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
        from /usr/lib/ruby/gems/1.8/gems/loaded_plugins-0.1.0/lib/loaded_plugins.rb:3
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
        from /usr/lib/ruby/gems/1.8/gems/plugins_plus-0.1.0/lib/plugins_plus.rb:1
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `gem_original_require'
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `require'
        from ./script/../config/../config/environment.rb:13
  • Stopped requiring 'plugins_plus'
  • ./script/generate model whatever
  • rake db:migrate
  • * I DID see the output from active_record/connection_adapters/abstract/schema_statements.rb during the migrate
  • ./script/server
  • * Did NOT see any output from active_record/connection_adapters/abstract/schema_statements.rb
  • requiring 'plugins_plus' again
  • ./script/server
  • * Did NOT see any output from active_record/connection_adapters/abstract/schema_statements.rb
  • * Still got same undefined method `initialize_schema_information' error.

Any suggestions?


Caveat: Must install using the ./script/plugin install -x option=

[link to mailing list...]

Next I tried installing it as a non-gem plugin:

./script/plugin install http://svn.pluginaweek.org/trunk/plugins/rails/plugins_plus
+ ./plugins_plus/CHANGELOG
+ ./plugins_plus/MIT-LICENSE
+ ./plugins_plus/README
+ ./plugins_plus/Rakefile
+ ./plugins_plus/init.rb
+ ./plugins_plus/lib/plugins_plus.rb
+ ./plugins_plus/tasks/plugins_plus_tasks.rake

Weird! Why aren't there more files in lib??

Looking at http://dev.pluginaweek.org/browser/trunk/plugins/rails/plugins_plus/lib , I see the reason:

Property svn:externals set to
appable_plugins http://svn.pluginaweek.org/trunk/plugins/rails/appable_plugins
loaded_plugins http://svn.pluginaweek.org/trunk/plugins/rails/loaded_plugins
partial_plugin_list http://svn.pluginaweek.org/trunk/plugins/rails/partial_plugin_list
plugin_assets http://svn.pluginaweek.org/trunk/plugins/action_pack/plugin_assets
plugin_dependencies http://svn.pluginaweek.org/trunk/plugins/rails/plugin_dependencies
plugin_migrations http://svn.pluginaweek.org/trunk/plugins/active_record/migrations/plugin_migrations
plugin_routing http://svn.pluginaweek.org/trunk/plugins/action_pack/plugin_routing

My app isn't _in_ a repository because it's just a throwaway app for test purposes.

I suggest putting a note in your readme that your application MUST be in a Subversion repository and you MUST install it using the -x option if you want the dependee plugins to be installed automatically!

Further evidence that this plugin will only work if those externals are in place: script/../config/../vendor/plugins/plugins_plus/init.rb:

base_path = File.dirname(__FILE__)
configuration.plugin_paths << "#{base_path}/lib"
load_plugin "#{base_path}/lib/partial_plugin_list"
load_plugin "#{base_path}/lib/loaded_plugins"
load_plugin "#{base_path}/lib/plugin_migrations"
load_plugin "#{base_path}/lib/plugin_assets"
load_plugin "#{base_path}/lib/appable_plugins"
load_plugin "#{base_path}/lib/plugin_routing"
load_plugin "#{base_path}/lib/plugin_dependencies"
~/code/applications/t > svn add ../t
> ./script/plugin remove plugins_plus
> ./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/plugins_plus
...
Fetching external item into '/home/tyler/code/applications/t/vendor/plugins/plugins_plus/lib/appable_plugins'
...

> ./script/server
...

Seems to work!

Incidentally, I'm still NOT seeing any output from active_record/connection_adapters/abstract/schema_statements.rb , but that doesn't seem to matter. SOMEHOW initialize_schema_information is getting defined, as this test verifies...

./vendor/plugins/plugins_plus/lib/plugin_migrations/lib/plugin_migrations/extensions/schema_statements.rb

      require 'pp'
      pp ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods.grep(/initialize_schema_information/)
      alias_method_chain :initialize_schema_information, :plugins

=> ["initialize_schema_information", "initialize_schema_information_with_plugins"]

The plugin install worked both with this line and without:

  config.plugins = [
    'plugins_plus',
    '*'


star_full.gif star_full.gif star_full.gif Appable plugins

Homepage: http://wiki.pluginaweek.org/Appable_plugins
Documentation: Readme
Source code: http://svn.pluginaweek.org/trunk/plugins/rails/appable_plugins
Project/Development: http://dev.pluginaweek.org/browser/trunk/plugins/rails/appable_plugins


Description: appable_plugins adds the ability for plugins to share models, controllers, and helpers with your Rails application. Classes are automatically mixed in with your own models/controllers/helpers.
Depends on: [[:Plugins:
  • loaded_plugins
  • plugin_dependencies|Plugins:
  • loaded_plugins
  • plugin_dependencies]]





Installation

    ./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/loaded_plugins/
  ./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/plugin_dependencies
./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/appable_plugins

(The indentation is an attempt at making it look like an upside-down dependency tree.)

You need to make sure plugin_dependencies is loaded first.

Examples

http://wiki.pluginaweek.org/Appable_plugins. Retrieved on 2007-04-20 10:51.

acts_as_commentable/
acts_as_commentable/app/
acts_as_commentable/app/models/
acts_as_commentable/app/models/comment.rb
acts_as_commentable/lib/
acts_as_commentable/lib/acts_as_commentable.rb
acts_as_commentable/init.rb

If you, as a user of this plugin, want to then add additional methods or even override methods from the acts_as_commentable plugin, you would simply create a file named comment.rb as you normally would in your application's app/models/ folder. For example,

my_app/
my_app/app/
my_app/app/models/
my_app/app/models/comment.rb

[...]

The order in which multiple models/controllers/helpers are loaded is based on the order in which the plugins were loaded. So in this example, since there was only 1 plugin, the Comment model in acts_as_commentable will be loaded first and then your application's Comment model.

star_full.gif star_full.gif star_empty.gif Plugin assets

Homepage: http://wiki.pluginaweek.org/Plugin_assets
Documentation: Readme
Source code: http://svn.pluginaweek.org/trunk/plugins/action_pack/plugin_assets
Project/Development: http://dev.pluginaweek.org/browser/trunk/plugins/action_pack/plugin_assets


Description: adds the ability to automate the copying of plugin assets into your application's public/ folder, in addition to providing tasks for semi-automatically performing updates.
Depends on: [[:Plugins:
  • loaded_plugins|Plugins:
  • loaded_plugins]]





Installation

  ./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/loaded_plugins/
./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/action_pack/plugin_assets

(The indentation is an attempt at making it look like an upside-down dependency tree.)

Usage

rake assets:list
rake assets:update -- skips those that already exist
rake assets:copy   -- overwrites if already exist


star_full.gif star_empty.gif star_empty.gif Loaded plugins

Homepage: http://wiki.pluginaweek.org/Loaded_plugins
Source code: http://svn.pluginaweek.org/trunk/plugins/rails/loaded_plugins/


As listed in other directories: http://rubyfurnace.com/plugins/loaded_plugins , http://www.agilewebdevelopment.com/plugins/betternestedset






http://wiki.pluginaweek.org/Loaded_plugins

loaded_plugins adds a global variable $LOADED_PLUGINS to the Rails environment that lists the paths to the base directory of each plugin that was loaded during initialization. The paths are listed in the order in which they were loaded. Once initialization is complete, $LOADED_PLUGINS is frozen to prevent it from accidentally being overwritten.

star_full.gif star_full.gif star_full.gif Plugin dependencies

Homepage: http://wiki.pluginaweek.org/Plugin_dependencies
Source code: http://svn.pluginaweek.org/trunk/plugins/rails/plugin_dependencies/
Project/Development: http://dev.pluginaweek.org/browser/trunk/plugins/rails/plugin_dependencies







Motivation

http://svn.pluginaweek.org/trunk/plugins/rails/plugin_dependencies/README (modified)

The current convention within Rails is to load plugins in alphabetical order. This poses a problem when certain plugins must be loaded before others. For example, suppose you write a plugin called acts_as_addressable that uses the acts_as_enumerated plugin by Trevor Squires at http://svn.protocool.com/rails/plugins/enumerations_mixin/. You would then have a directory structure like the following:

  vendor/
  vendor/plugins
  vendor/plugins/acts_as_addressable
  vendor/plugins/acts_as_enumerated

Ordered alphabetically, acts_as_addressable will be loaded BEFORE acts_as_enumerated. This could potentially cause issues if you were assuming in your plugin that acts_as_enumerated had already been loaded.

...

This plugin addresses these issues by giving all plugins/gems the ability to define what other plugins they depend on using a similar API to that of RubyGems.

Usage

http://svn.pluginaweek.org/trunk/plugins/rails/plugin_dependencies/README

For example, the acts_as_addressable.rb would look like the following:

acts_as_addressable/lib/acts_as_addressable.rb:
  require_plugin 'acts_as_enumerated'
  ...

When Rails is initialized, even though acts_as_addressable.rb will be executed first, the require does two things:

  1. Ensure that the acts_as_enumerated plugin is present. If it's not, an exception will be thrown.
  2. Load the acts_as_enumerated plugin and then continue initialization of the acts_as_addressable plugin.

This gives plugin developers the ability to add descriptive information about dependencies directly within their plugins rather than forcing the load order based on the directory names.

Installation

Option 1: As a gem (Preferred by User:Tyler)

> sudo gem install plugin_dependencies

config/environment.rb:
require 'plugin_dependencies'
Rails::Initializer.run do |config|
  ...

(It seems allowable to have it installed as a plugin in addition to having it installed as a gem. This might be advantageous in order to ensure that ./vendor/plugins/plugin_dependencies/tasks/plugin_dependencies_tasks.rake is loaded. But I don't know what plugin_dependencies_tasks.rake is for, so I can't comment on whether that's necessary or not.)

Option 2: As a plugin

This plugin must be loaded before any plugins that use it:

  config.plugins = ['plugin_dependencies'] + Dir.new('vendor/plugins').entries.reject {|f| f =~ /^\./}

(See Rails plugins and libraries / Installing and using#Specifying_load_order for details.)

Problem: undefined method `mattr_accessor'

I'd been using the plugin_dependencies gem before without problems (I thought), and it seems like I'm still able to start the server when I have a require 'plugin_dependencies' in environment.rb . HOWEVER, I get these errors, respectively, when I try to run ./script/about and ./script/console, and I'm not sure why...

> ./script/about
/usr/lib/ruby/gems/1.8/gems/plugin_dependencies-0.1.0/lib/plugin_dependencies/plugin_dependencies.rb:3: undefined method `mattr_accessor' for PluginAWeek::PluginDependencies:Module (NoMethodError)
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
        from /usr/lib/ruby/gems/1.8/gems/plugin_dependencies-0.1.0/lib/plugin_dependencies.rb:1
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `gem_original_require'
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `require'
        from ./script/../config/../config/environment.rb:14
> ./script/console
Loading development environment.
/usr/lib/ruby/gems/1.8/gems/plugin_dependencies-0.1.0/lib/plugin_dependencies/plugin_dependencies.rb:3:NoMethodError: undefined method `mattr_accessor' for PluginAWeek::PluginDependencies:Module
/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/selector_assertions.rb:525:NoMethodError: undefined method `camelize' for "top":String
./script/../config/../config/../app/controllers/application.rb:4:NameError: uninitialized constant ActionController::Base
Welcome!
irb -> (Ctrl-D)Loaded suite irb
Started
Finished in 0.000663 seconds.
0 tests, 0 assertions, 0 failures, 0 errors

(Not sure why it's trying to run a test suite there?!)

Fortunately, I can just fall back to using the non-gem version with plugins_plus and everything works fine.



Plugems

Project/Development: http://rubyforge.org/projects/plugems/


Description: Rails framework for fully 'gemified' applications and shared dependencies. Dependency management, views, rake tasks, configuration files, etc. supported directly via Rubygems. Has proved critical for us for large-scale enterprise Rails development.




Readiness: (Probably has a gem though) This Project Has Not Released Any Files 2007-03-23 17:10, Registered: 2007-02-16 13:24



Plugin migrations

See Rails plugins and libraries / Database-level#Plugin migrations

[Engines (category)]: more powerful plugins

http://rails-engines.org/

Rails Engines are a way of dropping in whole chunks of functionality into your existing application without affecting any of your existing code. They could also be described as application aspects, or vertical application slices – top-to-bottom units which provide full MVC coverage for a certain, specific application function.

Engines can be as lightweight as the simplest plugin, or as full-featured as your your imagination can conceive. They are a natural successor to Rails' original Generator mechanism, or alternatively, plugins with all the power you could ever hope for.

http://rails-engines.org/faq/components-vs-plugins-vs-engines/:

Engines are also useful when you have an entire 'subsystem' of a Rails application (such as managing users & permissions) where you have model objects, controllers to manipulate/administer those objects (updating, creating new ones) and a full set of views & helpers to display information about those objects. Engines are like a slice of an application from top (views/helpers) to bottom (models) which can be dropped into an existing application and appear as if they always existed in the normal /app directory. Developers can selectively override parts of Engines as they need to handle their application (such as changing the user/home view to display a silly name), without affecting the rest of the Engine).

Engines: Better than generators

http://rails-engines.org/faq/engines-vs-generators/:

The engines plugin extends Rails' own minimal plugin system just enough to allow you to include in your plugin almost any type of file you might find in a regular Rails application: controllers, views, helpers, libraries, models, schemas, tests, stylesheets and javascripts... anything you can think of, essentially.
These files are contained within a single directory inside /vendor/plugins, completely isolating them from the rest of your application and therefore making it trivial to update to new versions.
It is still crucial that you as the developer be allowed to alter the behaviour of this packaged code to suit the individual needs of your application. With this in mind, the Engines plugin allows you to override the behaviour of engine code in a simple and clear way:
  • single views can be provided which are automatically used instead of those provided with the engine
  • controller actions can be overridden individually in your application, isolating your custom code from the underlying default implementation
  • model and library code is normally provided as a ruby Module, making it simple to include in your own custom Models
Developing an engine is a much more natural process, compared to creating generators - there is no 'ERb translation step', and changes to an engine can be made and committed in one application and then propagated to another application with no intermediate stages. Engine code looks exactly like normal Rails application code, making it intuitive to skim when you are examining an engine's behavior.










Information about creating/writing plugins

[Ruby-general] Problem: loading a file can have side-effects; make it possible to load the file without those side-effects; in other words, two-stage initialization

You'd want to be able to do something like this:

SomeModule::SomeClass::do_the_usual_initialization = false
require 'some_class'

But: You can't do that before SomeModule::SomeClass have been defined. And it won't be defined until we load the file which contains their definition! But we can't do that without getting the unwanted side-effects, which is why we were doing the SomeModule::SomeClass::do_the_usual_initialization = false in the first place, to prevent those side-effects.

Catch 22.

Solution: Create dummy modules/classes.

Easiest way to do that?

Class.new(:name => :SomeClass, :parent => :SomeModule)::do_the_usual_initialization = false
require 'some_class'

(see Ruby libraries / Core#Module creation helper)

Would that work?

I think it would.

acts_as plugins

Bruce Tate (2007-03-13). Crossing borders: Extensions in Rails: The anatomy of an acts_as plug-in (http://www-128.ibm.com/developerworks/java/library/j-cb03137/index.html). Retrieved on 2007-03-14 10:15.

module ActMacro
  # Configuration options are
  #
  # * +column+ - specifies the column name to use for keeping the state (default: state)
  # * +initial+ - specifies an initial state for newly created objects (required)
  def acts_as_state_machine(opts)
    self.extend(ClassMethods)
    raise NoInitialState unless opts[:initial]
    
    write_inheritable_attribute :states, {}
    write_inheritable_attribute :initial_state, opts[:initial]
    write_inheritable_attribute :transition_table, {}
    write_inheritable_attribute :event_table, {}
    write_inheritable_attribute :state_column, opts[:column] || 'state'
    
    class_inheritable_reader    :initial_state
    class_inheritable_reader    :state_column
    class_inheritable_reader    :transition_table
    class_inheritable_reader    :event_table
    
    self.send(:include, ScottBarron::Acts::StateMachine::InstanceMethods)

    before_create               :set_initial_state
    after_create                :run_initial_state_actions
  end
end

...

Go back to the [write_inheritable_attribute and class_inheritable_reader macros (category)]. You may be wondering why the module doesn't use simple inheritance. The reason is simple: The module has an inheritance hierarchy of its own. These macros allow the module to project these attributes onto the target class -- Nonprofit in this example. The most important attributes are state_column and a series of transition tables containing the states, events, and transitions. Now it's time to add the class methods that form the DSL.






Information about creating/writing plugins: Testing plugins

Template loop detected: Template:Include with edit link

 


Rails plugins / Development tools edit

[Development tools (category)]

See also: Ruby_libraries#Development_.2F_Project_maintenance

star_full.gif star_full.gif star_empty.gif AnnotateModels

Source code: http://svn.pragprog.com/Public/plugins/annotate_models/








Tyrant

Project/Development: http://rubyforge.org/projects/tyrant/


Description: Provides a convenient way to run Rails applications without each user needing a development environment. Tyrant itself is a Rails application with the ability to run multiple Mongrel processes for each user-configured project.




Readiness: 3 - Alpha, This Project Has Not Released Any Files — Tyler (2007-03-23 18:02)


Rails Editor

Categories/Tags: Software Development , Integrated Development Environments (IDE)



Project/Development: http://rubyforge.org/projects/rails-editor/


Description: This is a little package that creates a ./script/editor functionality for a ruby on rails tree. This enables a console IDE utilizing screen and vim which makes editing rails on a console fairly painless.



Environment: Console (Text Based) (screen and [vim (category)])
Readiness: 4 - Beta


[Application starter] Rapid Rails Setup

Project/Development: http://rubyforge.org/projects/rrs-gem/


Description: Tired of performing the same old steps every time you create a new Rails project? With RRS (Rapid Rails Setup) Gem you can have the computer take care of the creation for you.




Readiness: Registered: 2007-02-09 13:20, This Project Has Not Released Any Files 2007-03-23 17:19


star_full.gif star_full.gif star_empty.gif Command completion for rake

Command completion for rake




[Development tools (category)]: Subversion / Tools for dealing with Subversion repositories

http://svn.tylerrick.com/rails_shared/svnrails.rb (based on [20])

http://svn.tylerrick.com/rails_shared/tasks/subversion.rake (based on [21])

http://balloon.hobix.com/svn_configure

  • Adds all files
  • Ignores files in tmp/ and log/
  • Creates a sample database.yml and ignores the original
  • Sets permissions for log/ and public/dispatch.*
  • Tells subversion which files should be executable

[Development tools (category)]: Database

MySQL Tasks

http://rubyfurnace.com/plugins/mysql_tasks

Some rake tasks to automate common database tasks (create/destroy & backup/restore).

rake db:mysql:create # Create database (using database.yml config)
rake db:mysql:destroy # Destroy database (using database.yml config)
rake db:mysql:backup # Dump schema and data to an SQL file (/db/backup_YYYY_MM_DD.sql)
rake db:mysql:restore # Load schema and data from an SQL file (/db/restore.sql)

Comments:

  • I wrote some similar tasks for "shared rake tasks" — Tyler (2007-03-08 15:27)

[Development tools (category)]: Deployment

Capistrano

Capistrano  edit   (Category  edit)


Fossilize

Description: Fossilize is a plugin for Ruby on Rails that allow developers pack their applications as Gems and distribute them, offering end-users simple tools for installation, upgrade and configuration. Allow creation of instances to reduce code duplication.




Readiness: Registered: 2006-08-15, This Project Has Not Released Any Files 2007-03-23 18:53






[Development tools (category)]: [Testing (category)]

See Rails / Testing


[Development tools (category)]/[Post-deployment (category)]: Logging

pl-analyze

See Rails / Performance

star_full.gif star_full.gif star_empty.gif Browser Logger

Homepage: http://revolutiononrails.blogspot.com/2007/01/stop-tailing-your-logs.html (blog)
Source code: svn://rubyforge.org/var/svn/browser-logger
Project/Development: http://rubyforge.org/projects/browser-logger/
As listed in other directories: http://rubyfurnace.com/plugins/browser_logger
Description: Appends just this request's logs to the end of the response. It’s a little more convenient than tailing a log, especially when you’re not logged in. For now, it’s ‘always on.’ Feel free to modify init.rb to incorporate whatever on/off switch you want.





http://revolutiononrails.blogspot.com/2007/01/stop-tailing-your-logs.html

You'll get all the database logs as well, complete with rudimentary color coding and JS filtering. This will always gather ALL logging actions, regardless of configured log level--helpful when you're in prod mode and want to debug a request without changing the log level and bouncing. Usage: Fire up your rails app, make a request with log! or logs! appended as a query param.

Rails Log Visualizer

Homepage: http://railslogvislzr.rubyforge.org/
Source code: svn://rubyforge.org/var/svn/railslogvislzr
Project/Development: http://rubyforge.org/projects/railslogvislzr/


Description: The RailsLogVisualizer provides you with a visual way to explore your Ruby on Rails production.log and find out how your application is really used.



Environment: Mac desktop
Authors: Daniel Wanja


http://railslogvislzr.rubyforge.org/

Load one of your log files

Note: loading a 10Mb production log file with 30000 requests takes about 2 seconds on my MacBook Pro. loading a 250Mb production log file with 530000 requests takes about 20 seconds. loading a 4.5Gb production log file with 11 million request takes about 10 minutes.

Analyzing your log file data

Once the log file is loaded you will see a breakdown of your requests by year, month, and day. Click on the year, month, or day to see the controllers invocations during that period. Click on the controller in the chart to see the method invocations during the selected period. The method are further broken down based on their http methods (get, post, delete, ...).


ResponseLogger (RJS)

Homepage: http://blog.teksol.info/pages/response-logger
Source code: svn://svn.teksol.info/svn/rails/plugins/response-logger


As listed in other directories: http://rubyfurnace.com/plugins/responselogger
Description: Logs the response (generated JavaScript) returned by your RJS actions.



Authors: François Beausoleil


Sample [22]:

log/development.log
===> text/javascript (49 bytes)
Element.replace('target', 'It works!');
<===



[Development tools (category)]/[Post-deployment (category)]: Debugging / Error handling

ValidateRequest

Homepage: http://validaterequest.rubyforge.org/
Source code: svn://rubyforge.org//var/svn/validaterequest/plugins/validate_request
Project/Development: http://rubyforge.org/projects/validaterequest/
As listed in other directories: http://rubyfurnace.com/plugins/validate_request






http://validaterequest.rubyforge.org/

This plugin allows you to specify and check the method and parameters that are used to call your actions. [...] The problem is that if someone visits the url ’/kitten/show’ or /kitten/show/blech’, an exception will be thrown. Furthermore, if someone visits the URL ’/kitten/show/5&this_kitten=sucks’, your application will be none the wiser. Nothing will break, but sometimes you’d like to know about these things, for instance to detect when you have a typo in a GET argument that’s originating in another part of your application.

class KittenController < ActionController::Base
  def show
    validate_request(:get, :id => :integer) or return
    @kitten = Kitten.find(params[:id])
  end 
end

The validate_request method will now verify that incoming requests are via the GET method, and that they contain one argument called ‘id’ whose value is an integer. If any of these conditions aren’t true, the requester is redirected to the site’s home page (configurable, of course), and flash[:error] is set with a polite message (also configurable).

star_full.gif star_empty.gif star_empty.gif RailsRemoteControl

http://seattlerb.rubyforge.org/RailsRemoteControl/

Rails Remote Control allows you to attach to running Rails processes using DRb and change the log level without restarts. Also, view actions handled per process.

Exception Notifier

See Exception Notifier plugin


[Development tools (category)]/[Post-deployment (category)]: Performance monitoring/improvements / profiling / benchmarking

See Rails / Performance

[Localization (category)]

localization_simplified

Project/Development: http://rubyforge.org/projects/l10n-simplified/
As listed in other directories: http://rubyfurnace.com/plugins/localization_simplified




Authors: Jesper Rønn-Jensen


http://rubyforge.org/projects/l10n-simplified/

Fast and easy localization of one-language applications. Adds UTF-8 support for Ruby + database. Modifies ActiveRecord errors + html error helpers, Date/Time helpers, locale time formats, to_currency, to_sentence

gettext_localize

http://rubyfurnace.com/plugins/gettext_localize

Rails plugin to help you localize your rails app using Gettext, it doesn't try to cover localization, internationalization of models [?]. It should work with Rails 1.1.6 and has been tested with the following.
 


Rails plugins and libraries / Miscellaneous edit

Miscellaneous plugins

[old] My tools

All of my (old) shared Rails code can be found at http://svn.tylerrick.com/rails_shared/ .

TableauEngine [Engines (category)][Photo gallery (category)]

http://rubyfurnace.com/plugins/tableauengine

TableauEngine is a AJAX-based photo album engine ported from the original Tableau photo album for rails, found at http://creativi.st/tableau.

Pluralizer

http://nubyonrails.com/tools/pluralize

Acts as Enterprisey

[Humor (category)]

http://www.agilewebdevelopment.com/plugins/acts_as_enterprisey


Directories thereof

 


To do bucket

Article metadata

Rails plugins and libraries / Article metadata edit

Article Metadata: Internal organization

This list is organized along the "core/internals"-"presentation/unimportant" continuum, referencing the Model-View-Controller paradigm where applicable. Things are organized roughly according to this order:

A plugin may only be listed in one primary category. Of course, not everything fits neatly into this organization and some things could fit equally well in two categories, but we'll see how it works...

  • Some entries have cross-cutting (multiple) concerns, in which case it's okay to list them. But you still have to choose a primary organization.
  • If you can't decide which category should be the primary one, here are some (order of precedence) guidelines which probably won't be helpful at all.
    • [Testing (category)] comes before MVC categorization. So if something is a test for caching, then it should go under Testing / Caching before Caching / Testing...
    • [Ruby-level (category)] comes before topical categorization. So Ruby-level / Dates before Top-level / Dates...
    • Performance monitoring/improvements and Permissions/Security currently take precedence over more specific concerns, since these are fairly cross-cutting in their MVC concerns anyway.
    • It being a Development tool (rather than a production tool) trumps other factors. "Development / Database" over "Database / Development".
    • Web services property (Google Maps API, etc.) trumps MVC.

†Most of this organization is inherited from/parallel to the organization of Rails.

Article Metadata: Scope and purpose

Comparable in scope to http://rubyfurnace.com/ . Intended, of course, to be the best directory of plugins available.

How is it different/better than all the other many directories out there?

  • The problem with most directories is that their default "list" view doesn't show enough detail, making comparison a slow and click-ful process. I think a lot of the information from the "detail" view ought to be listed in the list view (customizable, of course), allowing easy side-by-side comparison, and quick skimming of what's available without a lot of clicking...
    • There will not bee too much information on a page because you will browse by category. (No sense comparing apples with pickles!)
  • Designed to allow rapid evaluation and comparison.
    • There are many criteria that people use when deciding whether or not to use a particular plugin / which from among a set of alternatives to use. The editors will highlight those things that they think are most useful in deciding whether or not to use a particular plugin. Both the good and the ugly.
      • features — does it solve the problem(s) you need it to solve?
      • code prettiness (mostly considering the code you have to write to make use of it; but also considering their code, because if it's written poorly, there is a greater chance of bugs, poor maintenance, ...) (=> relevant code samples are included when helpful.)
      • performance considerations
      • number of dependencies
  • †Hand-edited (by humans).
    • Relevant/Useful: Descriptions only contain relevant information. Information that will help you to decide at a glance if you are interested in learning more about / using that plugin. If that means going over to their blog and pulling a juicy example, then that's what I'll do to make it relevant.
    • Quality editing. No broken markup (&lt;).
    • Selective. Only good (human-screened) plugins make it in.
  • †Categorized hierarchically: Makes it easy to browse to a category that interests you currently and just look at plugins in that category
  • †More categories/tags/metadata than most of the competition
  • †See more on one page (if you want -- well, currently you have no choice...but you will) -- multiple projects so it's easy to compare them -- don't have to click a bunch of times / open a bunch of windows to get the details and compare
    • Eventually you will be able to see a concise list and click "Details" to Ajax-load the details
  • Doesn't aim to be comprehensive, so the list is not cluttered with useless plugins. (Or if it ever does become comprehensive, then maybe most of them will be filtered out by default...)
  • Links to related things in other "areas" -- for example, "Testing" category will let you quickly jump over to see all Ruby (not Rails) testing libraries available. (Browse along different dimensions, not limiting you to stay only within Rails plugins.)
  • †Personalizable: can add your own notes and comments and examples; the others only let you keep your own favorites list ... if that.
  • †Pulls from multiple sources -- combines the best information, descriptions, examples, metadata from each
    • No other directory has links to both Agilewebdevelopment.com and Rubyfurnace.com (not that that's useful, but hey...)
    • So at the least it will contain all the data that the others do, but it will try to add more useful data to the mix
    • Cull the best comments/examples from blogs
  • Human-readable first, machine-readable second.
  • †Structured/machine-readable.
    • Encourage people to use it as a web service, etc.
    • I would like the controllers to be able to export XML/etc. to user agents that know how to use it

† Traits inherited from parent topic, "Software projects database"

Article Metadata: To do
  • Tableize: Move data into software_projects table and pull from there.
    • Use ActiveScaffold to list? Does it also work for detail lists like this is trying to be?
    • When doing an ActiveScaffold list within a certain category/section, have all new inserts scoped so that they get added to that category automatically.
  • Set it up to scrape [Repository URL, Homepage URL, Authors, License, Tags, install command] from rubyfurnace.com and store those values in software_projects table if !exist?() already.
Article Metadata: Fields

Fields:

  • †Repository URL
    • "install command" virtual attribute can be inferred from this. Can be used by a command line plugin browser/installer tool
  • †Homepage URL
    • Problem: People's "Homepage URL" for a plugin is often a blog post... wich may be very informative, but it may become out of date (?) because it (unlike a wiki article) probably won't be updated with new information (instead, they'll probably write a new post). Better to link to their blog's category for that plugin? Or what?
  • †Authors
  • †License
  • †Tags (using acts_as_taggable?)
  • †Rating (using acts_as_ratable?)
  • gem URL / is it available as a gem?

† Columns inherited from parent topic, "Software projects database"


 
Ads
Personal tools