rooftop-rails 0.0.3 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 44f03f4480ef66da90df9283ee01437c7e24fb1f
4
- data.tar.gz: 5d5bcfd4bbe1fc4d4d73ca638226bd35c04da30e
3
+ metadata.gz: d686ac1326055010ea5a1026d27d6d1b5fa7cfda
4
+ data.tar.gz: 62ddec40b4f47c843bc01976efa2dc28a0fa782c
5
5
  SHA512:
6
- metadata.gz: 45f27bfd588ba45324abae25ee6d798faaf78a74f91237009ee838d9a2275ff37fbb4f123476d09adbe3c1e8cb7a920d407da8572d27183866995b0c15e12afc
7
- data.tar.gz: a1263337fc73348789ed7f3ea001532ca0556ba706a22326f87f46f5bd03d62ff23f6daa0e90e9df312fc416a7bd5797de9474f5a6cbe0a9376882d8fda86b61
6
+ metadata.gz: 767379cba619e6a39b40c158043328f057119fe595ff215268ef92aace444541be2621197493f5946734d8c4508c5d6a75991ed95b3f06c47dd6eb5731cf7f23
7
+ data.tar.gz: 03298dae9b28386035440e077b6a07ed222b3b42a0eadcdee48eff2865d0b1a2eecb8997062fbc320a4505e1250d765dac5f47d7dd0efc6519121c6904211082
@@ -24,6 +24,10 @@ module Rooftop
24
24
  end
25
25
  end
26
26
 
