6. Releasing Gem
change version
run `bundle`
commit changes
run `rake release`
$ rake release
stupid_spam_protection 0.0.2 built to pkg/stupid_spam_protection-0.0.2.gem
Tagged v0.0.2
Pushed git commits and tags
Pushed stupid_spam_protection 0.0.2 to rubygems.org
7. in-memory testing with sqlite
spec/spec_helper.rb
require "active_record"
require "sqlite3”
ActiveRecord::Base.establish_connectio
n{
:adapter => "sqlite3”,
:database => ":memory:”
}
load "db/schema.rb" db/schema.rb
ActiveRecord::Schema.define do
RSpec.configure do |config| create_table "items", :force => true do |t|
config.around do |example| t.string "name”
ActiveRecord::Base.transaction do t.datetime "created_at", :null => false
example.run t.datetime "updated_at", :null => false
raise ActiveRecord::Rollback end
end
end
end
8. testing with mysql
database
spec/spec_helper.rb
begin
ActiveRecord::Base.establish_connection(config)
rescue
ActiveRecord::Base.establish_connection(config.merge('database' => nil))
ActiveRecord::Base.connection.create_database(config['database'], {
:charset => 'utf8‟,
:collation => 'utf8_unicode_ci‟})
end config = HashWithIndifferentAccess.new({
:adapter => "mysql2",
load "db/schema.rb" :host => "127.0.0.1",
:username => "root",
RSpec.configure do |config| :password => "",
# the same from previous slide :database => ”database_name”
end })
9. Tie gem to Rails app
Rails::Railtie
extend Rails framework
load all needed dependencies
several hooks methods for all needs
require "wnm_support/railtie" if defined?(Rails) lib/wnm_support.rb
module WnmSupport lib/wnm_support/railtie.rb
class Railtie < Rails::Railtie
initializer "wnm_support.view_helpers" do
ActionView::Base.send :include,
BoolToHuman
end
end
end
10. Railtie hooks 1
Plugin hooks
initializer
generators
rake_tasks
console
initializer "wnm_support.active_record_ext" do
ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.send :include,
WnmSupport::ActiveRecordExt::DestroyValidation
end
end
11. Railtie hooks 2
Rails configuration hooks
to_prepare (once in production, every request in development)
before_initialize
after_initialize
app_middleware
before_configuration
before_eager_load
generators
config.to_prepare do
AppController.send(:include,
Controller::Authentication)
end
12. What is Rails Engine ?
every rails app is an engine
Rails::Engine < Rails::Railtie
all together
gem skeleton
railtie
structure for app
dummy app for testing
assets
14. Generating Engine
rails plugin new blorgh --mountable –
full
everything (assets, controller, models,
views) are inside Blorgh namespace
module Blorgh
class Engine < ::Rails::Engine
isolate_namespace Blorgh
end
end
15. Basics commands
in root directory of the engine
bundle
rake
rspec
rails generate # generate code for engine
in spec/dummy or test/dummy location
rails console
rails server
rails generate # generate code for dummy app
16. Testing
generally as in standard rails application
engine is tested inside dummy app
small problems with factory girl
explicite model class in factory girl
include routes for request tests
FactoryGirl.define do
factory :user, :class => Blorgh ::User do
sequence(:login) { |n| "admin_#{n}" } RSpec.configure do |config|
password "too_secret" config.include Blorgh ::Engine.routes.url_helper
password_confirmation { password } end
end
end
17. Mounting Engine to host
application
Gemfile
gem “blorgh”, :path => “~/Sites/blorgh”
install migration
`rake blorgh:install:migrations`
load seeds data
Blorgh::Engine.load_seed # in rails console
require assets if needed
*= require blorgh/application # assets/stylesheets/application.css
mount to routes.rb
mount Blorgh::Engine => "/blorgh"
18. Get to engine and get
back
routes to engine from host app
prefix with engine name
example engine “blorgh”
<%= link_to “Users”, blorgh.users_path %>
routes from engine to host app
prefix with main_app
example engine “blorgh”
<%= link_to “Home page”,main_app.root_path %>
19. Overriding engine classes
Controller, Model, etc.
reopening classes
class_eval, module_eval
module MySite
class Railtie < ::Rails::Railtie
config.to_prepare do
Dir["app/decorators/**/*.rb"].each do |path|
load path app/decorators/models/blorgh/article.rb
end
end Blorgh::Article.class_eval do
end has_many :users, :class_name => „User'
end end
20. Overriding engine views
simple copy and paste view file that you want to
override to the same location in host app
21. Application Modules with
Rails Engine
every new engine means new namespace
application modules means for us more engines with
same namespace
inspiration from refinerycms
22. The same namespace
different engines
module Wnm module Wnm
module Core module Pages
class Engine < ::Rails::Engine class Engine < ::Rails::Engine
isolate_namespace Wnm isolate_namespace Wnm
engine_name :wnm_core engine_name :wnm_pages
end end
end end
rake wnm_core:install:migrations rake wnm_pages:install:migrations
Wnm::Core::Engine.load_seed Wnm::Pages::Engine.load_seed
both are nested in `Wnm` namespace
23. Developing from local
Production from git
bundler does not allow to have same package from
different sources in Gemfile
export LOAD_GEMS_FROM_LOCAL=1 .rvmrc
if ENV["LOAD_GEMS_FROM_LOCAL"] == "1" Gemfile
gem "wnm_core", :path => "~/Sites/wnm_core"
gem "wnm_pages", :path => "~/Sites/wnm_pages"
gem "wnm_customers", :path => "~/Sites/wnm_customers"
else
gem "wnm_core", :git => "git@…/wnm_core.git", :tag => "v1.0.0"
gem "wnm_pages", :git => "git@…/wnm_pages.git", :tag => "v1.0.0"
gem "wnm_customers", :git => "git@.../wnm_customers.git", :tag => "v1.0.0"
end
25. Tips
if you are overriding views heavily always prefix routes
path with engine module name
<%= link_to page.name, wnm_page.page_path(page), :title => page.name %>
use class methods instead of constants
always write full path to class/module if it is in
namespace
::ApplicationController instead of ApplicationController
testing is essential
26. Why use Rails::Engine ?
reusable code
code
hole application
assets
modular thinking
gem with MVC
faster test
testing gem in dummy app infrastructure
some well known engines
devise, kaminari, refinerycms
27. Problems
if you are bending engines weird thinks can happen
a lot of weird errors
application does not run in development mode from git
sources
tests passed, but in browser it is not running
in browser it is running but tests are throwing exceptions
overriding classes in host app
helper methods from host app does not work in overridden
views
some things from documentation does not work at all
28. Why we did this like that ?
a lot of our project are in general the same
build core for site quickly
“scaffold” for application
rails engine is infrastructure for modular application
we can have backend and frontend in the same
application module