Class: WithModel::NullTable

Inherits:
Object
  • Object
show all
Defined in:
lib/with_model/null_table.rb

Overview

Stands in for a Table when a model should inherit its superclass's table instead of getting one of its own, as Rails Single Table Inheritance requires. Selected by table(false).

In general, direct use of this class should be avoided. Instead use either the high-level API or low-level API.

Instance Method Summary collapse

Constructor Details

#initialize(superclass, name) ⇒ NullTable

Returns a new instance of NullTable.

Parameters:

  • superclass (Class)

    The resolved superclass whose table will be inherited.

  • name (Symbol, String)

    The model's name, so that a refusal can say which model it is talking about.



18
19
20
21
# File 'lib/with_model/null_table.rb', line 18

def initialize(superclass, name)
  @superclass = superclass
  @name = name
end

Instance Method Details

#configure(klass) ⇒ Object

Deliberately does nothing: leaving table_name unassigned is what lets Active Record's own inheritance supply the superclass's table.



54
55
# File 'lib/with_model/null_table.rb', line 54

def configure(klass)
end

#createObject

Creates nothing, but refuses a superclass that cannot support single table inheritance.

Refusals describe the model's situation rather than the call that produced it. Any expression that evaluates to false selects a NullTable, so there is no call spelling to quote - and in with_model 3.0, omitting table will arrive here too.

A superclass whose table does not exist yet is deliberately allowed: the table may be created later in the example, and a test may legitimately want a model whose table is missing. Active Record raises a clear StatementInvalid naming the table if it never appears, so refusing here would only forbid working setups.

What is left is InvalidSuperclass: both refusals are permanent facts about the superclass passed in, not about when it was looked at, so no amount of waiting makes them work.



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/with_model/null_table.rb', line 40

def create
  refuse "#{@superclass} has none to inherit" unless table_name?

  # Nothing more can be checked until there is a table to look at.
  return unless table_exists?
  return if inheritance_column?

  refuse "#{@superclass}'s table #{@superclass.table_name.inspect} has no " \
         "#{inheritance_column.inspect} column, so Active Record cannot tell its rows " \
         "apart from a subclass's"
end

#destroyObject

Drops nothing; there is no table of our own to drop.



75
76
# File 'lib/with_model/null_table.rb', line 75

def destroy
end

#teardown(klass) ⇒ Object

Removes the rows this model wrote, which would otherwise outlive the constant that names them and make the superclass unloadable (ActiveRecord::SubclassNotFound).

unscoped is required because a default_scope on the superclass would otherwise hide rows from the delete; the inheritance-column condition is then reapplied explicitly, since unscoped also discards the type condition that keeps this from touching the superclass's own rows.

A table that does not exist holds no rows to remove, and failing here would fail an example whose body had already passed.



68
69
70
71
72
# File 'lib/with_model/null_table.rb', line 68

def teardown(klass)
  return unless klass.table_exists?

  klass.unscoped.where(klass.inheritance_column => klass.sti_name).delete_all
end