module FlexColumns::Including::IncludeFlexColumns
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
Public Instance Methods
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
# 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