27
+ def path_matches?(path)
28
+ request.url =~ %r{#{path}}
29
+ end
30
+
27
31
 
28
32
  end
29
33
  end
@@ -22,7 +22,7 @@ module Rooftop
22
22
  path = CGI::unescape(path) if options[:unescape]
23
23
  delimiter = options[:delimiter]
24
24
  slug = "#{options[:prefix]}#{path}".gsub(/^\//, '').split(delimiter).last
25
- entity = where(slug: slug).first
25
+ entity = where(slug: slug, per_page: 1).first
26
26
  if entity.nil?
27
27
  raise Rooftop::RecordNotFoundError, "Couldn't find #{self} with slug #{slug}"
28
28
  else
@@ -47,6 +47,3 @@ module Rooftop
47
47
  end
48
48
  end
49
49
  end
50
-
51
-
52
-
@@ -31,6 +31,7 @@ module Rooftop
31
31
  ::Rails.cache.read("#{cache_key_base}/#{id}")
32
32
  end
33
33
 
34
+ all_objects.each {|o| o.run_callbacks(:find)}
34
35
  all_objects.length == 1 ? all_objects.first : all_objects
35
36
  else
36
37
  super
@@ -38,59 +39,121 @@ module Rooftop
38
39
  end
39
40
 
40
41
  def where(args)
41
- #Sort the arguments, and any keys which are arrays
42
- args = Hash[args.sort.each {|k,v| v.sort! if v.is_a?(Array)}]
43
- # Generate a hash for keying the cache of the results
44
- args_hash = Digest::MD5.hexdigest(args.to_s)
45
- cache_key = "#{cache_key_base}/collection_query/#{args_hash}"
46
- # first see if we have a collection which matches the args
47
- cached_collection = ::Rails.cache.read(cache_key)
48
- # if it's present, then we can return it directly.
49
- if cached_collection.present?
50
- return cached_collection
42
+ if Rooftop::Rails.configuration.perform_object_caching
43
+ # Sort the arguments - reduces the number of different argument hashes.
44
+ # Note that 2 different arg hashes might actually be the same, with child arrays
45
+ # in a different order. But we won't mess with the order of the child arrays
46
+ # because sometimes that's important.
47
+ args = Hash[args.sort]
48
+ # Generate a hash for keying the cache of the results
49
+ args_hash = Digest::MD5.hexdigest(args.to_s)
50
+ cache_key = "#{cache_key_base}/collection_query/#{args_hash}"
51
+ # first see if we have a collection which matches the args
52
+ cached_collection = ::Rails.cache.read(cache_key)
53
+ # if it's present, then we can return it directly.
54
+ if cached_collection.present?
55
+ ::Rails.logger.debug("Returning cached collection for #{cache_key}")
56
+ cached_collection.each {|o| o.run_callbacks :find}
57
+ return cached_collection
58
+ else
59
+ # If not, then we need to call super() to get it from the API
60
+ collection = super(args)
61
+ # and write it into the cache
62
+ ::Rails.cache.write(cache_key,collection)
63
+ # We also iterate over the collection and cache each object, and cache the argument hash against each object
64
+ collection.each do |object|
65
+ # This is a bit funky and circular. We store an array of hashes for queries to which this object belongs.
66
+ # If the object cache needs to be removed, we can iterate through those hashes and clear the collection caches too.
67
+ collection_query_hash_key = "#{object.cache_key}/collection_hashes"
68
+ collection_hashes = ::Rails.cache.read(collection_query_hash_key) || []
69
+ collection_hashes << args_hash
70
+ ::Rails.cache.write(collection_query_hash_key, collection_hashes)
71
+ # this is the object cache - i.e. it'll respond with a cache lookup for Page.find(14) or whatever
72
+ ::Rails.cache.write(object.cache_key,object)
73
+ ::Rails.logger.debug("Written cached collection for #{object.cache_key}")
74
+ end
75
+ collection
76
+ end
51
77
  else
52
- # If not, then we need to call super() to get it from the API
53
- collection = super(args)
54
- # and write it into the cache
55
- ::Rails.cache.write(cache_key,collection)
56
- # We also iterate over the collection and cache each object, and cache the argument hash against each object
57
- collection.each do |object|
58
- # This is a bit funky and circular. We store an array of hashes for queries to which this object belongs.
59
- # If the object cache needs to be removed, we can iterate through those hashes and clear the collection caches too.
60
- collection_query_hash_key = "#{object.cache_key}/collection_hashes"
61
- collection_hashes = ::Rails.cache.read(collection_query_hash_key) || []
62
- collection_hashes << args_hash
63
- ::Rails.cache.write(collection_query_hash_key, collection_hashes)
64
- # this is the object cache - i.e. it'll respond with a cache lookup for Page.find(14) or whatever
65
- ::Rails.cache.write(object.cache_key,object)
78
+ super
79
+ end
80
+ end
81
+
82
+ alias_method :find_by, :where
83
+
84
+ def all(args = {})
85
+ #TODO this is identical to where, above, but the super() is different. Refactor out to DRY
86
+ if Rooftop::Rails.configuration.perform_object_caching
87
+ #Sort the arguments, and any keys which are arrays
88
+ args = Hash[args.sort]
89
+ # Generate a hash for keying the cache of the results
90
+ args_hash = Digest::MD5.hexdigest(args.to_s)
91
+ cache_key = "#{cache_key_base}/collection_query/#{args_hash}"
92
+ # first see if we have a collection which matches the args
93
+ cached_collection = ::Rails.cache.read(cache_key)
94
+ # if it's present, then we can return it directly.
95
+ if cached_collection.present?
96
+ ::Rails.logger.debug("Returning cached collection for #{cache_key}")
97
+ cached_collection.each {|o| o.run_callbacks :find}
98
+ return cached_collection
99
+ else
100
+ # If not, then we need to call super() to get it from the API
101
+ collection = super
102
+ # and write it into the cache
103
+ ::Rails.cache.write(cache_key,collection)
104
+ # We also iterate over the collection and cache each object, and cache the argument hash against each object
105
+ collection.each do |object|
106
+ # This is a bit funky and circular. We store an array of hashes for queries to which this object belongs.
107
+ # If the object cache needs to be removed, we can iterate through those hashes and clear the collection caches too.
108
+ collection_query_hash_key = "#{object.cache_key}/collection_hashes"
109
+ collection_hashes = ::Rails.cache.read(collection_query_hash_key) || []
110
+ collection_hashes << args_hash
111
+ ::Rails.cache.write(collection_query_hash_key, collection_hashes)
112
+ # this is the object cache - i.e. it'll respond with a cache lookup for Page.find(14) or whatever
113
+ ::Rails.cache.write(object.cache_key,object)
114
+ ::Rails.logger.debug("Written cached collection for #{object.cache_key}")
115
+ end
116
+ collection
66
117
  end
67
- collection
118
+ else
119
+ super
68
120
  end
69
121
  end
70
122
 
71
123
  # A method to expire the relevant caches for a collection of objects or ids
72
124
  # @param args [Array] of either objects which respond to `.id`, or ids themselves
73
125
  def expire_cache_for(*args)
74
- args = args.collect {|a| a.respond_to?(:id) ? a.id : a}
126
+ args = args.collect {|a| a.respond_to?(:id) ? a.id : a}.flatten
75
127
  # the caches we need to clear are:
76
128
  # - the object cache
77
129
  # - any collection caches which included this object
78
130
  args.each do |id|
79
131
  object_cache_key = "#{cache_key_base}/#{id}"
80
- collection_keys = (::Rails.cache.read("#{object_cache_key}/collection_hashes") || []).collect do |hash|
81
- "#{cache_key_base}/collection_query/#{hash}"
82
- end
83
- collection_keys << "#{object_cache_key}/collection_hashes"
84
- [collection_keys + [object_cache_key]].flatten.each do |key|
85
- ::Rails.cache.delete(key)
132
+ object_collections = ::Rails.cache.read("#{object_cache_key}/collection_hashes")
133
+ if object_collections.present?
134
+ # this object has a list of collection hashes, each of which we need to remove
135
+ object_collections.each do |hash|
136
+ ::Rails.cache.delete("#{cache_key_base}/collection_query/#{hash}")
137
+ end
138
+ # by implication, the cached object should also be present; clear that too
139
+ ::Rails.cache.delete(object_cache_key)
140
+ else
141
+ # the object isn't in any collections; unfortunately we can't be sure whether this is because the object is old
142
+ # and uncached, or new and therefore needs to be in collections which currently exist for this class.
143
+ # Because of that, we'll aggressively remove caches for collections
144
+ begin
145
+ ::Rails.cache.delete_matched("#{cache_key_base}/collection_query*")
146
+ rescue NotImplementedError
147
+ ::Rails.cache.clear # rescue to Rails.cache.clear for caching methods where delete_matched isn't supported
148
+ end
86
149
  end
87
-
88
- end
150
+ # Always remove the object's cache. There's no risk of doing this for nonexistent things.
151
+ ::Rails.cache.delete(object_cache_key)
89
152
 
90
153
 
154
+ end
91
155
  end
92
-
93
156
  end
94
157
  end
95
158
  end
96
- end
159
+ end
@@ -0,0 +1,13 @@
1
+ class RooftopGenerator < ::Rails::Generators::Base
2
+ source_root File.expand_path("../templates", __FILE__)
3
+
4
+ class_option :api_token, :type => :string, :aliases => "-t", :desc => "Your Rooftop API token", :default => "YOUR_TOKEN_HERE"
5
+ class_option :site_name, :type => :string, :aliases => "-s", :desc => "Your Rooftop subdomain / site name", :default => "YOUR_SITE_NAME_HERE"
6
+
7
+ def create_initializer
8
+ @api_token = options[:api_token]
9
+ @site_name = options[:site_name]
10
+
11
+ template "initializer.rb.erb", "config/initializers/rooftop.rb"
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ if defined?(Rooftop)
2
+ Rooftop::Rails.configure do |config|
3
+ config.api_token = '<%= @api_token %>'
4
+ config.site_name = '<%= @site_name %>'
5
+ config.perform_http_response_caching = false
6
+ config.perform_object_caching = Rails.configuration.action_controller.perform_caching
7
+ config.resource_route_map = {
8
+ page: ->(path, params) {Rails.application.routes.url_helpers.page_path(path, params)}
9
+ }
10
+ <% if defined?(Rooftop::Events) %>
11
+ config.post_type_mapping = {
12
+ menu: Rooftop::Menus::Menu,
13
+ event: Rooftop::Events::Event,
14
+ event_instance: Rooftop::Events::Instance,
15
+ event_price: Rooftop::Events::Price,
16
+ event_price_list: Rooftop::Events::PriceList,
17
+ event_ticket_type: Rooftop::Events::TicketType,
18
+ event_price_band: Rooftop::Events::PriceBand
19
+ }
20
+ <% else %>
21
+ config.post_type_mapping = {
22
+ menu: Rooftop::Menus::Menu
23
+ }
24
+ <% end %>
25
+ end
26
+ end
data/lib/rooftop/rails.rb CHANGED
@@ -31,9 +31,11 @@ module Rooftop
31
31
  :perform_object_caching,
32
32
  :cache_store,
33
33
  :cache_logger,
34
+ :logger,
34
35
  :ssl_options,
35
36
  :proxy,
36
- :resource_route_map
37
+ :resource_route_map,
38
+ :post_type_mapping
37
39
 
38
40
  def initialize
39
41
  @authenticate_webhooks = true
@@ -43,6 +45,7 @@ module Rooftop
43
45
  @cache_logger = ::Rails.logger
44
46
  @ssl_options = {}
45
47
  @resource_route_map = {}
48
+ @logger = nil
46
49
  end
47
50
  end
48
51
  end
@@ -0,0 +1,20 @@
1
+ module Rooftop
2
+ module Rails
3
+ class CacheExpirer
4
+ def self.expire(payload)
5
+ begin
6
+ content_type = payload[:type].to_sym
7
+ if Rooftop.configuration.post_type_mapping[content_type].present?
8
+ klass = Rooftop.configuration.post_type_mapping[content_type]
9
+ else
10
+ klass = content_type.to_s.classify.constantize
11
+ end
12
+ klass.send(:expire_cache_for, payload[:id])
13
+ rescue => e
14
+ raise Rooftop::Rails::UnknownObjectForExpiry, e
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -11,18 +11,22 @@ module Rooftop
11
11
  end
12
12
 
13
13
  initializer "configure_rooftop", before: :add_entry_mappings do
14
- Rooftop.configure do |config|
15
- config.api_token = Rooftop::Rails.configuration.api_token
16
- config.site_name = Rooftop::Rails.configuration.site_name
17
- config.extra_headers = Rooftop::Rails.configuration.extra_headers
18
- config.advanced_options = Rooftop::Rails.configuration.advanced_options
19
- config.api_path = Rooftop::Rails.configuration.api_path
20
- config.url = Rooftop::Rails.configuration.url || "https://#{config.site_name}.rooftopcms.io"
21
- config.perform_caching = Rooftop::Rails.configuration.perform_http_response_caching
22
- config.cache_store = Rooftop::Rails.configuration.cache_store
23
- config.cache_logger = Rooftop::Rails.configuration.cache_logger
24
- config.ssl_options = Rooftop::Rails.configuration.ssl_options
25
- config.proxy = Rooftop::Rails.configuration.proxy
14
+ if Rooftop::Rails.configuration.api_token.present?
15
+ Rooftop.configure do |config|
16
+ config.api_token = Rooftop::Rails.configuration.api_token
17
+ config.site_name = Rooftop::Rails.configuration.site_name
18
+ config.extra_headers = Rooftop::Rails.configuration.extra_headers
19
+ config.advanced_options = Rooftop::Rails.configuration.advanced_options
20
+ config.api_path = Rooftop::Rails.configuration.api_path
21
+ config.url = Rooftop::Rails.configuration.url || "https://#{config.site_name}.rooftopcms.io"
22
+ config.perform_caching = Rooftop::Rails.configuration.perform_http_response_caching
23
+ config.cache_store = Rooftop::Rails.configuration.cache_store
24
+ config.cache_logger = Rooftop::Rails.configuration.cache_logger
25
+ config.ssl_options = Rooftop::Rails.configuration.ssl_options
26
+ config.proxy = Rooftop::Rails.configuration.proxy
27
+ config.logger = Rooftop::Rails.configuration.logger
28
+ config.post_type_mapping = Rooftop::Rails.configuration.post_type_mapping
29
+ end
26
30
  end
27
31
  end
28
32
 
@@ -48,13 +52,7 @@ module Rooftop
48
52
 
49
53
  initializer "clear_caches_on_webhook_notification" do
50
54
  ActiveSupport::Notifications.subscribe(/rooftop.*/) do |name, start, finish, id, payload|
51
- content_type = payload[:type]
52
- if Rooftop.configuration.post_type_mapping[content_type].present?
53
- klass = Rooftop.configuration.post_type_mapping[content_type]
54
- else
55
- klass = content_type.classify.constantize
56
- end
57
- klass.send(:expire_cache_for, payload[:id])
55
+ Rooftop::Rails::CacheExpirer.expire(payload)
58
56
  end
59
57
  end
60
58
  end
@@ -1,5 +1,6 @@
1
1
  module Rooftop
2
2
  module Rails
3
3
  class AncestorMismatch < StandardError; end
4
+ class UnknownObjectForExpiry < NoMethodError; end
4
5
  end
5
6
  end
@@ -8,11 +8,11 @@ module Rooftop::Rails
8
8
  helper_method :preview?
9
9
  end
10
10
  # Check whether the subdomain being presented is the preview domain.
11
- # If so, set Rooftop to use the preview API, and request a username / password
11
+ # If so, set Rooftop to add the preview header
12
12
  def check_preview_domain
13
13
  # If enable_preview_domain is not enabled, explicitly set use_preview_api false and return
14
14
  unless Rooftop::Rails.configuration.enable_preview_domain
15
- Rooftop.use_preview_api = false
15
+ Rooftop.preview = false
16
16
  return
17
17
  end
18
18
 
@@ -24,14 +24,14 @@ module Rooftop::Rails
24
24
  end
25
25
  # If user is authenticated, we're good to switch to the preview api
26
26
  if authenticated
27
- Rooftop.use_preview_api = true
27
+ Rooftop.preview = true
28
28
  else
29
29
  #otherwise ask for user / pass
30
30
  request_http_basic_authentication
31
31
  end
32
32
  else
33
33
  #if the subdomain doesn't match the configured one, explicitly set to false
34
- Rooftop.use_preview_api = false
34
+ Rooftop.preview = false
35
35
  return
36
36
  end
37
37
 
@@ -47,7 +47,7 @@ module Rooftop::Rails
47
47
  end
48
48
 
49
49
  def preview?
50
- Rooftop.use_preview_api == true
50
+ Rooftop.preview == true
51
51
  end
52
52
  end
53
53
  end
@@ -12,16 +12,21 @@ module Rooftop
12
12
  @id = id
13
13
  end
14
14
 
15
- def resolve
15
+ def resolve(params={})
16
16
  route_config = Rooftop::Rails.configuration.resource_route_map
17
17
  resource_key = @id.nil? ? @type.to_s.pluralize.to_sym : @type
18
18
  if route_config[resource_key]
19
- return route_config[resource_key].try(:call,@id)
19
+ if route_config[resource_key].arity == 1
20
+ return route_config[resource_key].try(:call,@id)
21
+ elsif route_config[resource_key].arity == 2
22
+ return route_config[resource_key].try(:call,@id, params)
23
+ end
20
24
  else
21
25
  begin
22
26
  route_info = ::Rails.application.routes.named_routes[resource_key].defaults
23
- route_info.reverse_merge!(id: @id) unless @id.nil?
24
- ::Rails.application.routes.url_helpers.url_for(route_info.merge(only_path: true))
27
+ # once you've called the routes once, you'll have an id. We don't want the previously called one, and in the case of not passing an ID, we want the index method instead of the show method
28
+ route_info.merge!(id: @id) unless @id.nil?
29
+ ::Rails.application.routes.url_helpers.url_for(route_info.merge(only_path: true, params: params))
25
30
  rescue
26
31
  nil
27
32
  end
@@ -1,5 +1,5 @@
1
1
  module Rooftop
2
2
  module Rails
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.6"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rooftop-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Error Studio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-28 00:00:00.000000000 Z
11
+ date: 2016-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: require_all
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 0.0.6
61
+ version: 0.0.7.4
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 0.0.6
68
+ version: 0.0.7.4
69
69
  description: This gem provides utility methods and a mountable engine for Rails applications
70
70
  using the Rooftop gem
71
71
  email:
@@ -82,7 +82,10 @@ files:
82
82
  - app/models/concerns/rooftop/rails/nested_model.rb
83
83
  - app/models/concerns/rooftop/rails/object_cache.rb
84
84
  - config/routes.rb
85
+ - lib/generators/rooftop/rooftop_generator.rb
86
+ - lib/generators/rooftop/templates/initializer.rb.erb
85
87
  - lib/rooftop/rails.rb
88
+ - lib/rooftop/rails/cache_expirer.rb
86
89
  - lib/rooftop/rails/development_constraint.rb
87
90
  - lib/rooftop/rails/engine.rb
88
91
  - lib/rooftop/rails/errors.rb