contentful_rails 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f0f7d55ee8546d4eed5140bb1768923d8bc6861b
4
- data.tar.gz: c0616573406f91822b3d3ee04d5138625498497a
2
+ SHA256:
3
+ metadata.gz: b9421a944765ac63cc458ab0b6f0a88dd50d13bd459898ca04a067ac7a328edf
4
+ data.tar.gz: 78e17715de578357a0217eb209771ab2e4234e0a92556f550033d7718fe40419
5
5
  SHA512:
6
- metadata.gz: bae8ca92a8774946ed40da840af9815059925c9c0f386d0fe23cddb514d6b4ca3906822c07b003826a213b60bc41e7e27881062bba4efd963bed45319ea2629b
7
- data.tar.gz: a934378c344537923460d5f96ee2328fe57ec49d316136eb4c6eaf5763fbed085574cccb121107bd929b1b1327b3550ecf7db5759ddf7d8035c9d0fdc52af1e1
6
+ metadata.gz: 460f1d80d06888d332e3206dfe076493a7796d618bdfd33a4b82a95ea65286aae57b818d31ca3e36cdb9d91a657c7a4e618b8eaf7b244a9a8580f8a13a2e3a51
7
+ data.tar.gz: b51109a95f65e45e795baf3e62762a5fa2c70ee4c6ba67a237953108e0bb12d4e5a60e6059c6ccbee0b367ddefb1e4959f66e266fca348b127a99bb5e3ec1493
data/README.md CHANGED
@@ -7,12 +7,12 @@ This is a work in progress. It relies on the contentful_model gem (http://github
7
7
 
8
8
  ## What is Contentful?
9
9
 
10
- [Contentful](https://www.contentful.com) is a content management platform for web applications, mobile apps and connected devices. It allows you to create, edit & manage content in the cloud and publish it anywhere via powerful API. Contentful offers tools for managing editorial teams and enabling cooperation between organizations.
10
+ [Contentful](https://www.contentful.com) provides a content infrastructure for digital teams to power content in websites, apps, and devices. Unlike a CMS, Contentful was built to integrate with the modern software stack. It offers a central hub for structured content, powerful management and delivery APIs, and a customizable web app that enable developers and content creators to ship digital products faster.
11
11
 
12
12
  # Configuration
13
13
  ContentfulRails accepts a block for configuration. Best done in a Rails initializer.
14
14
 
15
- ```
15
+ ```ruby
16
16
  ContentfulRails.configure do |config|
17
17
  config.authenticate_webhooks = true # false here would allow the webhooks to process without basic auth
18
18
  config.webhooks_username = "a basic auth username"
@@ -21,6 +21,7 @@ ContentfulRails.configure do |config|
21
21
  config.preview_access_token = "your preview access token"
22
22
  config.management_token = "your management access token"
23
23
  config.space = "your space ID"
24
+ config.environment = "your environment ID"
24
25
  config.contentful_options = "hash of options"
25
26
  end
26
27
  ```
@@ -39,7 +40,7 @@ By default, ContentfulRails will try to define your `entry_mapping` configuratio
39
40
  as [described here](https://github.com/contentful/contentful.rb#custom-resource-classes).
40
41
 
41
42
 
42
- ```
43
+ ```ruby
43
44
  ContentfulRails.configure do |config|
44
45
  ...
45
46
  config.eager_load_entry_mapping = false
@@ -59,7 +60,7 @@ The issue with 'Russian Doll' caching in Rails is that it requires a hit on the
59
60
 
60
61
  This is obviously expensive when the object is called over an API. So this gem wraps caches `updated_at` locally, and checks that first on subsequent calls.
61
62
 
62
- ```
63
+ ```ruby
63
64
  Foo.updated_at #returns a timestamp from cache, or from the API if no cache exists
64
65
  ```
65
66
 
@@ -73,7 +74,7 @@ To make use of this in your app:
73
74
  ## routes.rb
74
75
  Mount the ContentfulRails engine at your preferred url:
75
76
 
76
- ```
77
+ ```ruby
77
78
  mount ContentfulRails::Engine => '/contentful' #feel free to choose a different endpoint name
78
79
  ```
79
80
 
@@ -92,7 +93,7 @@ To take advantage of this, there's a custom Redcarpet renderer which allows you
92
93
 
93
94
  In your application_controller.rb:
94
95
 
95
- ```
96
+ ```ruby
96
97
  helper ContentfulRails::MarkdownHelper
97
98
  ```
98
99
 
@@ -101,8 +102,8 @@ This allows you to call `parse_markdown(@your_markdown)` and get HTML. *Note* th
101
102
  ## Manipulating images
102
103
  To manipulate images which are referenced in your markdown, you can pass the following into the `parse_markdown()` call.
103
104
 
104
- ```
105
- parse_markdown(@your_markdown, image_options: {width: 1024, height: 1024})
105
+ ```ruby
106
+ parse_markdown(@your_markdown, image_options: { width: 1024, height: 1024 })
106
107
  ```
107
108
 
108
109
  The `image_options` parameter takes the following options (some are mutually exclusive. Read the [instructions here](https://www.contentful.com/blog/2014/08/14/do-more-with-images-on-contentful-platform/)):
@@ -119,25 +120,41 @@ Sometimes you might want to apply some specific class, markup or similar to an h
119
120
 
120
121
  Just subclass the `ContentfulRails::MarkdownRenderer` class, and call any methods you need.
121
122
 
122
- ```
123
+ ```ruby
123
124
  class MyRenderer < ContentfulRails::MarkdownRenderer
124
- # If you want to pass options into your renderer, you need to overload initialize()
125
- def initialize(opts)
126
- @options = opts
127
- super
128
- end
129
-
130
- # If you want to do something special with links:
131
- def link(link,title,content)
132
- # Add a class name to all links, for example
133
- class_name = "my-link-class-name"
134
- content_tag(:a, content, href: link, title: title, class: class_name)
135
- end
125
+ # If you want to pass options into your renderer, you need to overload initialize()
126
+ def initialize(opts)
127
+ @options = opts
128
+ super
129
+ end
130
+
131
+ # If you want to do something special with links:
132
+ def link(link,title,content)
133
+ # Add a class name to all links, for example
134
+ class_name = "my-link-class-name"
135
+ content_tag(:a, content, href: link, title: title, class: class_name)
136
+ end
136
137
  end
137
138
  ```
138
139
 
139
140
  You can overload any methods exposed in RedCarpet.
140
141
 
142
+ # Preview API
143
+ ContenfulRails can be set up to use the [Contenful Preview API](https://www.contentful.com/developers/docs/references/content-preview-api/), and has the option of protecting that content behind basic authentication.
144
+ To enable the preview api, add the below settings to your configuration.
145
+
146
+ ```
147
+ ContentfulRails.configure do |config|
148
+ config.enable_preview_domain = true # use the preview domain
149
+ config.preview_access_token = "your preview access token"
150
+ config.preview_username = "a basic auth username"
151
+ config.preview_password = "a basic auth password"
152
+ end
153
+ ```
154
+
155
+ If you site is already protected with another form of authentication, then leave `preview_username` and `preview_password` unset.
156
+ This will skip the authentication step when displaying preview content.
157
+
141
158
  # To Do
142
159
  Some things would be nice to do:
143
160
 
@@ -1,49 +1,51 @@
1
- class ContentfulRails::WebhooksController < ActionController::Base
2
- protect_from_forgery with: :exception
3
-
4
- if ContentfulRails.configuration.authenticate_webhooks
5
- http_basic_authenticate_with name: ContentfulRails.configuration.webhooks_username,
6
- password: ContentfulRails.configuration.webhooks_password
7
- end
8
-
9
- params = [:verify_authenticity_token, {:only => [:create], raise: false}]
10
- if Rails::VERSION::MAJOR > 4
11
- skip_before_action *params
12
- else
13
- skip_before_filter *params
14
- end
15
-
16
- #this is where we receive a webhook, via a POST
17
- def create
18
- # The only things we need to handle in here (for now at least) are entries.
19
- # If there's been an update or a deletion, we just remove the cached timestamp.
20
- # The updated_at method which is included in ContentfulModel::Base in this gem
21
- # will check the cache first before making the call to the API.
22
-
23
- # We can then just use normal Rails russian doll caching without expensive API calls.
24
- request.format = :json
25
- update_type = request.headers['HTTP_X_CONTENTFUL_TOPIC']
26
-
27
- # All we do here is publish an ActiveSupport::Notification, which is subscribed to
28
- # elsewhere. In this gem are subscription options for timestamp or object caching,
29
- # implement your own and subscribe in an initializer.
30
- ActiveSupport::Notifications.instrument("Contentful.#{update_type}", params)
31
-
32
- #must return an ok
33
- render nothing: true
1
+ module ContentfulRails
2
+ # Controller for debugging and receiving Contentful Webhooks
3
+ # Webhooks are forwarded via the ActiveSupport::Notification system
4
+ class WebhooksController < ActionController::Base
5
+ protect_from_forgery with: :exception
6
+
7
+ if ContentfulRails.configuration.authenticate_webhooks
8
+ http_basic_authenticate_with name: ContentfulRails.configuration.webhooks_username,
9
+ password: ContentfulRails.configuration.webhooks_password
10
+ end
11
+
12
+ params = [:verify_authenticity_token, { only: [:create], raise: false }]
13
+ if Rails::VERSION::MAJOR > 4
14
+ skip_before_action(*params)
15
+ else
16
+ skip_before_filter(*params)
17
+ end
18
+
19
+ # this is where we receive a webhook, via a POST
20
+ def create
21
+ # The only things we need to handle in here (for now at least) are entries.
22
+ # If there's been an update or a deletion, we just remove the cached timestamp.
23
+ # The updated_at method which is included in ContentfulModel::Base in this gem
24
+ # will check the cache first before making the call to the API.
25
+
26
+ # We can then just use normal Rails russian doll caching without expensive API calls.
27
+ request.format = :json
28
+ update_type = request.headers['HTTP_X_CONTENTFUL_TOPIC']
29
+
30
+ # All we do here is publish an ActiveSupport::Notification, which is subscribed to
31
+ # elsewhere. In this gem are subscription options for timestamp or object caching,
32
+ # implement your own and subscribe in an initializer.
33
+ ActiveSupport::Notifications.instrument("Contentful.#{update_type}", params)
34
+
35
+ # must return an empty response
36
+ render body: nil
37
+ end
38
+
39
+ # Debug route
40
+ def debug
41
+ render plain: 'Debug method works ok'
42
+ end
43
+
44
+ private
45
+
46
+ def webhook_params
47
+ params.permit!
48
+ params.require(:sys).permit(:id, contentType: [sys: [:id]])
49
+ end
34
50
  end
35
-
36
- def debug
37
- render text: "Debug method works ok"
38
- end
39
-
40
- private
41
-
42
- def webhook_params
43
- params.permit!
44
- params.require(:sys).permit(:id, contentType: [sys: [:id]])
45
- end
46
-
47
-
48
-
49
51
  end
@@ -1,12 +1,15 @@
1
1
  module ContentfulRails
2
+ # Custom Redcarpet wrapper with opinionated defaults.
2
3
  module MarkdownHelper
3
- # Return HTML which is passed through the Redcloth markdown processor, using a custom renderer
4
+ # Return HTML which is passed through the Redcarpet markdown processor, using a custom renderer
4
5
  # so that we can manipulate images using contentful's URL-based API.
5
6
  # NOTE that this is super-permissive out of the box. Set options to suit when you call the method.
7
+ #
6
8
  # @param renderer_options [Hash] of options from https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch
7
9
  # @param markdown_options [Hash] of options from https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
10
+ # @param image_options [Hash] of options to pass to the Image API. https://github.com/contentful/contentful_rails#manipulating-images
8
11
  def parse_markdown(markdown_string, renderer_options: {}, markdown_options: {}, image_options: {})
9
- markdown_string ||= ""
12
+ markdown_string ||= ''
10
13
  markdown_opts = {
11
14
  no_intr_emphasis: true,
12
15
  tables: true,
@@ -43,4 +46,4 @@ module ContentfulRails
43
46
  markdown.render(markdown_string).html_safe
44
47
  end
45
48
  end
46
- end
49
+ end
data/config/routes.rb CHANGED
@@ -1,11 +1,9 @@
1
1
  ContentfulRails::Engine.routes.draw do
2
-
3
2
  resources :webhooks, only: [:create], defaults: { format: :json } do
4
3
  collection do
5
4
  scope constraints: ContentfulRails::DevelopmentConstraint do
6
- get "/debug", to: "webhooks#debug"
5
+ get '/debug', to: 'webhooks#debug'
7
6
  end
8
7
  end
9
8
  end
10
-
11
9
  end
@@ -1,14 +1,16 @@
1
1
  require 'redcarpet'
2
2
  require 'contentful_model'
3
3
 
4
- require "contentful_rails/engine"
5
- require "contentful_rails/development_constraint"
4
+ require 'contentful_rails/engine'
5
+ require 'contentful_rails/development_constraint'
6
6
  require 'contentful_rails/caching/timestamps'
7
- require "contentful_rails/markdown_renderer"
8
- require "contentful_rails/nested_resource"
9
- require "contentful_rails/sluggable"
10
- require "contentful_rails/preview"
7
+ require 'contentful_rails/markdown_renderer'
8
+ require 'contentful_rails/nested_resource'
9
+ require 'contentful_rails/sluggable'
10
+ require 'contentful_rails/preview'
11
11
 
12
+ # A collection of useful things to help make it easier to integrate Contentful into your Rails app.
13
+ # It includes view helpers, a Webhook handler, caching, and a Rails Engine to hook it all together.
12
14
  module ContentfulRails
13
15
  class << self
14
16
  attr_accessor :configuration
@@ -19,6 +21,19 @@ module ContentfulRails
19
21
  yield(configuration)
20
22
  end
21
23
 
24
+ def self.include_migrations_to_active_record
25
+ return unless active_record_available?
26
+
27
+ ActiveRecord::Migration.send(:include, ContentfulModel::Migrations::Migration)
28
+ end
29
+
30
+ def self.active_record_available?
31
+ Module.const_get('ActiveRecord::Migration')
32
+ rescue NameError
33
+ false
34
+ end
35
+
36
+ # Configuration accessors
22
37
  class Configuration
23
38
  attr_accessor :authenticate_webhooks,
24
39
  :webhooks_username,
@@ -28,6 +43,7 @@ module ContentfulRails
28
43
  :access_token,
29
44
  :preview_access_token,
30
45
  :management_token,
46
+ :environment,
31
47
  :space,
32
48
  :default_locale,
33
49
  :contentful_options,
@@ -39,7 +55,9 @@ module ContentfulRails
39
55
 
40
56
  def initialize
41
57
  @authenticate = true
42
- @slug_delimiter = "-"
58
+ @slug_delimiter = '-'
59
+ @environment = 'master'
60
+ @default_locale = 'en-US'
43
61
  @perform_caching = Rails.configuration.action_controller.perform_caching
44
62
  @eager_load_entry_mapping = true
45
63
  @contentful_options = {}
@@ -47,4 +65,4 @@ module ContentfulRails
47
65
  end
48
66
  end
49
67
 
50
- ActiveRecord::Migration.send(:include, ContentfulModel::Migrations::Migration)
68
+ ContentfulRails.include_migrations_to_active_record
@@ -1,13 +1,16 @@
1
1
  module ContentfulRails
2
+ # Module for caching extensions
2
3
  module Caching
3
4
  # A module to prepend into ContentfulModel::Base which will allow the model instance
4
5
  # to check the cache for its timestamp before making an expensive API call.
5
6
  # Also includes a module method to remove an existing timestamp.
6
7
  module Timestamps
8
+ # @private
7
9
  def self.prepended(base)
8
10
  base.extend ClassMethods
9
11
  end
10
12
 
13
+ # Class methods for Timestamps
11
14
  module ClassMethods
12
15
  # Clear an existing timestamp from the cache; called by the subscriber to the Entry notifications
13
16
  # from the WebhooksController.
@@ -17,19 +20,21 @@ module ContentfulRails
17
20
  Rails.cache.delete(cache_key)
18
21
  end
19
22
 
23
+ # Get the cache key for the timestamp
20
24
  def timestamp_cache_key(item_id)
21
- "contentful_timestamp/#{self.content_type_id}/#{item_id}"
25
+ "contentful_timestamp/#{content_type_id}/#{item_id}"
22
26
  end
23
27
  end
24
28
 
29
+ # Get the cache key for the timestamp for the current object
25
30
  def timestamp_cache_key
26
31
  self.class.timestamp_cache_key(id)
27
32
  end
28
33
 
29
-
34
+ # Fetches updated_at from cache if set, otherwise calls contentful object
30
35
  def updated_at
31
36
  if ContentfulRails.configuration.perform_caching && !ContentfulModel.use_preview_api
32
- Rails.cache.fetch(self.timestamp_cache_key) do
37
+ Rails.cache.fetch(timestamp_cache_key) do
33
38
  super
34
39
  end
35
40
  else
@@ -37,6 +42,7 @@ module ContentfulRails
37
42
  end
38
43
  end
39
44
 
45
+ # Get the cache key
40
46
  def cache_key
41
47
  if ContentfulModel.use_preview_api
42
48
  "preview/#{super}"
@@ -47,4 +53,3 @@ module ContentfulRails
47
53
  end
48
54
  end
49
55
  end
50
-
@@ -1,5 +1,9 @@
1
- class ContentfulRails::DevelopmentConstraint
2
- def self.matches?(request)
3
- Rails.env =~ %r{development} && (request.remote_ip =~ %r{127.0.0} || request.remote_ip =~ %r{^::1$})
1
+ module ContentfulRails
2
+ # Constraint for ensuring development origin
3
+ class DevelopmentConstraint
4
+ # Returns if current request is coming from development environment or localhost
5
+ def self.matches?(request)
6
+ Rails.env =~ %r{development} && (request.remote_ip =~ %r{127.0.0} || request.remote_ip =~ %r{^::1$})
7
+ end
4
8
  end
5
- end
9
+ end
@@ -1,6 +1,12 @@
1
1
  module ContentfulRails
2
+ # Rails Engine that initializes the Contentful wrappers
3
+ # This engine handles:
4
+ # * ContentfulModel configuration (settings and eager entry mapping loading)
5
+ # * Webhook Event handling (Entry publish/unpublish only)
6
+ # * Caching timestamp prepending on entry objects
7
+ # * Contentful MIME-type handling
8
+ # * Preview API caching behaviour and local authentication for accessing the Preview API
2
9
  class Engine < ::Rails::Engine
3
-
4
10
  isolate_namespace ContentfulRails
5
11
 
6
12
  config.generators do |g|
@@ -8,28 +14,27 @@ module ContentfulRails
8
14
  end
9
15
 
10
16
  config.before_initialize do
11
- if ContentfulRails.configuration.nil?
12
- ContentfulRails.configure {}
13
- end
17
+ ContentfulRails.configure {} if ContentfulRails.configuration.nil?
14
18
  end
15
19
 
16
- initializer "configure_contentful", before: :add_entry_mappings do
20
+ initializer 'configure_contentful', before: :add_entry_mappings do
17
21
  ContentfulModel.configure do |config|
18
22
  config.access_token = ContentfulRails.configuration.access_token
19
23
  config.preview_access_token = ContentfulRails.configuration.preview_access_token
20
24
  config.management_token = ContentfulRails.configuration.management_token
25
+ config.environment = ContentfulRails.configuration.environment
21
26
  config.default_locale = ContentfulRails.configuration.default_locale
22
27
  config.space = ContentfulRails.configuration.space
23
28
  config.options = ContentfulRails.configuration.contentful_options
24
29
  end
25
30
  end
26
31
 
27
- #Iterate through all models which inherit from ContentfulModel::Base
28
- #and add an entry mapping for them, so calls to the Contentful API return
29
- #the appropriate classes
30
- #If eager_load_entry_mapping is false, engine assumes entry mapping is set manually by
31
- #ContentfulRails.contentful_options[:entry_mapping] (passed through to Contentful.entry_mapping config)
32
- initializer "add_entry_mappings", after: :configure_contentful do
32
+ # Iterate through all models which inherit from ContentfulModel::Base
33
+ # and add an entry mapping for them, so calls to the Contentful API return
34
+ # the appropriate classes
35
+ # If eager_load_entry_mapping is false, engine assumes entry mapping is set manually by
36
+ # ContentfulRails.contentful_options[:entry_mapping] (passed through to Contentful.entry_mapping config)
37
+ initializer 'add_entry_mappings', after: :configure_contentful do
33
38
  if defined?(ContentfulModel) && ContentfulRails.configuration.eager_load_entry_mapping
34
39
  Rails.application.eager_load!
35
40
  ContentfulModel::Base.descendents.each do |klass|
@@ -38,38 +43,42 @@ module ContentfulRails
38
43
  end
39
44
  end
40
45
 
41
- initializer "subscribe_to_webhook_events", after: :add_entry_mappings do
42
- ActiveSupport::Notifications.subscribe(/Contentful.*Entry\.publish/) do |name, start, finish, id, payload|
46
+ initializer 'subscribe_to_webhook_events', after: :add_entry_mappings do
47
+ ActiveSupport::Notifications.subscribe(/Contentful.*Entry\.publish/) do |_name, _start, _finish, _id, payload|
43
48
  content_type_id = payload[:sys][:contentType][:sys][:id]
44
49
  klass = ContentfulModel.configuration.entry_mapping[content_type_id]
45
- # klass will be nil if the content model has been created in contentful but the model in rails hasn't been added
46
- unless klass.nil?
47
- klass.send(:clear_cache_for, payload[:sys][:id])
48
- end
49
50
 
51
+ # klass will be nil if the content model has been created in contentful but the model in rails hasn't been added
52
+ klass.send(:clear_cache_for, payload[:sys][:id]) unless klass.nil?
50
53
  end
51
54
 
52
- ActiveSupport::Notifications.subscribe(/Contentful.*Entry\.unpublish/) do |name, start, finish, id, payload|
53
- ActionController::Base.new.expire_fragment(%r{.*#{payload[:sys][:id]}.*})
55
+ ActiveSupport::Notifications.subscribe(/Contentful.*Entry\.unpublish/) do |_name, _start, _finish, _id, payload|
56
+ ActionController::Base.new.expire_fragment(%r{/.*#{payload[:sys][:id]}.*/})
54
57
  end
55
58
  end
56
59
 
57
- initializer "prepend_timestamps_module", after: :subscribe_to_webhook_events do
60
+ initializer 'prepend_timestamps_module', after: :subscribe_to_webhook_events do
58
61
  if defined?(::ContentfulModel)
59
62
  ContentfulModel::Base.send(:prepend, ContentfulRails::Caching::Timestamps)
60
63
  end
61
64
  end
62
65
 
63
- initializer "add_contentful_mime_type" do
64
- content_type = "application/vnd.contentful.management.v1+json"
65
- Mime::Type.register content_type, :contentful_json, [content_type]
66
+ # Module for defining Contentful vnd mime-type
67
+ module ContentfulJSON
68
+ # Contentful mime-type
69
+ MIMETYPE = 'application/vnd.contentful.management.v1+json'.freeze
70
+ end
71
+
72
+ initializer 'add_contentful_mime_type' do
73
+ Mime::Type.register(ContentfulJSON::MIMETYPE, :contentful_json)
66
74
  default_parsers = Rails::VERSION::MAJOR > 4 ? ActionDispatch::Http::Parameters::DEFAULT_PARSERS : ActionDispatch::ParamsParser::DEFAULT_PARSERS
67
- default_parsers[Mime::Type.lookup(content_type)] = lambda do |body|
75
+ default_parsers[Mime::Type.lookup(ContentfulJSON::MIMETYPE)] = lambda do |body|
68
76
  JSON.parse(body)
69
77
  end
78
+ ActionDispatch::Request.parameter_parsers = ActionDispatch::Request::DEFAULT_PARSERS if ActionDispatch::Request.respond_to?(:parameter_parsers=)
70
79
  end
71
80
 
72
- initializer "add_preview_support" do
81
+ initializer 'add_preview_support' do
73
82
  ActiveSupport.on_load(:action_controller) do
74
83
  include ContentfulRails::Preview
75
84
  end
@@ -1,31 +1,38 @@
1
1
  require 'redcarpet'
2
- # A custom renderer for Redcarpet, which adds options for manipulating images through the URL of the image,
3
- # and building links based on the content of the link.
4
- #
5
- # You can subclass this in your application, to add or manipulate specific markup to elements in the markdown.
6
- class ContentfulRails::MarkdownRenderer < Redcarpet::Render::HTML
7
- include ActionView::Helpers::TagHelper
8
- include ActionView::Context
9
- def initialize(opts)
10
- @options = opts
11
- @image_parameters = {
12
- w: @options[:image_options][:width], #width in px
13
- h: @options[:image_options][:height], #height in px
14
- fit: @options[:image_options][:fit], #crop, scale, pad, thumb
15
- f: @options[:image_options][:focus], #top, right, bottom, left, top_right, top_left, bottom_right, bottom_left, face
16
- fm: @options[:image_options][:format], #jpg, png
17
- bg: @options[:image_options][:background_colour], #no idea what the options are, but 'transparent' works for pngs
18
- r: @options[:image_options][:corner_radius], #corner radius in px
19
- q: @options[:image_options][:quality]
20
- }.delete_if {|k,v| v.nil?}
21
- super
22
- end
23
2
 
24
- def image(link, title, alt_text)
25
- # add the querystring to the image
26
- link += "?#{@image_parameters.to_query}"
27
- # return a content tag
28
- content_tag(:img, nil, src: link.to_s, alt: alt_text, title: title)
29
- end
3
+ module ContentfulRails
4
+ # A custom renderer for Redcarpet, which adds options for manipulating images through the URL of the image,
5
+ # and building links based on the content of the link.
6
+ #
7
+ # You can subclass this in your application, to add or manipulate specific markup to elements in the markdown.
8
+ class MarkdownRenderer < Redcarpet::Render::HTML
9
+ include ::ActionView::Helpers::TagHelper
10
+ include ::ActionView::Context
30
11
 
31
- end
12
+ def initialize(opts)
13
+ @options = opts
14
+ @image_parameters = {
15
+ w: @options[:image_options][:width], # width in px
16
+ h: @options[:image_options][:height], # height in px
17
+ fit: @options[:image_options][:fit], # crop, scale, pad, thumb
18
+ f: @options[:image_options][:focus], # top, right, bottom, left, top_right, top_left, bottom_right, bottom_left, face
19
+ fm: @options[:image_options][:format], # jpg, png, webp
20
+ bg: @options[:image_options][:background_colour], # no idea what the options are, but 'transparent' works for pngs
21
+ r: @options[:image_options][:corner_radius], # corner radius in px
22
+ q: @options[:image_options][:quality]
23
+ }.delete_if { |_, v| v.nil? }
24
+ super
25
+ end
26
+
27
+ # Image tag wrapper for forwarding Image API options
28
+ def image(link, title, alt_text)
29
+ # add the querystring to the image
30
+ if @image_parameters.present?
31
+ prefix = link.include?('?') ? '&' : '?'
32
+ link += "#{prefix}#{@image_parameters.to_query}"
33
+ end
34
+ # return a content tag
35
+ content_tag(:img, nil, src: link.to_s, alt: alt_text, title: title)
36
+ end
37
+ end
38
+ end
@@ -1,78 +1,81 @@
1
1
  module ContentfulRails
2
+ # Module for obtaining object references from paths
2
3
  module NestedResource
3
-
4
4
  def self.included(base)
5
5
  base.extend ClassMethods
6
6
  end
7
7
 
8
+ # Class methods for NestedResource
8
9
  module ClassMethods
9
10
  # Get a deeply-nested object from a string which represents the heirarchy.
10
11
  # The obvious use for this is to find an object from a URL
11
12
  # e.g. /grandparent/parent/child
12
- # @param [Symbol] the field to search by - for example, :slug
13
- # @param [String] the path as a forward-slash separated string
13
+ #
14
+ # @param field [Symbol] the field to search by - for example, :slug
15
+ # @param path [String] the path as a forward-slash separated string
14
16
  def get_nested_from_path_by(field, path, opts = {})
15
- options = {delimiter: '/', unescape: false, prefix: ""}
17
+ options = { delimiter: '/', unescape: false, prefix: '' }
16
18
  options.merge!(opts)
17
19
 
18
20
  path = CGI::unescape(path) if options[:unescape]
19
21
  delimiter = options[:delimiter]
20
- prefix = options[:prefix].empty? ? "" : "#{delimiter}#{options[:prefix]}#{delimiter}"
22
+ prefix = options[:prefix].empty? ? '' : "#{delimiter}#{options[:prefix]}#{delimiter}"
21
23
 
22
- root, *children = "#{prefix}#{path}".gsub(/^\//, '').split(delimiter)
24
+ root, *children = "#{prefix}#{path}".gsub(%r{/^\//}, '').split(delimiter)
23
25
 
24
26
  if field.to_sym == :id
25
- #we need to call find() to get by ID
27
+ # we need to call find() to get by ID
26
28
  root_entity = find(root)
27
29
  else
28
30
  begin
29
31
  root_entity = search(field => root).first
30
32
  rescue Contentful::BadRequest
31
- #we have something which needs find_by called on it
33
+ # we have something which needs find_by called on it
32
34
  root_entity = find_by(field => root).first
33
35
  end
34
36
  end
35
37
 
36
38
  if root_entity && root_entity.has_children?
37
- return root_entity.get_child_entity_from_path_by(field, children)
39
+ root_entity.get_child_entity_from_path_by(field, children)
38
40
  elsif root_entity
39
- return root_entity
40
- else
41
- return nil
41
+ root_entity
42
42
  end
43
43
  end
44
44
  end
45
45
 
46
46
  # Given a field and an array of child fields, we need to recurse through them to get the last one
47
- # @param [Symbol] the field we need to search for
48
- # @param [Array] an array of field values to match against
47
+ #
48
+ # @param field [Symbol] the field we need to search for
49
+ # @param children [Array] an array of field values to match against
49
50
  # @return an entity matching this class, which is the last in the tree
50
51
  def get_child_entity_from_path_by(field, children)
51
52
  # the next child in the path
52
53
  child_value = children.shift
54
+
53
55
  # get the child entity
54
- child = self.send(:children).find {|child| child.send(field) == child_value}
55
- if child && children.size > 0
56
- # we have some recursion to do - we're not at the end of the array
57
- # so call this method again with a smaller set of children
58
- child.get_child_entity_from_path_by(field, children)
59
- else
60
- return child #this is the final thing in the array - return it
61
- end
56
+ child = send(:children).find { |c| c.send(field) == child_value }
57
+
58
+ # we have some recursion to do - we're not at the end of the array
59
+ # so call this method again with a smaller set of children
60
+ return child.get_child_entity_from_path_by(field, children) if child && !children.empty?
61
+
62
+ child # this is the final thing in the array - return it
62
63
  end
63
64
 
64
65
  # Given a field (and optional delimiter), return a path to the current object.
65
66
  # e.g. you'd end up with /path/to/page (where this object is 'page')
66
- # @param [Symbol] the field to use to create the path
67
- # @param [String] the delimiter to use. Defaults to "/"
67
+ #
68
+ # @param field [Symbol] the field to use to create the path
69
+ # @param opts [Hash] the delimiter to use. Defaults to "/"
68
70
  # @return [String] the path as a string
69
71
  def nested_path_by(field, opts = {})
70
- options = {delimiter: "/", prefix: ""}
72
+ options = { delimiter: '/', prefix: '' }
71
73
  options.merge!(opts)
72
74
  delimiter = options[:delimiter]
73
- prefix = options[:prefix].empty? ? "" : "#{options[:prefix]}#{delimiter}"
74
- path = ([self] + ancestors).reverse.collect {|a| a.send(field)}.join(delimiter).gsub(prefix,"")
75
- return delimiter + path
75
+ prefix = options[:prefix].empty? ? '' : "#{options[:prefix]}#{delimiter}"
76
+ path = ([self] + ancestors).reverse.collect { |a| a.send(field) }.join(delimiter).gsub(prefix, '')
77
+
78
+ delimiter + path
76
79
  end
77
80
  end
78
81
  end
@@ -1,14 +1,14 @@
1
1
  module ContentfulRails
2
+ # Module to secure preview sessions and bust cache on preview entries
2
3
  module Preview
3
4
  extend ActiveSupport::Concern
4
5
 
5
6
  included do
6
7
  before_action :check_preview_domain
7
8
  after_action :remove_preview_cache
8
- if respond_to?(:helper_method)
9
- helper_method :preview?
10
- end
9
+ helper_method :preview? if respond_to?(:helper_method)
11
10
  end
11
+
12
12
  # Check whether the subdomain being presented is the preview domain.
13
13
  # If so, set ContentfulModel to use the preview API, and request a username / password
14
14
  def check_preview_domain
@@ -18,25 +18,29 @@ module ContentfulRails
18
18
  return
19
19
  end
20
20
 
21
- #check subdomain matches the configured one - we assume it's first sub.domain.in.the.array
21
+ # check subdomain matches the configured one - we assume it's first sub.domain.in.the.array
22
22
  if request.subdomains.first == ContentfulRails.configuration.preview_domain
23
- authenticated = authenticate_with_http_basic do |u,p|
24
- u == ContentfulRails.configuration.preview_username
25
- p == ContentfulRails.configuration.preview_password
23
+ if ContentfulRails.configuration.preview_username.nil? && ContentfulRails.configuration.preview_password.nil?
24
+ ContentfulModel.use_preview_api = true
25
+ return
26
+ end
27
+
28
+ authenticated = authenticate_with_http_basic do |u, p|
29
+ u == ContentfulRails.configuration.preview_username &&
30
+ p == ContentfulRails.configuration.preview_password
26
31
  end
27
32
  # If user is authenticated, we're good to switch to the preview api
28
33
  if authenticated
29
34
  ContentfulModel.use_preview_api = true
30
35
  else
31
- #otherwise ask for user / pass
32
- request_http_basic_authentication
36
+ # otherwise ask for user / pass
37
+ request_http_basic_authentication
33
38
  end
34
39
  else
35
- #if the subdomain doesn't match the configured one, explicitly set to false
40
+ # if the subdomain doesn't match the configured one, explicitly set to false
36
41
  ContentfulModel.use_preview_api = false
37
42
  return
38
43
  end
39
-
40
44
  end
41
45
 
42
46
  # If we're in preview mode, we need to remove the preview view caches which were created.
@@ -49,7 +53,7 @@ module ContentfulRails
49
53
  end
50
54
 
51
55
  def preview?
52
- ContentfulModel.use_preview_api == true
56
+ ContentfulModel.use_preview_api
53
57
  end
54
58
  end
55
- end
59
+ end
@@ -1,18 +1,17 @@
1
1
  module ContentfulRails
2
+ # A quick mixin to slugify a field other than 'slug'
3
+ # NOTE that if you include sluggable (and define a slug field) in a class which responds to
4
+ # slug() than you'll get a stack level too deep error.
2
5
  module Sluggable
3
6
  extend ActiveSupport::Concern
4
- # A quick mixin to slugify a field other than 'slug'
5
- # NOTE that if you include sluggable (and define a slug field) in a class which responds to
6
- # slug() than you'll get a stack level too deep error.
7
7
 
8
8
  class_methods do
9
9
  attr_accessor :slug_field
10
10
  end
11
11
 
12
+ # Returns the slugified version of the :slug_field
12
13
  def slug
13
- if self.class.slug_field.present?
14
- self.send(self.class.slug_field).parameterize(ContentfulRails.configuration.slug_delimiter)
15
- end
14
+ send(self.class.slug_field).parameterize(ContentfulRails.configuration.slug_delimiter) if self.class.slug_field.present?
16
15
  end
17
16
  end
18
- end
17
+ end
@@ -1,3 +1,4 @@
1
1
  module ContentfulRails
2
- VERSION = "0.4.1"
2
+ # Version number
3
+ VERSION = '0.5.0'.freeze
3
4
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contentful_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
+ - Contentful GmbH (David Litvak Bruno)
7
8
  - Error Creative Studio
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2017-05-22 00:00:00.000000000 Z
12
+ date: 2019-05-08 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: rails
@@ -30,14 +31,14 @@ dependencies:
30
31
  requirements:
31
32
  - - "~>"
32
33
  - !ruby/object:Gem::Version
33
- version: '0.2'
34
+ version: '1.0'
34
35
  type: :runtime
35
36
  prerelease: false
36
37
  version_requirements: !ruby/object:Gem::Requirement
37
38
  requirements:
38
39
  - - "~>"
39
40
  - !ruby/object:Gem::Version
40
- version: '0.2'
41
+ version: '1.0'
41
42
  - !ruby/object:Gem::Dependency
42
43
  name: redcarpet
43
44
  requirement: !ruby/object:Gem::Requirement
@@ -52,14 +53,216 @@ dependencies:
52
53
  - - "~>"
53
54
  - !ruby/object:Gem::Version
54
55
  version: '3.2'
56
+ - !ruby/object:Gem::Dependency
57
+ name: vcr
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: pry
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '3'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '3'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rspec-rails
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '3'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '3'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rake
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: guard
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: guard-rspec
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: guard-rubocop
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ - !ruby/object:Gem::Dependency
169
+ name: guard-yard
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ type: :development
176
+ prerelease: false
177
+ version_requirements: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ - !ruby/object:Gem::Dependency
183
+ name: webmock
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - "~>"
187
+ - !ruby/object:Gem::Version
188
+ version: '1'
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: 1.17.3
192
+ type: :development
193
+ prerelease: false
194
+ version_requirements: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - "~>"
197
+ - !ruby/object:Gem::Version
198
+ version: '1'
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: 1.17.3
202
+ - !ruby/object:Gem::Dependency
203
+ name: tins
204
+ requirement: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: 1.6.0
209
+ type: :development
210
+ prerelease: false
211
+ version_requirements: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: 1.6.0
216
+ - !ruby/object:Gem::Dependency
217
+ name: simplecov
218
+ requirement: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ type: :development
224
+ prerelease: false
225
+ version_requirements: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ - !ruby/object:Gem::Dependency
231
+ name: rubocop
232
+ requirement: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - "~>"
235
+ - !ruby/object:Gem::Version
236
+ version: 0.49.0
237
+ type: :development
238
+ prerelease: false
239
+ version_requirements: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - "~>"
242
+ - !ruby/object:Gem::Version
243
+ version: 0.49.0
244
+ - !ruby/object:Gem::Dependency
245
+ name: pg
246
+ requirement: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ type: :development
252
+ prerelease: false
253
+ version_requirements: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: '0'
55
258
  description: A gem to help with hooking Contentful into your Rails application
56
259
  email:
260
+ - david.litvak@contentful.com
57
261
  - hosting@errorstudio.co.uk
58
262
  executables: []
59
263
  extensions: []
60
264
  extra_rdoc_files: []
61
265
  files:
62
- - MIT-LICENSE
63
266
  - README.md
64
267
  - Rakefile
65
268
  - app/controllers/contentful_rails/webhooks_controller.rb
@@ -94,8 +297,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
297
  - !ruby/object:Gem::Version
95
298
  version: '0'
96
299
  requirements: []
97
- rubyforge_project:
98
- rubygems_version: 2.5.1
300
+ rubygems_version: 3.0.3
99
301
  signing_key:
100
302
  specification_version: 4
101
303
  summary: A gem to help with hooking Contentful into your Rails application
data/MIT-LICENSE DELETED
@@ -1,20 +0,0 @@
1
- Copyright 2014 Error Creative Studio
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.