Class: LowCardTables::HasLowCardTable::LowCardObjectsManager
- Inherits:
-
Object
- Object
- LowCardTables::HasLowCardTable::LowCardObjectsManager
- Defined in:
- lib/low_card_tables/has_low_card_table/low_card_objects_manager.rb
Overview
Unlike the LowCardAssociationsManager, the LowCardObjectsManager belongs to a particular instance of a model class that refers to a low-card table. Its responsibility is straightforward: it holds onto the actual instances of the low-card class that we return in response to someone accessing a low-card association. (More concretely: when you say my_user.status, you get back an instance of UserStatus; if you say my_user.status again, you get back the same instance of UserStatus. This class is responsible for creating that object in the first place, and holding onto it so that the same one gets returned all the time.)
In an ordinary Rails association, you’d get back live, normal instances of the associated class – just like if you’d said, say, UserStatus.find(...)
in the first place. However, this is inappropriate for low-card associations, because the whole ‘trick’ of the low-card system is that changing the attributes of the conceptually-associated UserStatus
object actually just changes which UserStatus
object you’re pointing at, rather than actually changing a UserStatus
row at all.
We perform a simple trick here instead, composed of three parts:
-
Returned objects from low-card associations are actually clones (Object#dup) of the normal low-card objects you’d ordinarily get; this is necessary so that clients can assign attributes to them in any way they want, and there’s no “crosstalk”.
-
Returned objects have their ID removed (through a simple
object.id = nil
); this prevents a whole class of common coding mistakes. Say you retrieve the low-card object associated with a particular referring object, and then modify some of its attributes. Without this change, you’d now be in a situation where you have an associated ActiveRecord object (the low-card object) that has a particular set of attributes, and a particular ID…and yet, when you call #save – which will succeed! – that particular ID doesn’t have that set of attributes at all. It would be way too easy to write code that looks completely correct, and yet fails; for example, you could grab the ID of that associated object and assign it to other referring rows. So we strip the ID off completely. -
Returned objects cannot be directly saved at all; if you call #save or #save! on them, you’ll get an exception, telling you not to do that. The low-card system itself needs to be in complete control of what rows get created, and be able to change referring IDs instead.
These tricks actually happen in LowCardTables::HasLowCardTable::LowCardAssociation#create_low_card_object_for and LowCardTables::LowCardTable::Base#_low_card_disable_save_when_needed!, but it makes sense to document them here, since this class is most clearly given this responsibility.
Instance Method Summary collapse
-
#foreign_key_for(association) ⇒ Object
Returns the foreign key for the given LowCardAssociation for this model instance.
-
#initialize(model_instance) ⇒ LowCardObjectsManager
constructor
Creates a new instance of the LowCardObjectsManager, tied to a particular instance of a low-card model.
-
#object_for(association) ⇒ Object
Returns the low-card object that corresponds to the given LowCardAssociation for this model instance.
-
#set_foreign_key_for(association, new_value) ⇒ Object
Sets the foreign key for the given LowCardAssociation for this model instance.
Constructor Details
#initialize(model_instance) ⇒ LowCardObjectsManager
Creates a new instance of the LowCardObjectsManager, tied to a particular instance of a low-card model. That is, model_instance
should be an instance of UserStatus
or something similar.
39 40 41 42 |
# File 'lib/low_card_tables/has_low_card_table/low_card_objects_manager.rb', line 39 def initialize(model_instance) @model_instance = model_instance @objects = { } end |
Instance Method Details
#foreign_key_for(association) ⇒ Object
Returns the foreign key for the given LowCardAssociation for this model instance. This wouldn’t really have to go through this class for any great reason right now, but, given that #set_foreign_key_for does, it makes a lot of sense to keep the logic here.
56 57 58 |
# File 'lib/low_card_tables/has_low_card_table/low_card_objects_manager.rb', line 56 def foreign_key_for(association) model_instance[association.foreign_key_column_name] end |
#object_for(association) ⇒ Object
Returns the low-card object that corresponds to the given LowCardAssociation for this model instance.
45 46 47 48 49 50 51 |
# File 'lib/low_card_tables/has_low_card_table/low_card_objects_manager.rb', line 45 def object_for(association) association_name = association.association_name.to_s.strip.downcase @objects[association_name] ||= begin association = model_instance.class._low_card_associations_manager._low_card_association(association_name) association.create_low_card_object_for(model_instance) end end |
#set_foreign_key_for(association, new_value) ⇒ Object
Sets the foreign key for the given LowCardAssociation for this model instance. We allow users to do this directly (e.g., my_user.user_status_id = 17
) so that they can, for example, store UserStatus
IDs out-of-band (in memcache, Redis, or whatever) for any reasons they want. When they do assign the foreign-key value, we need to invalidate the associated low-card object, since any previous data there is now no longer valid.
65 66 67 68 69 |
# File 'lib/low_card_tables/has_low_card_table/low_card_objects_manager.rb', line 65 def set_foreign_key_for(association, new_value) model_instance[association.foreign_key_column_name] = new_value invalidate_object_for(association) new_value end |