Module: FlagpoleSittaHelper

Defined in:
app/helpers/flagpole_sitta_helper.rb

Instance Method Summary collapse

Instance Method Details

#cache_sitta(options = {}, &block) ⇒ Object

AR - cache_sitta helper NOTE This is not safe for .builder xml files. Options

:section The section of the page the cache represents. This is best used in connection with -content_for. Can be any string you want it to be. If not provided will default to body. Also looks for the calls using sections. Will assume calls are in the instance variable ‘@#{options_calls’

:model The model of the object, or objects that you want to link the cache too. Pass the actually model, or an array of models. Must also have a corresponding route_id. If model is an array, route_id must also be an array of equal length. model is connected to route_id.

:route_id The unique identifier of the object, most likely what you route on for showing the object or objects that you want to link the cache too. Pass as a string, or an array of strings. Must also have a corresponding model. If route_id is an array, model must also be an array of equal length. model is connected to route_id.

:models_in_index Use this if the fragment you are rendering is an index pass it all the different types of models/classes could be included in the index. All the include classes must have cache sitta enabled. The cache for the used index pages will then be wiped clear when anyone of these models/classes has an object created or updated.

:index_only Use this if the cache should not be associated with any object, but rather only a model. Use this if your cache is an index, or can be ‘random’.

:sub_route_id Use this if options on the url can result in a difference in the cache. So if you had an page where you could pass in a year and month would be a great place for this. That way your caching each possible version of the page instead of just one.

:scope which will add a ‘scope’ to a :models_in_index cache, which will cause the cache to only be destroyed if an object with in its ‘scope’ is create, updated or destroyed. Like :model and :route_id for each model there must be a corresponding route_id. If you don’t want a scope on every model then just make the index model’s scope nil. The ‘scope’ can only be arguments for a where call. Which means it will either be a hash or an array. Scopes should be used sparling because in order to verify them on save they require a call to the database, and while it boils down to a call by id, they can still add up if you don’t pay attention.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'app/helpers/flagpole_sitta_helper.rb', line 88

def cache_sitta  options={}, &block

  options = clean_options(options)

  if options[:route_id].class.eql?(Array)
    main_route_id = options[:route_id][0]
  else
    main_route_id = options[:route_id]
  end

  if options[:model]

    if options[:model].class.eql?(Array)
      main_model = options[:model][0]
    else
      main_model = options[:model]
    end

  elsif options[:models_in_index]

    if options[:models_in_index].class.eql?(Array)
      main_model = options[:models_in_index][0]
    else
      main_model = options[:models_in_index]
    end
    
  end

  main_model = main_model.respond_to?(:constantize) ? main_model.constantize : main_model

  action = options[:action] || params[:action]

  key = "views/#{main_model}/#{action}"

  key = key + (main_route_id ? ('/' + main_route_id) : '')

  key = key + (options[:sub_route_id] ? ('/' + options[:sub_route_id]) : '')

  key = key + (options[:section] ? ('/' + options[:section]) : '')

  calls = instance_variable_get(
    "@" + (options[:section] ? options[:section] : 'body') + "_calls"
  )

  hash = benchmark("Read fragment #{key} :: FlagpoleSitta") do
    hash = FlagpoleSitta::CommonFs.flagpole_cache_read(key)
  end

  if hash
    content = hash[:content]
  else
    content = benchmark("Write fragment #{key} :: FlagpoleSitta") do
      #NOTE This is not safe for .builder xml files, and using capture here is why.
      #Its either this or a really complicated hack, from the rails source code, which
      #at the moment I don't feel comfortable using. Waiting for an official solution for
      #the ability to use capture with .builders.
      content = capture do

        if calls
          calls.each do |c|
            if instance_variable_get("@#{c[0]}").nil?
              instance_variable_set("@#{c[0]}", c[1].call())
            end
          end
        end

        yield

      end

      #AR - If the cache is an index or includes an index
      #then models_in_index should be passed with all the
      #models that could show up in the index.
      #Then on save of any model include here this index will be cleared.
      #This can also be used for fragments where there are just so many objects,
      #that while its not an index, there isn't a clear way expect to nuke it when
      #any of the model types involved are updated.

      associated = Array.new

      if options[:models_in_index].class.eql?(Array)
        options[:models_in_index].each_index do |i|
          m = options[:models_in_index][i]
          if options[:scope]
            scope = options[:scope][i]
          end
          processed_model = m.respond_to?(:constantize) ? m.constantize : m
          associated << update_index_array_cache(processed_model, key, scope)
        end
      elsif options[:models_in_index]
        processed_model = options[:models_in_index].respond_to?(:constantize) ? options[:models_in_index].constantize : options[:models_in_index]
        associated << update_index_array_cache(processed_model, key, options[:scope])
      end

      #AR - Create a link between each declared object and the cache.

      if !options[:index_only] && options[:route_id]
        if options[:route_id].class.eql?(Array) && options[:model].class.eql?(Array)
          options[:model].each_index do |i|
            associated << update_show_array_cache(options[:model][i], key, options[:route_id][i])
          end
        else
          associated << update_show_array_cache(main_model, key, main_route_id)
        end
      end

      FlagpoleSitta::CommonFs.flagpole_cache_write(key, {:content => content, :associated => associated})

      content

    end

  end

  safe_concat content

end

#clean_options(options = {}) ⇒ Object

In case an unsafe param gets passed. Don’t want to save SQL injection attempts in the cache.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'app/helpers/flagpole_sitta_helper.rb', line 13

def clean_options options={}

  result = Hash.new

  options.each do |k,v|
    #If it fails its not a string and it doesn't need to be 
    #sanitized anyway.
    begin
      clean_v = sanitize(v)
    rescue
      clean_v = v
    end

    result[k] = clean_v

  end

  result

end

#update_index_array_cache(model, key, scope = nil) ⇒ Object



3
4
5
# File 'app/helpers/flagpole_sitta_helper.rb', line 3

def update_index_array_cache model, key, scope=nil
  model.try(:update_array_cache, key, :scope => scope)
end

#update_show_array_cache(model, key, route_id) ⇒ Object



7
8
9
# File 'app/helpers/flagpole_sitta_helper.rb', line 7

def update_show_array_cache model, key, route_id
  model.try(:update_array_cache, key, :route_id => route_id)
end