Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for #render_in and ViewComponent #19

Merged
merged 2 commits into from
Apr 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.rspec_status
Gemfile.lock
gemfiles/*.lock
tmp/
65 changes: 12 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class JumbotronComponent < Renderful::Component
end
```

You can now render this component like this:
You can now render the component like this:

```ruby
RenderfulClient.render('my_entry_id')
Expand Down Expand Up @@ -113,64 +113,23 @@ also for any entries linking to it, so that they are re-rendered. This is very u
if you have a `Page` entry type that contains references to many UI components - when one of the
components is updated, you want the page to be re-rendered.

### Rails integration
### ViewComponent support

If you are using Ruby on Rails and you want to use ERB instead of including HTML in your components,
you can inherit from the Rails component:
Renderful integrates nicely with [ViewComponent](https://github.com/github/view_component) for
rendering your components:

```ruby
class JumbotronComponent < Renderful::Component::Rails
end
```

Then, create an `app/views/renderful/_jumbotron.html.erb` partial:

```erb
<div class="jumbotron">
<h1 class="display-4"><%= entry.fields[:title] %></h1>
<p class="lead"><%= entry.fields[:content] %></p>
</div>
```

As you can see, you can access the content entry via the `entry` local variable.

#### Custom renderer

Rails components use `ActionController::Base.renderer` by default, but this prevents you from
using your own helpers in components. If you want to use a different renderer instead, you can
override the `renderer` method:

```ruby
class JumbotronComponent < Renderful::Component::Rails
def renderer
ApplicationController.renderer
end
end
RenderfulClient = Renderful::Client.new(
components: {
'jumbotron' => JumbotronComponent, # JumbotronComponent inherits from ViewComponent::Base
},
)
```

#### Custom locals

If you want, you can also add your own locals:
However, keep in mind you will now have to pass a view context when rendering them:

```ruby
class JumbotronComponent < Renderful::Component::Rails
def locals
italian_title = entry.title.gsub(/hello/, 'ciao')
{ italian_title: italian_title }
end
end
```

You would then access them like regular locals:

```erb
<div class="jumbotron">
<h1 class="display-4">
<%= entry.fields[:title] %>
(<%= italian_title %>)
</h1>
<p class="lead"><%= entry.fields[:content] %></p>
</div>
RenderfulClient.render('my_entry_id', view_context: view_context)
```

## Providers
Expand Down Expand Up @@ -214,7 +173,7 @@ RenderfulClient.render('your_entry_id')
In order to integrate with Prismic, you will first need to add the `prismic.io` gem to your Gemfile:

```ruby
gem 'prismic.io'
gem 'prismic.io', require: 'prismic'
```

Now make sure to install it:
Expand Down
1 change: 0 additions & 1 deletion lib/renderful.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
require 'renderful/provider/prismic'
require 'renderful/client'
require 'renderful/component/base'
require 'renderful/component/rails'
require 'renderful/version'

module Renderful
Expand Down
14 changes: 10 additions & 4 deletions lib/renderful/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@ module Renderful
class Client
attr_reader :provider, :components, :cache

def initialize(provider:, components:, cache: Cache::Null)
def initialize(provider:, components:, cache: Cache::Null.new)
@provider = provider
@components = components
@cache = cache
end

def render(entry_id)
def render(entry_id, options = {})
cache.fetch(ContentEntry.build_cache_key(provider, id: entry_id)) do
content_entry = provider.find_entry(entry_id)
component_for_entry(content_entry).render
component = component_for_entry(content_entry)

if component.respond_to?(:render_in)
component.render_in(options.fetch(:view_context))
else
component.render
end
end
end

Expand All @@ -34,7 +40,7 @@ def component_klass_for_entry(content_entry)
end

def component_for_entry(content_entry)
component_klass_for_entry(content_entry).new(content_entry, client: self)
component_klass_for_entry(content_entry).new(entry: content_entry, client: self)
end
end
end
4 changes: 2 additions & 2 deletions lib/renderful/component/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ module Component
class Base
attr_reader :entry, :client

def initialize(entry, client:)
def initialize(entry:, client:)
@entry = entry
@client = client
end

def render
raise NotImplementedError
fail NotImplementedError
end
end
end
Expand Down
29 changes: 0 additions & 29 deletions lib/renderful/component/rails.rb

This file was deleted.

4 changes: 4 additions & 0 deletions renderful.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Gem::Specification.new do |spec|

spec.add_development_dependency 'appraisal', '~> 2.2'
spec.add_development_dependency 'bundler', '~> 2.1'
spec.add_development_dependency 'capybara', '~> 3.32'
spec.add_development_dependency 'combustion', '~> 1.1'
spec.add_development_dependency 'contentful', '~> 2.11'
spec.add_development_dependency 'gem-release', '~> 2.1'
Expand All @@ -40,4 +41,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4.1'
spec.add_development_dependency 'rubocop', '~> 0.79.0'
spec.add_development_dependency 'rubocop-rspec', '~> 1.37'
spec.add_development_dependency 'vcr', '~> 5.1'
spec.add_development_dependency 'view_component', '~> 2.2'
spec.add_development_dependency 'webmock', '~> 3.8'
end
15 changes: 15 additions & 0 deletions spec/integration/contentful_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Contentful integration test', type: :feature do
around do |example|
VCR.use_cassette('contentful', &example)
end

it 'renders Contentful entries' do
visit '/contentful'

expect(page.body.strip).to eq('Homepage')
end
end
15 changes: 15 additions & 0 deletions spec/integration/prismic_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Prismic integration test', type: :feature do
around do |example|
VCR.use_cassette('prismic', &example)
end

it 'renders Contentful entries' do
visit '/prismic'

expect(page.body.strip).to eq('Homepage')
end
end
20 changes: 20 additions & 0 deletions spec/internal/app/components/page_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

class PageComponent < ViewComponent::Base
def initialize(entry:, client:)
@entry = entry
@client = client
end

def call
normalized_fields[:title]
end

private

def normalized_fields
@normalized_fields ||= @entry.fields.with_indifferent_access.transform_values do |field|
field.respond_to?(:as_text) ? field.as_text : field
end
end
end
5 changes: 5 additions & 0 deletions spec/internal/app/controllers/pages_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class PagesController < ActionController::Base
def prismic; end
end
1 change: 1 addition & 0 deletions spec/internal/app/views/pages/contentful.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= RenderfulContentfulClient.render('6pG1BlIIaL69l0YWcDI4I5', view_context: self) %>
1 change: 1 addition & 0 deletions spec/internal/app/views/pages/prismic.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= RenderfulPrismicClient.render('XodtshAAACIACgDj', view_context: self) %>
1 change: 0 additions & 1 deletion spec/internal/app/views/renderful/_test.html.erb

This file was deleted.

22 changes: 22 additions & 0 deletions spec/internal/config/initializers/renderful.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

RenderfulPrismicClient = Renderful::Client.new(
provider: Renderful::Provider::Prismic.new(prismic: Prismic.api(
'https://renderfultest.cdn.prismic.io/api',
)),
components: {
'page' => PageComponent,
},
cache: Rails.cache,
)

RenderfulContentfulClient = Renderful::Client.new(
provider: Renderful::Provider::Contentful.new(contentful: Contentful::Client.new(
space: 'secret_space_id',
access_token: 'secret_access_token'
)),
components: {
'page' => PageComponent,
},
cache: Rails.cache,
)
3 changes: 2 additions & 1 deletion spec/internal/config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

Rails.application.routes.draw do
# Add your own routes here, or remove this file if you don't have need for it.
get 'prismic', to: 'pages#prismic'
get 'contentful', to: 'pages#contentful'
end
9 changes: 6 additions & 3 deletions spec/renderful/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,19 @@
.with(an_instance_of(String))
.and_return(entry)

component = instance_double('Renderful::Component::Base')
allow(component_klass).to receive(:new)
.with(entry, client: client)
.and_return(instance_double('Renderful::Component::Base', render: 'render_output'))
.with(entry: entry, client: client)
.and_return(component)
allow(component).to receive(:render)
.and_return('render_output')
end

context 'when a component has been registered for the provided content type' do
let(:components) { { content_type_id => component_klass } }

it 'renders the content type with its component' do
result = client.render(entry_id)
result = client.render(entry_id, view_context: 'dummy context')

expect(result).to eq('render_output')
end
Expand Down
26 changes: 0 additions & 26 deletions spec/renderful/component/rails_spec.rb

This file was deleted.

11 changes: 11 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# frozen_string_literal: true

require 'prismic'
require 'view_component'

require 'combustion'
Combustion.initialize! :action_controller, :action_view, :sprockets

require 'rspec/rails'
require 'capybara/rspec'
require 'renderful'
require 'webmock'
require 'vcr'

RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
Expand All @@ -17,3 +23,8 @@
c.syntax = :expect
end
end

VCR.configure do |config|
config.cassette_library_dir = "spec/vcr_cassettes"
config.hook_into :webmock
end
Loading