Skip to content
Andrew Geweke edited this page Nov 2, 2013 · 8 revisions

The low_card_tables API is non-intrusive — it does not override existing methods to mean different things, and it prefixes all its methods with low_card_. The API is also fundamentally bulk-oriented: methods all work in a constant number of database statements. If you have a low-card table with 1,000 possible combinations of values in it and zero rows currently, and you call, for example, low_card_find_or_create_ids_for asking for IDs for every possible combination of values, all at once, then only a handful of SQL statements will be run — and your table will now have 1,000 rows in it, and you'll have your return values.

In general, you will never make calls directly to any of the classes in the LowCardTables:: namespace. Rather, declaring a model as is_low_card_table or has_low_card_table gives it additional API.

(You may discover methods on classes that start with _low_card_i.e., with an underscore, then low_card. These are methods that should be considered private to the low_card_tables system; do not invoke them.)

Here's what the API adds:

To ActiveRecord::Base

  • MyModel.is_low_card_table? returns true if this model has been declared as a low-card table (using is_low_card_table), and false otherwise. This will work for any class that inherits from ActiveRecord::Base.
  • MyModel.has_any_low_card_tables? returns true if this model has been declared to have a low-card table (using has_low_card_table) and false otherwise. This will work for any class that inherits from ActiveRecord::Base.
  • ActiveRecord::Base.low_card_cache_expiration= lets you set the low-card caching policy for all low-card tables (that don't have their own policy explicitly set). See Caching for more information.

To any has_low_card_table model

  • MyModel.low_card_update_foreign_keys! will look at all references this model has to any low-card tables, compute the correct low-card IDs to go in its columns, and update those columns on this model instance, without saving it. Generally you will never need to call this method, because it is automatically called for you just before saving the object. However, it's there if you need it — for example, if you're preparing a lot of model instances for a call to the activerecord-import bulk-import gem, calling this on each instance will set its referring columns properly without impacting performance too much. (This call will touch the database only if it needs to create a new row for the particular combination of attributes on your model.)

To any is_low_card_table model

Retrieving rows directly:

  • MyLowCardTable.low_card_all_rows: Returns all rows on the model, as a simple Array of model objects, from cache. This is equivalent to simply calling MyLowCardTable.all, but this comes from the cache, while the latter will (as it would on any ActiveRecord table) run a database query.
  • MyLowCardTable.low_card_row_for_id: Given a single ID, returns the row for that ID as a model object, from cache. Raises LowCardTables::Errors::LowCardIdNotFoundError if passed an ID that doesn't exist in the table.
  • MyLowCardTable.low_card_rows_for_ids: If given an array containing multiple IDs, returns a Hash mapping each of them to a model object representing that row, from cache. If given a single ID (not an array), simply returns that model object. Raises LowCardTables::Errors::LowCardIdNotFoundError if passed an ID that doesn't exist in the table.

Retrieving rows that partially match a Hash, or a block:

  • MyLowCardTable.low_card_rows_matching: Given a block (but no input), returns an Array of all model objects that match that block. Given a single Hash as input, returns an Array of all model objects that match the constraints in that Hash — for example, given { :deleted => false, :gender => 'female' }, you will get an Array of all rows that have deleted == false and gender == 'female', no matter what other data they have. Given an array of Hashes as input, returns a Hash mapping each of those Hashes to an Array of model objects that match the constraints in each of those Hashes.
  • MyLowCardTable.low_card_ids_matching: Behaves identically to low_card_rows_matching, but returns simple integer IDs, not entire model objects.

Retrieving rows that match an exact set of data:

  • MyLowCardTable.low_card_find_rows_for: Given a single instance of the model class, returns the canonical instance of the model class whose attributes match that model's attributes. (This may appear to be pointless, but you can pass it a model instance with attributes set, but no ID, and you'll get back a model instance with an ID set, so you can store that ID in an appropriate referring model.) Given a single Hash that must contain keys for exactly all of the attributes of the low-card model, returns the canonical instance of the model class whose attributes match that Hash. Given an array of model instances or an array of Hashes, returns a Hash that maps each of those input values to the canonical instance of the model class that matches that model instance or Hash. This method will return nil (or bind the input to nil in the the returned Hash) if there is no row in the table for that combination of attributes currently.
  • MyLowCardTable.low_card_find_ids_for: Exactly like low_card_find_rows_for, except that simple integer IDs are returned, rather than entire model objects.

Retrieving or creating rows that match an exact set of data:

  • MyLowCardTable.low_card_find_or_create_rows_for: Behaves identically to low_card_find_rows_for, except that rows will be created as necessary for sets of attributes that aren't in the table yet. This happens in a constant number of SQL statements.
  • MyLowCardTAble.low_card_find_or_create_ids_for: Behaves identically to low_card_find_or_create_rows_for, except that simple integer IDs are returned, rather than entire model objects.

Manipulating the cache:

  • MyLowCardTable.low_card_flush_cache!: Flushes the cache for this table. See Caching for why you might want to do that manually.

Finding referring models:

  • MyLowCardTable.low_card_referring_models: Returns an Array of all ActiveRecord::Base subclasses that have declared that they refer to this low-card table. (e.g., in our examples, UserStatus.low_card_referring_models will return [ User ].)

Collapsing rows in migrations:

  • MyLowCardTable.low_card_collapse_rows_and_update_referrers!: Called with no arguments (or a simple options Hash); primarily used during migrations, and automatically called for you — you only need to call it yourself if you've told low_card_tables explicitly not to call it in certain situations. If you remove a column from a low-card table, there will suddenly be duplicate rows; this breaks the contract of low_card_tables. This method will iterate through the table, detect duplicate rows, pick a 'winner' for each combination of values, delete the 'losers', and then update all referring columns in all referring tables to point to only winners, not losers. As options, you can pass :low_card_update_referring_models => false if you want to skip the update behavior; you can also pass :low_card_referrers => [ ... ] (passing an array of ActiveRecord::Base subclasses) in case, for some reason, it doesn't update columns in one or more referring models properly.
Clone this wiki locally