Permalink
Browse files

Add a module level method to data_generations to set generation on al…

…l models controlled by data generations before executing a block of code.
  • Loading branch information...
1 parent 8142a9a commit 67680b48a59f0c7f120401bc19d3775708027107 @crowbot crowbot committed Apr 4, 2012
Showing with 64 additions and 5 deletions.
  1. +42 −5 lib/fixmytransport/data_generations.rb
  2. +22 −0 spec/shared/data_generation_helper.rb
@@ -3,13 +3,50 @@ module FixMyTransport
module DataGenerations
+ @@data_generation_models = []
+ mattr_accessor :data_generation_models
+
+
def self.included(base)
base.send :extend, ClassMethods
end
+ # TODO: Find a better way to preload all models controlled by data generations
+ def self.preload_all_models
+ Dir[ File.join(RAILS_ROOT,'app','models','*.rb') ].map { |file| require_dependency file }
+ end
+
+ # Will set the scope to the generation passed on each model in the
+ # models_to_set_generation_on parameter, and then yield the block
+ def self.set_generation(models_to_set_generation_on, generation, &block)
+ if models_to_set_generation_on.empty?
+ yield
+ else
+ current_model = models_to_set_generation_on.pop
+ current_model.in_generation(generation) do
+ self.set_generation(models_to_set_generation_on, generation, &block)
+ end
+ end
+ end
+
+ # Set the scope to the generation passed for all models controlled by data generations
+ def self.in_generation(generation, &block)
+ # Make sure all models are loaded - as Rails uses lazy loading, some might only
+ # be loaded in the context of the block passed - and we need to set the scope on them first
+ self.preload_all_models
+ # make a copy of the list of models that exist in data generations
+ models_to_set_generation_on = Array.new(self.data_generation_models)
+ # call the recursive function to set the generation scope on each of them
+ self.set_generation(models_to_set_generation_on, generation, &block)
+ end
+
module ClassMethods
def exists_in_data_generation(options={})
+
+ # Record that this model is scoped by data generations
+ FixMyTransport::DataGenerations.data_generation_models << self
+
cattr_accessor :data_generation_options_hash
# Want this not to be inherited by instances
class << self
@@ -20,8 +57,8 @@ class << self
self.class_eval do
# This default scope hides any models that belong to past or future data generations.
- default_scope :conditions => [ "#{quoted_table_name}.generation_low <= ?
- AND #{quoted_table_name}.generation_high >= ?",
+ default_scope :conditions => [ ["#{quoted_table_name}.generation_low <= ?",
+ "AND #{quoted_table_name}.generation_high >= ?"].join(" "),
CURRENT_GENERATION, CURRENT_GENERATION ]
# This callback sets the data generations columns to the current generation
# if not value has been set on them
@@ -81,9 +118,9 @@ def normalize_slug_sequences(data_generation)
# Perform a block of code in the context of the data generation passed
def in_generation(generation_id, &block)
self.with_exclusive_scope do
- self.with_scope(:find => {:conditions => [ "#{quoted_table_name}.generation_low <= ?
- AND #{quoted_table_name}.generation_high >= ?",
- generation_id, generation_id ]}) do
+ condition_string = ["#{quoted_table_name}.generation_low <= ?",
+ "AND #{quoted_table_name}.generation_high >= ?"].join(" ")
+ self.with_scope(:find => {:conditions => [ condition_string, generation_id, generation_id ]}) do
yield
end
end
@@ -17,6 +17,28 @@ module DataGenerationHelper
shared_examples_for "a model that exists in data generations" do
+ describe 'when the data generation is set for all models controlled by data generations' do
+
+ it 'should have the scope for the generation set in the call' do
+ FixMyTransport::DataGenerations.in_generation(PREVIOUS_GENERATION) do
+ condition_string = ["#{@model_type.quoted_table_name}.generation_low <= ?",
+ "AND #{@model_type.quoted_table_name}.generation_high >= ?"].join(" ")
+ expected_scope = {:conditions => [ condition_string, PREVIOUS_GENERATION, PREVIOUS_GENERATION ]}
+ @model_type.send(:scope, :find).should == expected_scope
+ end
+ end
+
+ it 'should have the default scope after the call' do
+ condition_string = ["#{@model_type.quoted_table_name}.generation_low <= ?",
+ "AND #{@model_type.quoted_table_name}.generation_high >= ?"].join(" ")
+ expected_scope = {:conditions => [ condition_string , CURRENT_GENERATION, CURRENT_GENERATION ]}
+ FixMyTransport::DataGenerations.in_generation(PREVIOUS_GENERATION) do
+ end
+ @model_type.send(:scope, :find).should == expected_scope
+ end
+
+ end
+
describe 'when the class is set to replayable' do
before do

0 comments on commit 67680b4

Please sign in to comment.