Skip to content
Closed
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
87 changes: 87 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,93 @@ watch them for changes as well.
directories %w[app config lib spec your-appname/app]
```

## Integrating with `ember-cli-deploy`

The EmberCLI community recently unified the various deployment techniques into a
single, core-team supported project: [ember-cli-deploy][ember-cli-deploy].

This project attempts to streamline the process of pushing and serving
EmberCLI-built static assets.

To integrate with `ember-cli-deploy`'s ["Lightning Fast Deploys"][lightning]
(using the Redis adapter), instantiate an `EmberCLI::Deploy` in your controller:

```ruby
require "ember-cli/deploy"

class ApplicationController < ActionController::Base
def index
@deploy = EmberCLI::Deploy.new(namespace: "frontend")

render text: @deploy.html, layout: false
end
end
```

`EmberCLI::Deploy` takes a `namespace` (the name of your app declared in your
initializer) and handles all interaction with the Redis instance.

This is great for `staging` and `production` deploys, but introduces an extra
step in the feedback loop during development.

Luckily, `EmberCLI::Deploy` also accepts an `index_html` override, which will
replace the call to the Redis instance. This allows integration with the normal
`ember-cli-rails` workflow:

```ruby
require "ember-cli/deploy"

class ApplicationController < ActionController::Base
def index
@deploy = EmberCLI::Deploy.new(
namespace: "frontend",
index_html: index_html,
)

render text: @deploy.html, layout: false
end

private

def index_html
if serve_with_ember_cli_rails?
render_to_string(:index)
end
end

def serve_with_ember_cli_rails?
! %w[production staging].include?(Rails.env)
end
end
```

Additionally, having access to the outbound HTML beforehand also enables
controllers to inject additional markup, such as metadata, CSRF tokens, or
analytics tags:


```ruby
require "ember-cli/deploy"

class ApplicationController < ActionController::Base
def index
@deploy = EmberCLI::Deploy.new(
namespace: "frontend",
index_html: index_html,
)

