Disclaimer
redhillonrails_core was originally created by github.com/harukizaemon but it was retired and is no longer supported.
That fork is intended to make redhillonrails_core compatible with edge rails and introduce some new features.
RedHill on Rails Core
Goal of redhillonrails_core is to provided missing ActiveRecord support for database specific features:
-
foreign_keys
-
case-insensitive and partial indexes (pgsql only)
-
views
Installation
As a gem
gem install redhillonrails_core
…or as a plugin
script/plugin install http://github.com/mlomnicki/redhillonrails_core.git
Compatibility
-
Ruby - 1.8, 1.9
-
ActiveRecord - 2.X, 3.X
-
Databases - PostgreSQL, MySQL, SQLite3 (most features should also run on others)
Foreign Key Support
The plugin provides two mechanisms for adding foreign keys as well as preserving foreign keys when performing a schema dump. (Using SQL-92 syntax and as such should be compatible with most databases that support foreign-key constraints.)
The first mechanism for creating foreign-keys allows you to add a foreign key when defining a table. For example:
create_table :orders do |t|
...
t.foreign_key :customer_id, :customers, :id
end
You also have the option of specifying what to do on delete/update using :on_delete
/:on_update
, respectively to one of: :cascade
; :restrict
; and :set_null
:
create_table :orders do |t|
...
t.foreign_key :customer_id, :customers, :id, :on_delete => :set_null, :on_update => :cascade
end
The second method allows you to create arbitrary foreign-keys at any time:
add_foreign_key(:orders, :customer_id, :customers, :id, :on_delete => :set_null, :on_update => :cascade)
In either case, if your database supports deferred foreign keys (for example PostgreSQL) you can specify this as well:
t.foreign_key :customer_id, :customers, :id, :deferrable => true
add_foreign_key(:orders, :customer_id, :customers, :id, :deferrable => true)
By default, the foreign key will be assigned a name by the underlying database. However, if this doesn’t suit your needs, you can override the default assignment using the :name
option:
add_foreign_key(:orders, :customer_id, :customers, :id, :on_delete => :set_null, :on_update => :cascade, <strong>:name => :orders_customer_id_foreign_key<strong>)
You can also query the foreign keys for a model yourself by calling foreign_keys()
:
Order.foreign_keys
Or for an arbitrary table by calling foreign_keys(table_name)
on a database adapter.
Either method returns an array of the following meta-data:
-
name
- The name of the foreign key constraint; -
table_name
- The table for which the foreign-key was generated; -
column_names
- The column names in the table; -
references_table_name
- The table referenced by the foreign-key; and -
references_column_names
- The columns names in the referenced table.
If you need to drop a foreign-key, use:
remove_foreign_key :orders, :orders_ordered_by_id_fkey
The plugin also ensures that all foreign keys are output when performing a schema dump. This happens automatically when running rake migrate
or rake db:schema:dump
. This has particular implications when running unit tests that contain fixtures. To ensure the test data is correctly reset after each test, you should list your fixtures in order of parent->child. For example:
fixtures :customers, :products, :orders, :order_lines
Rails will then set-up and tear-down the fixtures in the correct sequence.
View Support
The plugin provides a mechanism for creating and dropping views as well as preserving views when performing a schema dump:
create_view :normal_customers, "SELECT * FROM customers WHERE status = 'normal'"
drop_view :normal_customers
Model Indexes
ActiveRecord::Base already provides a method on connection for obtaining the indexes for a given table. This plugin now makes it possible to obtain the indexes for a given model–ActiveRecord::Base
–class. For example:
Invoice.indexes
Would return all the indexes for the invoices
table.
Partial Indexes (indexes with conditions)
Partial indexes index only a portion of the database. Only PostgreSQL supports this feature.
add_index :users, :username, :unique => true, :conditions => {:state => "active"}
Indexing using an arbitrary expression (PostgreSQL only)
Create expression-based indexes:
add_index :users, [:first_name, :last_name], :expression => 'LOWER(first_name || ' ' || last_name)'
add_index :places, :expression => 'sin(lat) * cos(lng)', :name => 'index_places_on_something'
add_index :documents, :body, :expression => "USING gin (to_tsvector('english', body))"
Expression is a pass-through: no quoting, escaping is done on it. Presumably, this expression is part of migrations, or at least, code under your control.
Case-insensitive Indexes
For PostgreSQL, you can add an option :case_sensitive => false
to add_index
which will generate an expression index of the form:
LOWER(column_name)
This means finder queries of the form:
WHERE LOWER(column_name) = LOWER(?)
are able to use the indexes rather require, in the worst case, full-table scans.
Note also that this ties in well with Rails built-in support for case-insensitive searching:
validates_uniqueness_of :name, :case_sensitive => false
Tests
redhillonrails_core is tested using similar approach to ActiveRecord tests. However we use rspec in favor of Test::Unit
First you have to fetch sources from github as specs are not inculded in a gem.
$ git clone https://[email protected]/mlomnicki/redhillonrails_core.git
$ cd redhillonrails_core
$ bundle install
$ rake postgresql:build_database # create redhillonrails user first
$ rake mysql:build_database # create user as above
$ bundle exec rake spec
# to run postgresql specs only
$ bundle exec rake spec postgresql:spec
Support
Don’t hesitate to ask questions on our mailing list. groups.google.com/group/rails-db
Contributors
-
Michał Łomnicki
-
François Beausoleil - github.com/francois
-
Greg Barnett
-
Romulo A. Ceccon - github.com/romuloceccon
-
Laurynas Butkus - lauris.night.lt
-
Fernando García Samblas - nando.lacoctelera.com