DockerCon US 2016 - Extending Docker With APIs, Drivers, and Plugins
Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_...
-
Upload
duongthuan -
Category
Documents
-
view
232 -
download
0
Transcript of Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_...
![Page 1: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/1.jpg)
Extending Rails:Understanding and Building Plugins
Clinton R. Nixon
![Page 2: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/2.jpg)
Welcome!
Welcoming robin by Ian-S (http://flickr.com/photos/ian-s/2301022466/)
![Page 3: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/3.jpg)
What are we going to talk about?
The short
‣ How plugins work with Ruby on Rails
‣ How to find and install plugins
The long
‣ Types of plugins
‣ How to build plugins
![Page 4: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/4.jpg)
Ruby on Rails and plugins
History of plugins:
‣ Introduced with Rails 1.0 as a way to extract functionality
‣ Made it easy to distribute functionality
‣ In Rails 2.0, some core features were pulled into plugins and some plugins pulled into core
‣ In Rails 2.1, gem dependencies introduced
![Page 5: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/5.jpg)
Gem dependencies
Fulfills same role as a plugin
‣ Major disadvantage of plugins: no dependencies
‣ Your app can now depend on a gem
‣ That depends on other gems
Same techniques apply as a standard plugin
‣ Differences will be pointed out
![Page 6: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/6.jpg)
Where do you find plugins?
Unfortunately, no simple answer
‣ Rails wiki
‣ Giant list of plugins
‣ Used by script/plugindiscover
‣ Lots of out of date information
![Page 7: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/7.jpg)
Where do you find plugins?
My recommendations
‣ Agile Web Development
‣ Core Rails Plugins
‣ Technoweenie (Rick Olson)
![Page 8: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/8.jpg)
How do you install plugins?
Install from a URL:
‣ script/plugininstallhttp://example.com/plugins/make_foo
‣ script/plugininstallsvn://code.mondu.org/svn/atom_fu/trunk
‣ script/plugininstallgit://github.com/bnl/acts_as_replicator.git
![Page 9: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/9.jpg)
How do you install plugins?
Install by name:
‣ script/pluginsourcehttp://example.com/plugins/
‣ script/plugininstallmake_foo
![Page 10: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/10.jpg)
Plugin installation sources
See list of sources:
‣ script/pluginsources
Remove source:
‣ script/pluginunsourcehttp://example.com/plugins/
![Page 11: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/11.jpg)
Autodiscovering plugin sources
Scrape Rails wiki for sources:
‣ script/plugindiscover
![Page 12: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/12.jpg)
vendor/plugins trivia
Plugins are installed, by default, in vendor/plugins. However:
‣ “plugins can be nested arbitrarily deep within an unspecified number of intermediary directories” - railties/lib/rails/plugin/locator.rb
‣ So, vendor/plugins/my_organization/acts_as/acts_as_long_dir_name/ is fine.
![Page 13: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/13.jpg)
Additional plugin paths
More plugin paths can be defined as configuration.plugin_pathsinenvironment.rb‣ Overwrites default plugin paths
![Page 14: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/14.jpg)
How do you install gem plugins?
Installing gem dependencies
‣ Add config.gem'gemname' to environment.rb
‣ rakegems:install makes sure gems are installed locally
‣ rakegems:unpack puts gems in vendor/gems
‣ Even better: rakegems:unpack:dependencies
‣ Recompilation: rakegems:build
![Page 15: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/15.jpg)
Questions
Baby monkey (http://flickr.com/photos/7971389@N03/504227772/)
![Page 16: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/16.jpg)
What types of plugins are there?
‣ acts_as...
‣ ...fu
‣ controller and view helpers
‣ testing helpers
‣ resourceful plugins
‣ piggyback plugins
![Page 17: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/17.jpg)
acts_as... plugins
Adds capabilities to ActiveRecord models
‣ acts_as_versioned
‣ acts_as_paranoid
‣ acts_as_state_machine
‣ acts_as_taggable_on
![Page 18: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/18.jpg)
...fu plugins
Adds new controller capabilities and back-end processing
‣ attachment_fu
‣ GeoKit
‣ BackgrounDRb
‣ Active Merchant
‣ Exception Notification
![Page 19: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/19.jpg)
Helper plugins
Automate frequently repeated or complicated tasks; some crossover with ...fu plugins
‣ will_paginate
‣ Stickies
‣ jRails
‣ ssl_requirement
‣ TinyMCE for Rails
‣ permalink_fu
![Page 20: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/20.jpg)
Testing plugins
Adds capabilities to testing in Rails
‣ Shoulda
‣ Factory Girl
‣ Test::Spec on Rails
‣ RSpec on Rails
![Page 21: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/21.jpg)
Resourceful plugins
Plugins which contain a mini-app
‣ Savage Beast
‣ Comatose
‣ RESTful Authentication
‣ Bloget
‣ Sandstone
![Page 22: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/22.jpg)
Piggyback plugins
Plugins that alter the behavior of other plugins
‣ Also known as “evil twin plugin”
‣ Usually not published
‣ But increasingly found on GitHub
![Page 23: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/23.jpg)
Questions
Shinji the Hedgehog by Narisa (http://flickr.com/photos/narisa/508277874/)
![Page 24: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/24.jpg)
What are the parts of a plugin?
‣ README
‣ about.yml
‣ install.rb
‣ uninstall.rb
‣ init.rb
‣ lib/
‣ Rakefile
‣ tasks/
‣ generators/
‣ test/‣ anything else you want to add
![Page 25: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/25.jpg)
README and about.yml
about.yml:author: Clinton R. Nixonsummary: Adds ability to set foreign key constraints.description: "Adds ability to set foreign key constraints in the database through ActiveRecord migrations. Only works currently with MySQL, PostgreSQL, and SQLite."homepage: http://www.extendviget.com/plugin: git://github.com/vigetlabs/foreign_key_migrations.gitlicense: MITversion: 0.9rails_version: 2.0+
You can see this information with: script/plugininfoPLUGIN.
![Page 26: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/26.jpg)
install.rb & uninstall.rb
Run automatically
‣ script/plugininstall
‣ script/pluginuninstall
Usually contains code to display instructions or move files
Often not found
puts IO.read(File.join(File.dirname(__FILE__), 'README'))
![Page 27: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/27.jpg)
init.rb
Always run at Rails startup
Arbitrary Ruby code
Usually injects plugin code
ActionView::Helpers::AssetTagHelper::JAVASCRIPT_DEFAULT_SOURCES = \ ['jquery','jquery-ui','jrails']ActionView::Helpers::AssetTagHelper::reset_javascript_include_defaultrequire 'jrails'
![Page 28: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/28.jpg)
lib/
Arbitrary Ruby code to be loaded
‣ models
‣ controllers
‣ modules
Added to require path
Because of Rails’ autoloading, all properly named files here will be available without require statements
![Page 29: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/29.jpg)
Rakefile and tasks/
Rakefile contains tasks internal to the plugin
‣ Only executed from plugin directory
tasks/ contains tasks external to the plugin
‣ Available throughout the Rails environment
‣ in .rake files
![Page 30: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/30.jpg)
generators/
Contains new generators that can be run in Rails
‣ script/generate and script/destroy
Both generator definitions and generator assets
Used to automate creation of models, controllers, views, migrations, and tests
![Page 31: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/31.jpg)
test/
Tests for plugin
‣ raketest:plugins
‣ raketest:pluginsPLUGIN=plugin_name
‣ plugin Rakefile test task
![Page 32: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/32.jpg)
Anything else you want to add
License files
Further instructions
Changelog
Contribution guidelines
Gemspecs
Todo lists
Asset files (JavaScript, images)
![Page 33: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/33.jpg)
Questions
Baby Hippo by phalinn (http://flickr.com/photos/phalinn)
![Page 34: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/34.jpg)
How do you create a plugin?
script/generateplugin createvendor/plugins/test_plugin/libcreatevendor/plugins/test_plugin/taskscreatevendor/plugins/test_plugin/testcreatevendor/plugins/test_plugin/READMEcreatevendor/plugins/test_plugin/MIT‐LICENSEcreatevendor/plugins/test_plugin/Rakefilecreatevendor/plugins/test_plugin/init.rbcreatevendor/plugins/test_plugin/install.rbcreatevendor/plugins/test_plugin/uninstall.rbcreatevendor/plugins/test_plugin/lib/test_plugin.rbcreatevendor/plugins/test_plugin/tasks/test_plugin_tasks.rakecreatevendor/plugins/test_plugin/test/test_plugin_test.rb
![Page 35: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/35.jpg)
Plugins and metaprogramming
Modules
‣ include
‣ extend
alias_method and alias_method_chain
![Page 36: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/36.jpg)
Using modules
Allows you to namespace your code
‣ Common idiom: YourName::YourPlugin::ModuleName
includeYourModule‣ adds methods to class instances
extendYourModule‣ adds methods to class
![Page 37: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/37.jpg)
Common module inclusion idiommodule YourName::YourPlugin::YourModule def self.included(base) base.extend ClassMethods end def foo ... end module ClassMethods def bar ... end endend
User.send(:include, YourName::YourPlugin::YourModule)
>> user = User.new>> user.foo>> User.bar
![Page 38: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/38.jpg)
Aliasing methods
Hook onto any method using this technique
def awesome_find ... old_find(params)end
alias_method :old_find, :findalias_method :find, :awesome_find
Kind of messy and unsustainable
![Page 39: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/39.jpg)
alias_method_chain
def find_with_awesome(params) ... find_without_awesome(params)end
alias_method_chain :find, :awesome
# Equivalent to:# alias_method :find_without_awesome, :find# alias_method :find, :find_with_awesome
![Page 40: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/40.jpg)
Multiple aliasingclass Finder def find puts "found" end
def find_with_awesome puts "AWESOME" find_without_awesome end
def find_with_humility find_without_humility puts "nothing, really" end
alias_method :find_without_awesome, :find alias_method :find, :find_with_awesome alias_method :find_without_humility, :find alias_method :find, :find_with_humilityend
>>> Finder.new.findAWESOMEfoundnothing, really
![Page 41: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/41.jpg)
Multiple aliasingclass Finder def find puts "found" end
def find_with_awesome puts "AWESOME" find_without_awesome end
def find_with_humility find_without_humility puts "nothing, really" end
alias_method_chain :find, :awesome alias_method_chain :find, :humilityend
>>> Finder.new.findAWESOMEfoundnothing, really
![Page 42: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/42.jpg)
Plugin initialization order
‣ Framework is initializated (This typo was too great to leave out)
‣ Environment is loaded
‣ Gem dependencies are loaded
‣ Plugins are loaded
‣ config/initializers/*.rb (application initializers) loaded
‣ after_initialize callback executed
‣ Routes and observers loaded
![Page 43: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/43.jpg)
Plugin best practices
‣ Namespace your code
‣ Enhance, not override
‣ Leave choices to plugin users
‣ Do as little as possible
‣ Don’t do anything unexpected
![Page 44: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/44.jpg)
Questions
Chloe’s Baby #2 by mdprovost (http://flickr.com/photos/anderani/2617606614/)
![Page 45: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/45.jpg)
How do you setup a plugin?
install.rb - on installation
‣ only works when script/plugininstall used
init.rb - on application load
![Page 46: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/46.jpg)
init.rb
Run every time the Rails environment is loaded
‣ script/server
‣ script/console
‣ script/runner
![Page 47: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/47.jpg)
init.rb
For a small plugin, may be all you need
Should kick off most of your metaprogramming
Sometimes used to copy assets
‣ Don’t do this unless absolutely necessary
Should only do things you need to do every time your plugin is loaded
![Page 48: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/48.jpg)
init.rb binding
def evaluate_init_rb(initializer) if has_init_file? silence_warnings do # Allow plugins to reference the current configuration object config = initializer.configuration eval(IO.read(init_path), binding, init_path) end endend
![Page 49: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/49.jpg)
Gem plugins and init.rb
init.rb found under rails/ directory in a gem plugin
lib/ still added to load path
![Page 50: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/50.jpg)
How do you work with models?
New models dropped in lib/ will automatically get picked up and be accessible - but are not reloaded in development.
Downside: user cannot easily extend model.
![Page 51: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/51.jpg)
Model behavior in lib/
A solution:
‣ Put a module in lib/ to be included in a model class in app/models/
We can get assistance from generators if we require a class for our plugin to work.
‣ Example: acts_as_taggable_on vs. Bloget
![Page 52: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/52.jpg)
Single table inheritance as a solution
You can drop a model in lib/ intended to be inherited from.
‣ DB table will need a type column
‣ STI has its own downsides
![Page 53: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/53.jpg)
Adding behavior to multiple models
To affect all models automatically, include code in ActiveRecord::Base.
‣ Not very common usage
![Page 54: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/54.jpg)
Granting ability to add behavior
AKA acts_as...
Include module in ActiveRecord::Base, but only add one method to trigger behaviormodule ActiveRecord::Acts::Versioned def self.included(base) base.extend ClassMethods end
module ClassMethods def acts_as_versioned(options = {}, &extension) ... end endendActiveRecord::Base.send :include, ActiveRecord::Acts::Versioned
![Page 55: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/55.jpg)
acts_as_paranoid walkthrough
Baby croc by marcelgermain (http://flickr.com/photos/marcelgermain/1472148914/)
![Page 56: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/56.jpg)
How do you work with controllers?
Like models, you can drop a controller in lib/ and it will work. Again, this has the drawback that the user cannot easily edit it.
Wrapping behavior in a module and including it is smart. Inheritance also works well.
![Page 57: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/57.jpg)
Classes involved with controllers
ActionController::Base and ActionView::Base are the two classes to change.
ActionController::Base.send(:include, Stickies::ControllerActions)ActionController::Base.send(:include, Stickies::AccessHelpers)ActionView::Base.send(:include, Stickies::AccessHelpers)ActionView::Base.send(:include, Stickies::RenderHelpers)
![Page 58: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/58.jpg)
A better way to handle helpers
Since Rails 0.8.5, there’s been a better way to add helpers to controllers and views.
ActionController::Base.send(:include, Stickies::AccessHelpers)ActionController::Base.helper(Stickies::AccessHelpers)ActionController::Base.helper(Stickies::RenderHelpers)
![Page 59: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/59.jpg)
Adding behavior to controllers
Included modules are the most common way to add controller behavior.
![Page 60: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/60.jpg)
resource_this walkthrough
You can use a setup method to add parameters to your behavior, allowing for complex controller manipulation.
![Page 61: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/61.jpg)
How do you work with views?
Working with views is much like working with controllers.
Use ActionController::Base.helper to add new helpers.
![Page 62: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/62.jpg)
Changing template root
class FooController < ActionController::Base self.template_root = \
File.join(File.dirname(__FILE__), '..', 'views') end
One problem with this: the controller will expect all views - including templates and partials - to be found under this directory.
![Page 63: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/63.jpg)
Questions
Baby tiger (http://flickr.com/photos/modu_li/1788817738/)
![Page 64: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/64.jpg)
How do you work with generators?
Generators can let you make models, controllers, or anything else to stick directly into the user’s Rails app.
Put assets and generation script in generators/.
Thanks to Brian Landau
![Page 65: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/65.jpg)
Structure of generators/ directory
• generators/• plugin_name/
• plugin_name_generator.rb• templates/
• a_model.rb• a_controller.rb• some_views/
• view_file.html.erb• USAGE
![Page 66: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/66.jpg)
Two types of generators
Rails::Generator::Base‣ No required argument
‣ More basic
Rails::Generator::NamedBase‣ First argument is a class name
‣ Extra attributes available in generation
‣ Use when you're creating a specific named object
![Page 67: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/67.jpg)
Generator class structure
Should inherit from Base or NamedBase
Must define a manifest method
Can have a banner method
Can have an add_options! method
![Page 68: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/68.jpg)
NamedBase attributes
name Blog::Commentorblog/comment
class_nesting
class_nesting_depth
class_path
file_path
class_name
plural_name
singular_name
table_name
Blog
1
['blog']
blog/comment
Blog::Comment
comments
comment
blog_comments
![Page 69: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/69.jpg)
Manifest directives
‣ class_collisions
‣ directory
‣ file
‣ template
‣ migration_template
‣ route_resources
‣ readme
‣ dependency
![Page 70: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/70.jpg)
USAGE
Description:Thecomatosegeneratorcreatesamigrationforthecomatosemodel.
Thegeneratortakesamigrationnameasitsargument.ThemigrationnamemaybegiveninCamelCaseorunder_score.'add_comatose_support'isthedefault.
Thegeneratorcreatesamigrationclassindb/migrateprefixedbyitsnumberinthequeue.
Example:./script/generatecomatoseadd_comatose_support
With4existingmigrations,thiswillcreateanComatosemigrationinthefiledb/migrate/005_add_comatose_support.rb
![Page 71: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/71.jpg)
Generator templates
Use ERB to customize
‣ For ERB generating ERB: <%%[email protected]%>
‣ Generator methods available
‣ Unlike Rails’ views, generator instance variable not available
![Page 72: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/72.jpg)
Programmatically running generators
Rails::Generator::Scripts::Generate.new.run( ['authenticated', 'user', 'sessions'])
![Page 73: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/73.jpg)
How do you add new tasks?
No different from Rails
‣ Place Rake files in tasks/ named whatever.rake
The plugin Rakefile is only for Rake tasks run in the plugin directory.
‣ raketest
‣ rakerdoc
‣ rakererdoc
‣ rakeclobber_rdoc
![Page 74: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/74.jpg)
How do you deal with other plugins?
Simple trick: all plugins in vendor/plugins are loaded in alphabetical order.
![Page 75: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/75.jpg)
How do you test a plugin?
One way: require that your plugin is in a Rails app
‣ Easy
‣ Ugly
‣ Cannot specify Rails version
‣ May interfere with app classes
‣ Requires your plugin’s setup to be run
![Page 76: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/76.jpg)
Running plugin tests
From plugin dir: raketest
‣ Does not automatically load Rails environment
‣ To load Rails env:
‣ require File.join(File.dirname(__FILE__), '../../../../test/test_helper')
![Page 77: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/77.jpg)
Running plugin tests
From Rails app dir
‣ raketest:plugins
‣ raketest:pluginsPLUGIN=plugin_name
Running from Rails app dir does not run plugin’s Rakefile, so dependencies in there are not executed.
![Page 78: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/78.jpg)
Standalone testing of plugins
Helper plugins may not need a Rails app
For other plugins, you can mock out a Rails app
‣ Generators may need a full directory
‣ Model plugins can get by with a test database
‣ Controller plugins may need very little
‣ But mocking out routing can be very hard
![Page 79: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/79.jpg)
How do you package your plugin?
A public Subversion or Git repository lets users install with script/plugin.
To make a gem plugin, try Mr Bones.
PROJ.name = 'friend-feed'PROJ.authors = 'Clinton R. Nixon'PROJ.email = '[email protected]'PROJ.url = 'friend-feed.rubyforge.org'PROJ.dependencies = ['json']PROJ.version = FriendFeed::VERSION
![Page 80: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/80.jpg)
Bloget walkthrough
Baby tapir (http://flickr.com/photos/su-lin/2087767962/)
![Page 81: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/81.jpg)
Foreign Key Migrations walkthrough
Baby duck (http://flickr.com/photos/dizzygirl/437988363/)
![Page 82: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/82.jpg)
RESTful Authentication walkthrough
Uganda Mbeya (http://flickr.com/photos/youngrobv/2347565498/)
![Page 83: Extending Rails: Understanding and Building Pluginsassets.en.oreilly.com/1/event/12/Extending Rails_ Understanding and...Ruby on Rails and plugins History of plugins: ‣ Introduced](https://reader031.fdocuments.net/reader031/viewer/2022022012/5b1cc83e7f8b9ae9388b938b/html5/thumbnails/83.jpg)
Resources
‣ Peepcode’s Plugin Patterns by Andrew Stewart
‣ Addison-Wesley’s Shortcut Rails Plugins by James Adam
‣ Rick Olson: techno-weenie.net - tons of plugins and plugin building blog posts
‣ This talk: http://crnixon.org/talks/rails-plugins