Module: FlexColumns::Including::IncludeFlexColumns

Extended by:
ActiveSupport::Concern
Defined in:
lib/flex_columns/including/include_flex_columns.rb

Overview

IncludeFlexColumns defines the methods on ActiveRecord::Base that get triggered when you say ‘include_flex_columns_from’ on an ActiveRecord model. Note, however, that it is not simply directly included into ActiveRecord::Base; rather, it’s included only when you actually make that declaration, and included into the specific model class itself. (This helps avoid pollution or conflict on any ActiveRecord models that have not used this functionality.)

This module works in a pretty different way from FlexColumns::HasFlexColumns, which is the corresponding module that gets included when you declare a flex column with flex_column :foo do ... end. That module builds up an object representation of the flex column itself and of all its fields, and then holds onto these objects and uses them to do its work. This module, on the other hand, actively and aggressively defines the appropriate methods when you call #include_flex_columns_from, but does not create or hold onto any object representation of the included columns. This is for two reasons: first off, there’s a lot more complexity in defining a flex column itself than in simply including one. Secondly, and more subtly, defining a flex column is a process with a decided start and end – the contents of the block passed to flex_column. Including fields, however, is a component part of a class that’s defined using the Ruby class keyword, and which can get reopened and redefined at any given time. Thus, we really have no choice but to aggressively define methods when include_flex_columns_from is called; holding onto an object representation would largely just ensure that that object representation grew incorrect over time in development mode, as columns get defined and redefined over time.

(A corollary of this is that, in Rails development mode, depending on how classes get reloaded, it’s possible that if you remove an include_flex_columns_from declaration from a model, the defined methods won’t actually disappear until you restart your server. There’s really not much we can do about this, since there’s no Ruby hook that says “someone is defining methods on class X” – nor would one make any sense, since you can re-open classes at any time and as many times as you want in Ruby.)

In comments below, we’re working with the following example:

class UserDetail < ActiveRecord::Base
  self.primary_key = :user_id
  belongs_to :user

  flex_column :details do
    field :background_color
    field :likes_peaches
  end
end

class User < ActiveRecord::Base
  has_one :detail

  include_flex_columns_from :detail
end

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Instance Method Details

#_flex_column_included_object_for(column_name) ⇒ Object

This is the method that gets called by generated delegated methods via FlexColumns::ActiveRecord::Base#_flex_column_object_for, and called in order to retrieve the correct flex-column object for a column. In other words, the generated method User#background_color looks something like:

def background_color
  flex_column_object = _flex_column_object_for(:details)
  flex_column_object.background_color
end


61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/flex_columns/including/include_flex_columns.rb', line 61

def _flex_column_included_object_for(column_name)
  # Fetch the association that this column is included from.
  association = self.class._flex_column_is_included_from(column_name)

  if association
    # Get the associated object. We automatically will build the associated object, if necessary; this is so that
    # you don't have to either actively create associated objects ahead of time, just in case you need them later,
    # or litter your code with checks to see if those objects exist already or not.
    associated_object = send(association) || send("build_#{association}")
    return associated_object.send(column_name)
  else
    raise FlexColumns::Errors::NoSuchColumnError.new(%{Class #{self.class.name} knows nothing of a flex column named #{column_name.inspect}.})
  end
end