ar-extensions, Rails 2.x followup
on July 18, 2008 @ 01:41 AM
First things first, ar-extensions moved to Lighthouse and Github. So please no more tickets or patches on rubyforge. I’ll close out or move over the ones on rubyforge that currently reside there.
Now, the fun stuff.
ar-extensions and Rails 2.x compability
For the most part ar-extensions 0.7.0 (and below) is not compatible with Rails 2.0.x and 2.1. The import functionality works, but ar-extensions will bork on some edge cases of using ActiveRecord::Base.find methods. It won’t return the wrong value, it will simply raise an exception. So if you’re using ar-extensions in your Rails 2.x app, the app itself will probably bork (and I realize that you probably already know this). If you’re using the import functionality in isolation then you should be fine.
Some of the loading issues with ar-extensions that people had are due to ar-extensions being loaded during the time that Rails goes through the loading process (if you put require ‘ar-extensions’ in config/environments/development.rb, test.rb or production.rb). You can get around this by moving if after the Rails::Initializer.run block in your config/environment.rb file.
Tonight I made several commits to get ar-extensions closer to Rails 2.1.0 compatibility. HEAD right now is Rails 2.0.1 compatible, but not 2.0.2 or 2.1.0 compatible. As soon as ar-extensions is compatible I will release 0.8.0. I am hoping for it to be released within the next few days. And by compatible I mean that ar-extensions not only passes its own tests, but it also doesn’t break any of ActiveRecord’s tests.
ar-extensions, Rails 2.x
on July 17, 2008 @ 02:34 AM
There are some issues with ar-extensions and Rails 2.x. At first glance it mainly has to do with load order and what to load. I’m going to try to post an update or at least instructions tomorrow so people can use ar-extensions with Rails 2.x and up.
I’m going to be moving the codebase to github and will start work on ar-extensions to get closer to a 1.0 release later this fall. I plan to kick out 0.8 which includes some bug fixes and any Rails 2.x issues as soon as possible.
I am also looking into using Lighthouse for tickets. Rubyforge’s bug tracking isn’t the greatest and apparently there have been tickets there for a while that I had no idea about (sorry about that).
0.9 will be the first release where I look to improve and cleanup the codebase. Thanks for your patience.
Any questions, comments or suggestions feel free to let me know. Thanks,
ar-extensions get a little praise
on January 20, 2008 @ 09:52 PM
Alan Miles found the import functionality of my ar-extensions gem/plugin helpful and he posted about it here
I’m so glad to hear that ar-extensions is helping Alan and it’s nice to see that he’s sharing this usefulness with others via his blog
ActiveRecord::Extensions 0.7.0 Released!
on July 21, 2007 @ 06:37 AM
ActiveRecord::Extensions 0.7.0 is released! Thanks to Michael Flester and Gabe da Silveira for the patches they submitted!
Updates include:
- Oracle support for better finders (but regexps only work with Oracle 10 or higher) and import (Michael Flester)
- created_at/updated_at timestamps are now implemented with import functionality if they exist on the tables (Zach Dennis/Michael Flester)
- fixed padding issue with MySQL by increasing the byte buffer size to 8 bytes. (thanks to Gabe da Silveira)
To install as a gem you can run:
gem install ar-extensions
To update a previously installed gem you can run:
gem update ar-extensions
To install as a script/plugin you can run:
script/plugin install http://arext.rubyforge.org/svn/tags/ar-extensions-0.7.0
To see information on the usage of ar-extensions please refer to the arext page or refer to the RDOC documentation
Enjoy!
For questions, comments please feel free to email me, zach dot dennis at gmail dot com or by submitting to rubyforge project page for arext.
Rails patch 8277
on May 06, 2007 @ 05:11 AM
The synchronize functionality released in ActiveRecord::Extensions 0.6.0 should probably go in core. So I submitted a patch
My reasoning is that is ActiveRecord::Base#reload already works on a per instance level, why not allow it work on a class level where the class can efficiently handle reloads on multiple instances at once.
The benefit of the class level reload is that you can do one query to the database regardless of how many instances you have rather then having to perform one query per instance.
If you’re in favor of the patch please encourage it gets accepted.
ActiveRecord::Extensions 0.6.0 released
on May 06, 2007 @ 04:34 AM
ActiveRecord::Extensions 0.6.0 is released! You can install it via RubyGems:
gem install ar-extensions |
What’s New?
0.6.0 includes:- support for arrays when using the Hash arguments and the ‘_contains’ suffix.
- a synchronize method which acts like ActiveRecord::Base#reload, but it works on multiple instances. The benefit being that it makes one query to reload all instances rather then one query per instance
- a bug fix for URI encoded strings when using find with ActiveRecord objects
Examples
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# synchronize example post = BlogPost.find_by_author_name( 'zdennis' ) columns = [ :author_name, :title ] values = [ [ 'yoda', 'test post' ] ] BlogPost.import columns, values, :synchronize=>[ post ] post.author_name # => 'yoda' # using synchronize option with import posts = BlogPost.find(:all) BlogPost.import( columns, values, :synchronize=>posts) # using arrays with the _contains suffix BlogPost.find( :all, :conditions=>{ :author_name_contains=>[ 'ab', 'oc', 'ed' ] } ) |
Questions, Comments
zach dot dennis at gmail dot com
ActiveRecord::Extensions 0.5.2 Released!
on March 15, 2007 @ 01:32 AM
ActiveRecord::Extensions 0.5.2 is released! A rubygem has been born!
Installation is so easy now for ActiveRecord::Extensions:
gem install -r 'ar-extensions' |
Enjoy!
0.5.1 was also released, but I quickly released 0.5.2 after it to fix a possible bug with method aliasing. This would only occur if you had another plugin or rubygem which used the same alias name for ActiveRecord::Base#quote
ActiveRecord::Extensions 0.5.0 Released!
on March 14, 2007 @ 02:14 AM
ActiveRecord::Extensions 0.5.0 is released! This release includes support for querying against Time objects against ActiveRecord columns which are considered :datetime by ActiveRecord’s standards .
Code Example
To find all blog posts within the last week:
BlogPost.find( :all, :conditions=>{ :created_at_gt => Time.now-1.week } ) |
To find all posts within the last year:
BlogPost.find( :all, :conditions=>{ :created_at_gt => Time.now-1.year } ) |
To find all posts over a year old:
BlogPost.find( :all, :conditions=>{ :created_at_lt => Time.now-1.year} ) |
User.find( :all, :conditions=>{ :logged_in_at_gt => Time.now-15.minutes} ) |
Supported Suffix Modifiers
This particular query addition supports the following column name suffix modifiers (ie: the “_lt” in the “created_at_lt”).- _lt => less than
- _gt => greater than
- _lte => less than or equal to
- _gte => greater than or equal to
- _ne => not equal to
- _not => not equal to
- eq => equal to _(this is implied without a suffix present)
MySQL TIMESTAMP Disclaimer
This does not work on TIMESTAMP columns for MySQL due to an issue with the inconsistency of TIMESTAMP columns in varying versions of MySQL and due to the nature of server configurations which can alter the behavior of TIMESTAMP columns.
PostgreSQL Support Note
I recently switched to a Mac, I am compiling PostgreSQL 8.1 and 8.2 as I type this. As soon as I can test this functionality against PostgreSQL I will release an update with that support.
Download It Now!
- Rubyforge: http://rubyforge.org/frs/?group_id=2113
ActiveRecord::Extensions 0.4.0 Released!
on February 12, 2007 @ 02:22 AM
ActiveRecord::Extensions 0.4.0 is released!
Updates
- added to_csv functionality (works with belongs_to, has_one and has_many relationships)
- added temporary table functionality
- added foreign key functionality
to_csv functionality
Example 1, exporting all fields
1 2 3 4 |
class Book < ActiveRecord::Base ; end book = Book.find( 1 ) book.to_csv |
Example 2, only exporting certain fields
1 2 3 4 |
class Book < ActiveRecord::Base ; end book = Book.find( 1 ) book.to_csv( :only=>%W( title isbn ) |
Example 3, exporting a model including a belongs_to association
1 2 3 4 5 6 |
class Book < ActiveRecord::Base belongs_to :author end book = Book.find( 1 ) book.to_csv( :include=>:author ) |
This also works for a has_one relationship. The :include option can also be an array of has_one/belongs_to associations. This by default includes all fields on the belongs_to association.
Example 4, exporting a model including a has_many association
1 2 3 4 5 6 |
class Book < ActiveRecord::Base has_many :tags end book = Book.find( 1 ) book.to_csv( :include=>:tags ) |
This by default includes all fields on the has_many assocaition. This can also be an array of multiple has_many relationships. The array can be mixed with has_one/belongs_to associations array as well. IE: :include=>[ :author, :sales ]
Example 5, nesting associations
1 2 3 4 5 6 7 8 9 |
class Book < ActiveRecord::Base belongs_to :author has_many :tags end book = Book.find( 1 ) book.to_csv( :include=>{ :author => { :only=>%W( name ) }, :tags => { :only=>%W( tagname ) } ) |
Example 6, using Arrays returned by find
1 2 3 4 5 6 7 8 9 |
class Book < ActiveRecord::Base belongs_to :author has_many :tags end books = Book.find( :all ) books.to_csv( :include=>{ :author => { :only=>%W( name ) }, :tags => { :only=>%W( tagname ) } ) |
Temporary Table Support
Example 1, using defaults
1 2 3 |
class Project < ActiveRecord::Base ; end Project.create_temporary_table |
This creates a temporary table named ‘temp_projects’ and creates a constant name TempProject. The table structure is copied from the projects table.
Example 2, using :table_name and :model options
Project.create_temporary_table :table_name=>'my_projects', :model=>'MyProject' |
This creates a temporary table named ‘my_projects’ and creates a constant named MyProject. The table structure is copied from the projects table.
Example 3, using :like
ActiveRecord::Base.create_temporary_table :like=>Project |
This is the same as calling Project.create_temporary_table.
Example 4, using block form
1 2 3 |
Project.create_temporary_table do |t| # ... end |
Using the block form will automatically drop the temporary table when the block exits. t which is passed into the block is the temporary table class. In the above example t equals TempProject. The block form can be used with all of the available options.
Foreign Key Support
Enables support for enabling and disabling foreign keys for the underlying database connection for ActiveRecord. This can be used with or without block form. This also uses the connection attached to the model.
Example 1, without block form
1 2 |
Project.foreign_keys.disable Project.foreign_keys.enable |
If you use this form you have to manually re-enable the foreign keys.
Example 2, with block form
1 2 3 4 5 6 7 |
Project.foreign_keys.disable do # ... end Project.foreign_keys.enable do # ... end |
If you use the block form the foreign keys are automatically enabled or disabled when the block exits. This currently does not restore the state of foreign keys to the state before the block was entered.
Download It Now!
ActiveRecord::Extensions 0.4.0
Check it out from SVN into your Rails project
svn co svn://rubyforge.org/var/svn/arext/tags/ar-extensions-0.4.0 vendor/plugins/
Temporary Table Nicety
on January 31, 2007 @ 05:53 AM
A taste of temporary table support for ActiveRecord and MySQL.
Creating Temporary Tables
Temporary tables can be created by using two forms. Temporary tables will generate the following SQL:
CREATE TEMPORARY TABLE table_name LIKE base_table |
The First Form
A block form which manages your temporary table (ie: it creates the table at the start of the block and ensures it is removed by the end of the block, similar to how IO objects work in ruby) .
The Second Form
The second form allows you to assign your temporary table to a variable. You are responsible for destroying it. Or you could just leave it around until your ruby process is done and your database will kill it when the connection closes.
Here’s an example using the block form:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# create our model class Account < ActiveRecord::Base end # perform the update Account.create_temporary_table do |t| t.new.is_a? ActiveRecord::Base # => true t.new.is_a? ActiveRecord::TemporaryTable # => true # You can treat 't' like any model class, and create new records, # add validations, etc. record = t.new :name=>"New Account" record.save record.create :name => "Another new account" # TempAccount is created to reference this model class as well TempAccount == t # => true # the "end" block here will drop our temporary table and remove # our TempAccount constant end |
Checking It Out
You can pull it down from trunk right now. It will be included in the next release (which will be 0.4.0):- svn checkout svn://rubyforge.org/var/svn/arext/trunk/ar-extensions
Like Tables
Like tables are similar to temporary tables. In fact they are created in the exact same way except that they are permanent. They are normal tables until you destroy them. A like table simply generates the following sql:
CREATE TABLE table_name LIKE base_table |
You can create this the same way way you create temporary tables, just pass in the :permanent option as a parameter:
1 2 3 4 5 6 7 8 9 10 |
class Account < ActiveRecord::Base end # t is your model class, also aliased as TempAccount. temp_account_model_class = Account.create_temporary_table :permanent=>true TempAccount == temp_account_model_class # => true # drop your table TempAccount.drop |
ActiveRecord Foreign Key Nicety
on January 24, 2007 @ 09:47 PM
I’ve been busy lately and I haven’t finished the to_csv functionality for ActiveRecord::Extensions. It’s coming, but I haven’t had time to implement all of the tests.
A new feature that myself and Mark Van Holstyn worked up was because we wanted an elegant solution to this in a problem we had. And it was time to finally put in the foreign key support that I hacked together over a year ago. Now it’s not a hack, and I think it’s kind of elegant.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# Disable foreign keys altogether ActiveRecord::Base.foreign_keys.disable # Enable foreign keys ActiveRecord::Base.foreign_keys.enable # Run some updates in a disable block and have AR automatically re-enable foreign keys Topic.foreign_keys.disable do # ... code here.... end # Run some updates in a enable block and have AR automatically re-disable foreign keys Topic.foreign_keys.enable do # ... code here .... end |
This works on any instance of ActiveRecord::Base, and it works on the connection for that instance. So if you have models which are connected to different databases, no worries.
This is in trunk right now and works great for MySQL.
to_csv update (nearing Round #2)
on January 04, 2007 @ 07:17 AM
Round #2 of the to_csv functionality is nearing completion. The updates so far are:
- supports associations via the :include option on a per model object basis
- supports custom headers through the model class
It will work on an ActiveRecord model object itself or an array of ActiveRecord model objects that are returned from any “find” method call.
Basic :include option
The :include option will bring in an association that is created with belongs_to or has_many declarations.
Here is a basic example for a belongs_to association to be included in the CSV results with default options:
csv = People.find( :all ).to_csv( :include=> [ :address ] ) |
- :headers=>true
- :headers=>false
Updated :headers Option
To detour from the :include options for a moment, the :headers option has been updated to accept:- an array of column names as Symbols or Strings
- a Hash of column name to header name mappings as Symbols or Strings
Here are a few examples of the new headers option in use:
1 2 3 4 5 6 7 8 |
# using symbols csv = People.find( :all ).to_csv( :headers => [ :first_name, :last_name ] } # using strings csv = People.find( :all ).to_csv( :headers => [ 'first_name', 'last_name' ] } # using a Hash to supply custom headers csv = People.find( :all ).to_csv( :headers => { :first_name=>'FirstName', :last_name=>'LastName' } |
Since Arrays are ordered the CSV columns will be in the order of the Array. Since Hashes aren’t ordered the order of the columns will be done alphabetically based on the field name.
Intermediate Usage Of :include
The :include option can take:- an Array of Strings or Symbols denoting the name of the association
- a Hash of Hashes mapping the association name to an options Hash
The options Hash is what you’re already passing into the to_csv method. If you use the Hash form of :include you get the ability to embed different options per each association included.
Here are some more intermediate examples:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
people = People.find( :all ) # Using a Hash to specify the column you want from the Address relationship people.to_csv( :include=>{ :address=>{ :only=>[ :street, :city, :state, :zip ] } } ) # Using a top level options to include only certain fields from each person and # then options to include certain fields from each person's address. people.to_csv( :only=>[ :first_name, :last_name ], :include=>{ :address=>{ :only=>[ :street, :city, :state, :zip ] } } ) # Modification of the last example to use custom headers people.to_csv( :headers=>{ :first_name=>"FName", :last_name=>"LName" } , :include=>{ :address=>{ :headers=>{ :city=>"Hometown", :state=>"ST" } } } ) |
That’s a brief summary for where the state of affairs is at for now. If you want more information please read all of the nice tests by checking out the SVN repository.
There are some other usages that you will be able to do like (see below) but the tests and functionality has not been intentionally implemented although it may/may work off from existing functionality:- support multiple :include options for multiple associations
- embed :include options inside of :include options for chaining associations
One thing I don’t like about all of this so far is all of the curly braces, brackets and potentially parenthesizes. The more :includes you want to have, the more curly braces you’re going to have most likely.
I’m trying to think of a block like declarative syntax to handle this, but I haven’t come up with any worthwhile yet. If you’ve got any ideas I’m all ears.
Upcoming 0.4.0 release
This will be launched in a 0.4.0 release which should be soon. I’ve got to be out of town part of this weekend, and the most of next week so I am going to see if I can crunch it in before the next Monday.
ActiveRecord::Extensions 0.3.0 Released!
on December 30, 2006 @ 12:50 AM
ActiveRecord::Extensions 0.3.0 is released! Download it here.
There are no functionality changes in this release. There are two changes:- thanks to Michael Schuerig for pointing out a potential namespace issue which is fixed in this release
- tests are now loaded in the a new ruby process rather then into the same ruby process as rake tasks when running rake test:
ActiveRecord::Extensions 0.2.0 Released!
on December 22, 2006 @ 07:50 AM
ActiveRecord::Extensions 0.2.0 is released! Download it here .
Updates include:- Changes to the to_csv method to support an API compatible with the ToCSV plugin by Chris Abad
- Added support for SQLite and SQLite3
- Added “does_not_match” suffix for :conditions which want to negate a regex
- Added “not_between” suffix for :conditions which want to negate a range
- Converted test database schema to use migrations, and added tasks to load test database
to_csv updates
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Developer < ActiveRecord::Base ; end developers = Developer.find( :all ) # Output default headers, this is implicit if headers is not provided csv = developers.to_csv( :headers => true ) # Output no headers csv = developers.to_csv( :headers => false ) # Output only the following columns csv = developers.to_csv( :only=>[ :id, :name ] ) # Output all columns except the following csv = developers.to_csv( :except => [ :id, :name ] ) |
Updates to better finders
I was typing some code today and I was using Ranges and Regexps. It just felt write to say that something_does_not_match when matching between a Regular Expression. And then I decided to add “not_between” for Ranges.
1 2 3 4 5 6 7 |
class Developer < ActiveRecord::Base ; end # find all developers whose name does not match the regex Developer.find :all, :conditions => { :name_does_not_match => '^Zach' } # find all developers whose IQ is not between 80 and 120 Developer.find :all, :conditions => { :iq_not_between => ( 80 .. 120 ) } |
Running ActiveRecord::Extensions Tests
ActiveRecord::Extensions provides a great testing suite. Just run “rake -T” to see all of the supported tasks. In 0.2.0 the ability to load a test database from migrations has been added.
# Usage
rake db:test:prepare_<db>
# IE:
rake db:test:prepare_mysql
# Then run your tests:
rake test:mysql
# And don't forget to test against activerecord
rake test:activerecord:mysql ~/rails_trunk/activerecord
The only prerequisite of the above is to make sure that your connection is specified correctly for the database you want to test. To do this go into the tests/connections/native_
Enjoy 0.2.0!
For any questions or comments let me know.- zach DOT dennis AT gmail DOT com
ActiveRecord::Extensions SQLite Compatibility
on December 21, 2006 @ 03:18 AM
The upcoming 0.2.0 release is going to include SQLite compatibility, and it looks like that is going to be released before the weekend hits! Any one out there who uses SQLite and wants to leverage the usefulness of ActiveRecord::Extensions, wait no longer (then 1 to 2 more days)!
The upcoming 0.2.0 release will update the to_csv and to_csv_file method arguments.
1 2 3 4 5 6 7 8 9 10 11 |
# rather then array_of_models.to_csv( :headers => [ :field1, :field2, :field3 ] ) # it'll be array_of_models.to_csv( :headers => true|false, :only=> [ :field1, :field2, :field3 ] ) # or array_of_models.to_csv( :headers => true|false, :except=> [ :id ] ) # and the same goes for the options that were passed into to_csv_file as well array_of_models.to_csv_file( filename, :headers=>[ :name, :salary ] ) |
Thanks to Dan Kubb for bringing this up. The API is borrowed from Chris Abad’s ToCSV plugin.
After that I’ll be on holiday vacation and I hope to kick out some cool stuff, like the :include option that Dan Kubb mentioned. for the to_csv.