@deploy.append_to_head(render_to_string(partial: "my_csrf_and_metadata")
@deploy.append_to_body(render_to_string(partial: "my_analytics")

render text: @deploy.html, layout: false
end
# ...
end
```

[ember-cli-deploy]: https://github.com/ember-cli/ember-cli-deploy
[lightning]: https://github.com/ember-cli/ember-cli-deploy#lightning-approach-workflow

## Heroku

In order to deploy EmberCLI Rails app to Heroku:
Expand Down
5 changes: 5 additions & 0 deletions ember-cli-rails.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,10 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = ">= 1.9.3"

spec.add_dependency "railties", ">= 3.1", "< 5"
spec.add_dependency "redis"
spec.add_dependency "sprockets", ">= 2.0"

spec.add_development_dependency "rspec", "~> 3.1.0"
spec.add_development_dependency "climate_control"
spec.add_development_dependency "fakeredis"
end
79 changes: 79 additions & 0 deletions lib/ember-cli/deploy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
require "active_support/core_ext/object/blank"
require "ember-cli/page"

module EmberCLI
class Deploy
def initialize(namespace:, index_html: nil)
@namespace = namespace
@index_html = index_html
@body_markup = []
@head_markup = []
end

def append_to_body(markup)
body_markup << markup
end

def append_to_head(markup)
head_markup << markup
end

def html
if index_html.present?
page = Page.new(html: index_html)

body_markup.each do |markup|
page.append_to_body(markup)
end

head_markup.each do |markup|
page.append_to_head(markup)
end

page.build
else
index_html_missing!
end
end

private

attr_reader :body_markup, :head_markup, :namespace

def index_html
@index_html ||= redis.get(deploy_key).presence
end

def current_key
"#{namespace}:current"
end

def deploy_key
redis.get(current_key).presence || deployment_not_activated!
end

def redis
Redis.new(url: ENV.fetch("REDIS_URL"))
end

def index_html_missing!
message = <<-FAIL
HTML for #{deploy_key} is missing.

Did you forget to call `ember deploy`?
FAIL

raise KeyError, message
end

def deployment_not_activated!
message = <<-FAIL
#{current_key} is empty.

Did you forget to call `ember deploy:activate`?
FAIL

raise KeyError, message
end
end
end
53 changes: 53 additions & 0 deletions lib/ember-cli/page.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
module EmberCLI
class Page
def initialize(html:)
@html = html.clone
@body_markup = []
@head_markup = []
end

def build
if has_head?
head_markup.each do |markup|
html.insert(head_position, markup)
end
end

if has_body?
body_markup.each do |markup|
html.insert(body_position, markup)
end
end

html
end

def append_to_body(markup)
body_markup << markup
end

def append_to_head(markup)
head_markup << markup
end

private

attr_reader :body_markup, :head_markup, :html

def has_head?
html.include?("<head")
end

def has_body?
html.include?("<body")
end

def head_position
html.index(">", html.index("<head")) + 1
end

def body_position
html.index(">", html.index("<body")) + 1
end
end
end
108 changes: 108 additions & 0 deletions spec/lib/ember-cli/deploy_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
require "spec_helper"
require "ember-cli/deploy"

describe EmberCLI::Deploy do
describe "#append_to_head" do
it "injects the string into the <head> tag" do
provided_html = "<html><head></head></html>"
ember_cli_deploy = build_ember_cli_deploy(index_html: provided_html)

ember_cli_deploy.append_to_head("<script></script>")
index_html = ember_cli_deploy.html

expect(index_html).to eq("<html><head><script></script></head></html>")
end
end

describe "#append_to_body" do
it "injects the string into the <body> tag" do
provided_html = "<html><body></body></html>"
ember_cli_deploy = build_ember_cli_deploy(index_html: provided_html)

ember_cli_deploy.append_to_body("<script></script>")
index_html = ember_cli_deploy.html

expect(index_html).to eq("<html><body><script></script></body></html>")
end
end

describe "#html" do
context "when the HTML is provided" do
it "returns the HTML" do
provided_html = "<p>Hello World</p>"
ember_cli_deploy = build_ember_cli_deploy(index_html: provided_html)

index_html = ember_cli_deploy.html

expect(index_html).to eq(provided_html)
end
end

context "when the keys are present" do
it "retrieves the HTML from Redis" do
stub_index_html(html: "<p>Hello World</p>")
ember_cli_deploy = build_ember_cli_deploy

index_html = ember_cli_deploy.html

expect(index_html).to eq("<p>Hello World</p>")
end
end

context "when the current index is missing" do
it "raises a helpful exception" do
deploy_key = "#{namespace}:abc123"
stub_index_html(html: nil, deploy_key: deploy_key)
ember_cli_deploy = build_ember_cli_deploy

expect { ember_cli_deploy.html }.to raise_error(
/HTML for #{deploy_key} is missing/
)
end
end

context "when the current key is unset" do
it "raises a helpful exception" do
stub_current_key(nil)
ember_cli_deploy = build_ember_cli_deploy

expect { ember_cli_deploy.html }.to raise_error(
/#{namespace}:current is empty/
)
end
end
end

around :each do |example|
with_modified_env REDIS_URL: "redis://localhost:1234" do
example.run
end
end

def build_ember_cli_deploy(index_html: nil)
EmberCLI::Deploy.new(namespace: namespace, index_html: index_html)
end

def namespace
"human-health"
end

def stub_current_key(deploy_key)
current_key = "#{namespace}:current"

redis.set(current_key, deploy_key)
end

def stub_index_html(deploy_key: "#{namespace}:123", html:)
stub_current_key(deploy_key)
redis.set(deploy_key, html)
end

def redis
Redis.new(url: ENV["REDIS_URL"])
end

def with_modified_env(options, &block)
ClimateControl.modify(options, &block)
end
end
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require "fakeredis"
require "climate_control"