Skip to content

Instantly share code, notes, and snippets.

@amcaplan
Last active November 5, 2015 19:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amcaplan/0841065fdb69966b860f to your computer and use it in GitHub Desktop.
Save amcaplan/0841065fdb69966b860f to your computer and use it in GitHub Desktop.
Rails Engines

Setting Up

$ rails plugin new forget --mountable --skip-test-unit --dummy-path=spec/dummy
$ git init
$ git add .
$ git commit -m "Initial commit - generate a Rails Engine called Forget"

In forget.gemspec:

s.add_development_dependency "rspec-rails", "~> 3.0"
$ bundle install
$ rails generate rspec:install

In engine.rb:

config.generators do |g|
  g.test_framework :rspec
end
$ rspec
$ git add .
$ git commit -m "Set up RSpec"

First Requirement: Set Up an Endpoint

$ rails g controller cache --no-helper --no-controller-specs --no-view-specs
$ rails g rspec:request cache_clear_request

Fill in spec/requests/forget/cache_clear_requests_spec.rb:

require 'rails_helper'

RSpec.describe "CacheClearRequests", type: :request do
  context 'Given a value in the Rails cache' do
    let(:key) { 'key' }
    let(:value) { 'value' }

    before do
      Rails.cache.write(key, value)
      expect(Rails.cache.read(key)).to eq(value)
    end

    context 'When a request is made to clear the cache' do
      before do
        delete('/cache')
      end

      it 'removes the value from the cache' do
        expect(Rails.cache.read(key)).to be_nil
      end
    end
  end
end

Change line 3 of spec/rails_helper.rb:

require File.expand_path('../../spec/dummy/config/environment', __FILE__)

Seek correct path in spec/request/cache_clear_request_spec.rb:

delete(forget.cache_path)

Add route in config/routes.rb:

delete '/cache', to: 'cache#destroy'

Add action to CacheController:

def destroy
end

Add another test to assert a successful response:

it 'returns a 204 status' do
  expect(response.status).to eq(204)
end

Fill out the controller action, second line first:

def destroy
  Rails.cache.clear
  head :no_content
end
$ git add .
$ git commit -m "Add endpoint to clear the cache"

Second Requirement: Auditing!

$ rails g model cache_clearing
$ rspec
$ rake db:migrate

Expand the request specs:

require 'rails_helper'

context 'Given a value in the Rails cache' do
  let(:key) { 'key' }
  let(:value) { 'value' }

  before do
    Rails.cache.write(key, value)
    expect(Rails.cache.read(key)).to eq(value)
    expect(Forget::CacheClearing.count).to eq(0)
  end

  context 'When a request is made to clear the cache' do
    before do
      delete(forget.cache_path)
    end

    it 'returns a 204 status' do
      expect(response.status).to eq(204)
    end

    it 'removes the value from the cache' do
      expect(Rails.cache.read(key)).to be_nil
    end

    it 'saved a record that the cache was cleared' do
      expect(Forget::CacheClearing.count).to eq(1)
    end
  end
end

Make it pass in CacheController:

def destroy
  Rails.cache.clear
  Forget::CacheClearing.create!
  head :no_content
end
$ git add .
$ git commit -m "Save timestamps of cache clearings with a model"

Third Requirement: Big Button

$ rails g rspec:feature clear_cache_button

Update forget.gemspec:

s.add_development_dependency "capybara", "~> 2.5.0"

Fill out Cache-Clearing Button spec:

require 'rails_helper'

RSpec.feature "ClearCacheButtons", type: :feature do
  scenario 'clearing the cache' do
    key = :key
    value = 'cached_value'

    Rails.cache.write(key, value)
    expect(Rails.cache.read(key)).to eq(value)

    visit forget.cache_new_path
    click_button('Clear the Cache')

    expect(Rails.cache.read(key)).to be_nil
  end
end

Add new route:

get '/cache/new', to: 'cache#new'

Add controller action to CacheController:

def new
end

Add a new view, app/views/forget/cache/new.html.erb:

<%= button_to 'Clear the Cache', forget.cache_path, method: :delete %>
$ git add .
$ git commit -m "Add button to clear the cache"

Integrate into another app!

Switch to cacher (must be found in the same directory as forget).

Update the Gemfile:

gem 'forget', path: '../forget'
$ bundle install

When it fails, go back to forget and fill out forget.gemspec.

-  s.homepage    = "TODO"
-  s.summary     = "TODO: Summary of Forget."
-  s.description = "TODO: Description of Forget."
+  s.homepage    = "http://railsremoteconf.com"
+  s.summary     = "Summary of Forget."
+  s.description = "Description of Forget."
$ git add .
$ git commit -m "Fix gemspec so it's valid"

Now switch back to cacher.

Add the route to config/routes.rb:

mount Forget::Engine => '/forget'

Or we can do this instead! 😁

mount Forget::Engine => '/sparkly_dinosaurs'

Time to demo! Run the rails server, show what's at the root route. Now go to /sparkly_dinosaurs/cache/new and click the button... Oh no, that didn't work! Copy over and run the migration:

$ rake forget:install:migrations
$ rake db:migrate

Restart the rails server, try again. We're in business! The number at the root route is cleared by the cache-clearing button!

Requirement: Red Button

Add some CSS to app/assets/stylesheets/forget/cache.css:

.button_to input[type=submit] {
  background: #fa5503;
  background-image: -webkit-linear-gradient(top, #fa5503, #ad2626);
  background-image: -moz-linear-gradient(top, #fa5503, #ad2626);
  background-image: -ms-linear-gradient(top, #fa5503, #ad2626);
  background-image: -o-linear-gradient(top, #fa5503, #ad2626);
  background-image: linear-gradient(to bottom, #fa5503, #ad2626);
  -webkit-border-radius: 8;
  -moz-border-radius: 8;
  border-radius: 8px;
  font-family: Arial;
  color: #ffffff;
  font-size: 23px;
  padding: 10px 20px 10px 20px;
  text-decoration: none;
}
$ git add .
$ git commit -m "Make the button nicer by adding CSS"

Refresh in cacher - much prettier!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment