SlideShare a Scribd company logo
1 of 46
Download to read offline
Ruby on Rails:
      Plug-in Development 101
      ...and some...




http://jimeh.me/           by Jim Myhrberg
The Basics
Helpers
Controller Methods
Controllers, Helpers & Views
The Basics
to get you started
Generate a Plug-in
      $ script/generate plugin hello_world
install.rb is executed once during installation.

init.rb is the only file included by Rails.

The lib folder is your sanctuary.

Aside from hello_world.rb, place all Ruby source files in
lib/hello_world/ to avoid naming collisions.
Example: Collecta_ruby
Single-file Plug-in

 install.rb copies collecta.yml
 to Rails’ config folder during
 installation.

 init.rb requires lib/collecta.rb,
 loads settings from installed
 collecta.yml and applies them
 to the Collecta class.

 lib/collecta.rb is the ‘heart’ of
 the plug-in.
install.rb

     require "rubygems"
     require "fileutils"

     dir = File.dirname(__FILE__)
     templates = File.join(dir, "templates")
     files = [
       File.join("config", "collecta.yml")
     ]

     files.each do |file|
       if !File.exist?(File.join(RAILS_ROOT, file))
         FileUtils.cp File.join(templates, file), File.join(RAILS_ROOT, file)
       end
     end
init.rb


    if defined? Rails
      require "collecta"
      config_file = File.join(RAILS_ROOT, "config", "collecta.yml")
      if File.exist?(config_file)
        config = YAML.load_file(config_file)
        if !config[RAILS_ENV.to_s].nil? && !config[RAILS_ENV.to_s]["api_key"].nil?
          Collecta.api_key = config[RAILS_ENV.to_s]["api_key"]
        end
      end
    end
collecta.rb

        require   "rubygems"
        require   "net/http"
        require   "uri"
        require   "cgi"
        require   "json"
        require   "xml"

        class Collecta

          @@api_key = nil
          @@api_url = "http://api.collecta.com/search"

          # rest of the class...
        end
Example: Facebooker Plus
Multi-file Plug-in

 init.rb requires all needed files
 from lib folder, and calls an init
 method too boot the plugin.

 Notice how all files are located
 under lib/facebooker_plus/.
 This avoids any naming
 collisions from other plug-ins,
 gems, or system.
init.rb
 if defined? Rails
   if defined? Facebooker
     require 'facebooker_plus/facebooker_plus'
     require 'facebooker_plus/rails/fb_sig_add'
     require 'facebooker_plus/rails/controller'
     require 'facebooker_plus/rails/helper'
     require 'facebooker_plus/extensions/action_controller'
     require 'facebooker_plus/extensions/action_view'
     require 'facebooker_plus/extensions/session'

     FacebookerPlus::Base.init(defined?(config) ? config : nil)

   else
     STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n"
   end
 end
Helpers
create or overload helpers
One of the simplest things to implement in a Plug-in.
action_view.rb
action_view.rb



     ActionView::Base.send(:include, FacebookerPlus::Rails::Helper)
helper.rb
helper.rb

  module FacebookerPlus
    module Rails
      module Helper

        def url_for(options = {})
          options.is_a?(Hash) ? super(options) : fb_sig_add(super(options))
        end

        def form_for(record_or_name_or_array, *args, &proc)
          args[0][:url] = fb_sig_add(args[0][:url]) if !args[0][:url].nil?
          super(record_or_name_or_array, *args, &proc)
        end

      end
    end
  end
Controller Methods
access custom methods in all controllers
Makes it easy to control different aspects of your plug-
in from within controllers.

Easily create global before/after filters which run from
your plug-in.

Create class methods to enable/disable your plugin on
a per-controller basis.
action_controller.rb
action_controller.rb

     module ::ActionController
       class Base
         def self.inherited_with_facebooker_plus(subclass)
           inherited_without_facebooker_plus(subclass)
           if subclass.to_s == "ApplicationController"
             subclass.send(:include, FacebookerPlus::Rails::Controller)
           end
         end
         class << self
           alias_method_chain :inherited, :facebooker_plus
         end
       end
     end
controller.rb
controller.rb
module FacebookerPlus
  module Rails
    module Controller
      def self.included(controller)
        controller.extend ClassMethods
      end
      def send_p3p_headers
        if !params[:fb_sig_in_iframe].blank?
          headers['P3P'] = 'CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"'
        end
      end
      def url_for(options = {})
        fb_sig_add(super(options)) rescue super(options)
      end
      module ClassMethods
        def init_facebooker_plus(options = {})
          before_filter :send_p3p_headers
        end
      end
    end
  end
end
Fancy initialization
application_controller.rb



        class ApplicationController < ActionController::Base

          init_facebooker_plus(:app_class => "App")

        end
application_controller.rb



        class ApplicationController < ActionController::Base

          init_facebooker_plus(:app_class => "App")

        end
controller.rb
 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
       end
       def set_facebooker_plus_options(options = {})
         @facebooker_plus_options = options
       end
       def apply_facebooker_options(options = {})
         if @facebooker_plus_options.has_key?(:app_class) then end
       end
       def create_session_cookie_if_needed # magic happens here
       end
       module ClassMethods
         def init_facebooker_plus(options = {})
           before_filter { |controller| controller.set_facebooker_plus_options(options) }
           before_filter :create_session_cookie_if_needed
           before_filter :apply_facebooker_options
         end
       end
     end
   end
 end
controller.rb
 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
       end
       def set_facebooker_plus_options(options = {})
         @facebooker_plus_options = options
       end
       def apply_facebooker_options(options = {})
         if @facebooker_plus_options.has_key?(:app_class) then end
       end
       def create_session_cookie_if_needed # magic happens here
       end
       module ClassMethods
         def init_facebooker_plus(options = {})
           before_filter { |controller| controller.set_facebooker_plus_options(options) }
           before_filter :create_session_cookie_if_needed
           before_filter :apply_facebooker_options
         end
       end
     end
   end
 end
controller.rb
 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
       end
       def set_facebooker_plus_options(options = {})
         @facebooker_plus_options = options
       end
       def apply_facebooker_options(options = {})
         if @facebooker_plus_options.has_key?(:app_class) then end
       end
       def create_session_cookie_if_needed # magic happens here
       end
       module ClassMethods
         def init_facebooker_plus(options = {})
           before_filter { |controller| controller.set_facebooker_plus_options(options) }
           before_filter :create_session_cookie_if_needed
           before_filter :apply_facebooker_options
         end
       end
     end
   end
 end
controller.rb
 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
       end
       def set_facebooker_plus_options(options = {})
         @facebooker_plus_options = options
       end
       def apply_facebooker_options(options = {})
         if @facebooker_plus_options.has_key?(:app_class) then end
       end
       def create_session_cookie_if_needed # magic happens here
       end
       module ClassMethods
         def init_facebooker_plus(options = {})
           before_filter { |controller| controller.set_facebooker_plus_options(options) }
           before_filter :create_session_cookie_if_needed
           before_filter :apply_facebooker_options
         end
       end
     end
   end
 end
controller.rb
 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
       end
       def set_facebooker_plus_options(options = {})
         @facebooker_plus_options = options
       end
       def apply_facebooker_options(options = {})
         if @facebooker_plus_options.has_key?(:app_class) then end
       end
       def create_session_cookie_if_needed # magic happens here
       end
       module ClassMethods
         def init_facebooker_plus(options = {})
           before_filter { |controller| controller.set_facebooker_plus_options(options) }
           before_filter :create_session_cookie_if_needed
           before_filter :apply_facebooker_options
         end
       end
     end
   end
 end
Controllers, Helpers & Views
full controllers, helpers and views in your plug-in
Very useful in some scenarios when complex
functionality is needed.

New Relic’s RPM plug-in uses it to display application
performance under http://localhost:3000/newrelic.

Decently complex to setup.
init.rb

 if defined? Rails
   if defined? Facebooker
     require 'facebooker_plus/facebooker_plus'
     require 'facebooker_plus/rails/fb_sig_add'
     require 'facebooker_plus/rails/controller'
     require 'facebooker_plus/rails/helper'
     require 'facebooker_plus/extensions/action_controller'
     require 'facebooker_plus/extensions/action_view'
     require 'facebooker_plus/extensions/session'

     FacebookerPlus::Base.init(defined?(config) ? config : nil)

   else
     STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n"
   end
 end
init.rb

 if defined? Rails
   if defined? Facebooker
     require 'facebooker_plus/facebooker_plus'
     require 'facebooker_plus/rails/fb_sig_add'
     require 'facebooker_plus/rails/controller'
     require 'facebooker_plus/rails/helper'
     require 'facebooker_plus/extensions/action_controller'
     require 'facebooker_plus/extensions/action_view'
     require 'facebooker_plus/extensions/session'

     FacebookerPlus::Base.init(defined?(config) ? config : nil)

   else
     STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n"
   end
 end
facebooker_plus.rb
facebooker_plus.rb
   module FacebookerPlus
     class Base
       def self.init(rails_config)

         controller_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'controllers')
         helper_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'helpers')
         $LOAD_PATH << controller_path
         $LOAD_PATH << helper_path

         if defined? ActiveSupport::Dependencies
           ActiveSupport::Dependencies.load_paths << controller_path
           ActiveSupport::Dependencies.load_paths << helper_path
         elsif defined? Dependencies.load_paths
           Dependencies.load_paths << controller_path
           Dependencies.load_paths << helper_path
         else
           to_stderr "ERROR: Rails version #{(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : ''} too old."
           return
         end

         if rails_config
           rails_config.controller_paths << controller_path
         else
           current_paths = ActionController::Routing.controller_paths
           if current_paths.nil? || current_paths.empty?
              to_stderr "WARNING: Unable to modify the routes in this version of Rails.   Developer mode not available."
           end
           current_paths << controller_path
         end

       end
       # more code here
     end
   end
facebooker_plus.rb



controller_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'controllers')
helper_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'helpers')
$LOAD_PATH << controller_path
$LOAD_PATH << helper_path
facebooker_plus.rb


 if defined? ActiveSupport::Dependencies
   ActiveSupport::Dependencies.load_paths << controller_path
   ActiveSupport::Dependencies.load_paths << helper_path
 elsif defined? Dependencies.load_paths
   Dependencies.load_paths << controller_path
   Dependencies.load_paths << helper_path
 else
   to_stderr "ERROR: Rails version #{(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : ''} too old."
   return
 end
facebooker_plus.rb


 if rails_config
   rails_config.controller_paths << controller_path
 else
   current_paths = ActionController::Routing.controller_paths
   if current_paths.nil? || current_paths.empty?
      to_stderr "WARNING: Unable to modify the routes in this version of Rails.   " +
        "Developer mode not available."
   end
   current_paths << controller_path
 end
controller.rb

 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
         view_path = File.join(File.dirname(__FILE__), "app", "views")
         if controller.public_methods.include?("append_view_path") # rails 2.1+
           controller.append_view_path(view_path)
         elsif controller.public_methods.include?("view_paths")    # rails 2.0+
           controller.view_paths << view_path
         else                                                      # rails <2.0
           controller.template_root = view_path
         end
       end
     end
   end
 end
controller.rb

 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
         view_path = File.join(File.dirname(__FILE__), "app", "views")
         if controller.public_methods.include?("append_view_path") # rails 2.1+
           controller.append_view_path(view_path)
         elsif controller.public_methods.include?("view_paths")    # rails 2.0+
           controller.view_paths << view_path
         else                                                      # rails <2.0
           controller.template_root = view_path
         end
       end
     end
   end
 end
The Plug-in “app” folder
Collecta_ruby source:
          http://github.com/jimeh/collecta_ruby

          Facebooker Plus source:
          http://github.com/jimeh/facebooker_plus

          Railscasts: Making a Plug-in:
          http://railscasts.com/episodes/33-making-a-plugin




email: contact@jimeh.me — twitter: @jimeh     slideshare: http://www.slideshare.net/jimeh

More Related Content

What's hot

Rails 3 Beautiful Code
Rails 3 Beautiful CodeRails 3 Beautiful Code
Rails 3 Beautiful CodeGreggPollack
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your AppLuca Mearelli
 
Drupal 7 — Circle theme
Drupal 7 — Circle themeDrupal 7 — Circle theme
Drupal 7 — Circle themeKirill Borzov
 
3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slides3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slidesMasterCode.vn
 
15.exemplu complet eloquent view add-edit-delete-search
15.exemplu complet eloquent view add-edit-delete-search15.exemplu complet eloquent view add-edit-delete-search
15.exemplu complet eloquent view add-edit-delete-searchRazvan Raducanu, PhD
 
Plug in development
Plug in developmentPlug in development
Plug in developmentLucky Ali
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010Plataformatec
 
Synapseindia reviews sharing intro cakephp
Synapseindia reviews sharing intro cakephpSynapseindia reviews sharing intro cakephp
Synapseindia reviews sharing intro cakephpSynapseindiaComplaints
 
How to quickly make REST APIs with CompoundJS
How to quickly make REST APIs with CompoundJSHow to quickly make REST APIs with CompoundJS
How to quickly make REST APIs with CompoundJSFrank Rousseau
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Elena Kolevska
 
WordPress Queries - the right way
WordPress Queries - the right wayWordPress Queries - the right way
WordPress Queries - the right wayAnthony Hortin
 
Simple Contact Us Plugin Development
Simple Contact Us Plugin DevelopmentSimple Contact Us Plugin Development
Simple Contact Us Plugin Developmentwpnepal
 
6applets And Graphics
6applets And Graphics6applets And Graphics
6applets And GraphicsAdil Jafri
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSAntonio Peric-Mazar
 
Sherlock Markup and Sammy Semantic - drupal theming forensic analysis
Sherlock Markup and Sammy Semantic - drupal theming forensic analysisSherlock Markup and Sammy Semantic - drupal theming forensic analysis
Sherlock Markup and Sammy Semantic - drupal theming forensic analysisAndreas Sahle
 

What's hot (20)

Rails 4.0
Rails 4.0Rails 4.0
Rails 4.0
 
Rails 3 Beautiful Code
Rails 3 Beautiful CodeRails 3 Beautiful Code
Rails 3 Beautiful Code
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your App
 
Drupal 7 — Circle theme
Drupal 7 — Circle themeDrupal 7 — Circle theme
Drupal 7 — Circle theme
 
3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slides3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slides
 
15.exemplu complet eloquent view add-edit-delete-search
15.exemplu complet eloquent view add-edit-delete-search15.exemplu complet eloquent view add-edit-delete-search
15.exemplu complet eloquent view add-edit-delete-search
 
Plug in development
Plug in developmentPlug in development
Plug in development
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010
 
Synapseindia reviews sharing intro cakephp
Synapseindia reviews sharing intro cakephpSynapseindia reviews sharing intro cakephp
Synapseindia reviews sharing intro cakephp
 
How to quickly make REST APIs with CompoundJS
How to quickly make REST APIs with CompoundJSHow to quickly make REST APIs with CompoundJS
How to quickly make REST APIs with CompoundJS
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
Laravel tips-2019-04
Laravel tips-2019-04Laravel tips-2019-04
Laravel tips-2019-04
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
WordPress Queries - the right way
WordPress Queries - the right wayWordPress Queries - the right way
WordPress Queries - the right way
 
Simple Contact Us Plugin Development
Simple Contact Us Plugin DevelopmentSimple Contact Us Plugin Development
Simple Contact Us Plugin Development
 
Bake by cake php2.0
Bake by cake php2.0Bake by cake php2.0
Bake by cake php2.0
 
6applets And Graphics
6applets And Graphics6applets And Graphics
6applets And Graphics
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJS
 
Sherlock Markup and Sammy Semantic - drupal theming forensic analysis
Sherlock Markup and Sammy Semantic - drupal theming forensic analysisSherlock Markup and Sammy Semantic - drupal theming forensic analysis
Sherlock Markup and Sammy Semantic - drupal theming forensic analysis
 

Similar to Rails Plugin Development 101 (...and some...)

Template rendering in rails
Template rendering in rails Template rendering in rails
Template rendering in rails Hung Wu Lo
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin GeneratorJohn Cleveley
 
Empowering users: modifying the admin experience
Empowering users: modifying the admin experienceEmpowering users: modifying the admin experience
Empowering users: modifying the admin experienceBeth Soderberg
 
Zend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolZend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolGordon Forsythe
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30fiyuer
 
Symfony2 Introduction Presentation
Symfony2 Introduction PresentationSymfony2 Introduction Presentation
Symfony2 Introduction PresentationNerd Tzanetopoulos
 
Ajax, JSF, Facelets, Eclipse & Maven tutorials
Ajax, JSF, Facelets, Eclipse & Maven tutorialsAjax, JSF, Facelets, Eclipse & Maven tutorials
Ajax, JSF, Facelets, Eclipse & Maven tutorialsRaghavan Mohan
 
Web-based application development part 31MINIMIZE .docx
Web-based application development part 31MINIMIZE .docxWeb-based application development part 31MINIMIZE .docx
Web-based application development part 31MINIMIZE .docxcelenarouzie
 
Getting started with WordPress development
Getting started with WordPress developmentGetting started with WordPress development
Getting started with WordPress developmentSteve Mortiboy
 
Curso Symfony - Clase 3
Curso Symfony - Clase 3Curso Symfony - Clase 3
Curso Symfony - Clase 3Javier Eguiluz
 
MidwestPHP 2016 - Adventures in Laravel 5
MidwestPHP 2016 - Adventures in Laravel 5 MidwestPHP 2016 - Adventures in Laravel 5
MidwestPHP 2016 - Adventures in Laravel 5 Joe Ferguson
 
Write your first WordPress plugin
Write your first WordPress pluginWrite your first WordPress plugin
Write your first WordPress pluginAnthony Montalbano
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Rupicon 2014 Action pack
Rupicon 2014 Action packRupicon 2014 Action pack
Rupicon 2014 Action packrupicon
 
Sahana Eden - Introduction to the Code
Sahana Eden - Introduction to the CodeSahana Eden - Introduction to the Code
Sahana Eden - Introduction to the CodeAidIQ
 
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018Damien Carbery
 
WordPress Plugin development
WordPress Plugin developmentWordPress Plugin development
WordPress Plugin developmentMostafa Soufi
 

Similar to Rails Plugin Development 101 (...and some...) (20)

Template rendering in rails
Template rendering in rails Template rendering in rails
Template rendering in rails
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin Generator
 
Empowering users: modifying the admin experience
Empowering users: modifying the admin experienceEmpowering users: modifying the admin experience
Empowering users: modifying the admin experience
 
Zend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolZend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_Tool
 
Django design-patterns
Django design-patternsDjango design-patterns
Django design-patterns
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30
 
Symfony2 Introduction Presentation
Symfony2 Introduction PresentationSymfony2 Introduction Presentation
Symfony2 Introduction Presentation
 
Ajax, JSF, Facelets, Eclipse & Maven tutorials
Ajax, JSF, Facelets, Eclipse & Maven tutorialsAjax, JSF, Facelets, Eclipse & Maven tutorials
Ajax, JSF, Facelets, Eclipse & Maven tutorials
 
Web-based application development part 31MINIMIZE .docx
Web-based application development part 31MINIMIZE .docxWeb-based application development part 31MINIMIZE .docx
Web-based application development part 31MINIMIZE .docx
 
Comilla University
Comilla University Comilla University
Comilla University
 
Getting started with WordPress development
Getting started with WordPress developmentGetting started with WordPress development
Getting started with WordPress development
 
Curso Symfony - Clase 3
Curso Symfony - Clase 3Curso Symfony - Clase 3
Curso Symfony - Clase 3
 
MidwestPHP 2016 - Adventures in Laravel 5
MidwestPHP 2016 - Adventures in Laravel 5 MidwestPHP 2016 - Adventures in Laravel 5
MidwestPHP 2016 - Adventures in Laravel 5
 
Django Vs Rails
Django Vs RailsDjango Vs Rails
Django Vs Rails
 
Write your first WordPress plugin
Write your first WordPress pluginWrite your first WordPress plugin
Write your first WordPress plugin
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Rupicon 2014 Action pack
Rupicon 2014 Action packRupicon 2014 Action pack
Rupicon 2014 Action pack
 
Sahana Eden - Introduction to the Code
Sahana Eden - Introduction to the CodeSahana Eden - Introduction to the Code
Sahana Eden - Introduction to the Code
 
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018
 
WordPress Plugin development
WordPress Plugin developmentWordPress Plugin development
WordPress Plugin development
 

Recently uploaded

Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 

Recently uploaded (20)

Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 

Rails Plugin Development 101 (...and some...)

  • 1. Ruby on Rails: Plug-in Development 101 ...and some... http://jimeh.me/ by Jim Myhrberg
  • 3. The Basics to get you started
  • 4. Generate a Plug-in $ script/generate plugin hello_world
  • 5. install.rb is executed once during installation. init.rb is the only file included by Rails. The lib folder is your sanctuary. Aside from hello_world.rb, place all Ruby source files in lib/hello_world/ to avoid naming collisions.
  • 7. Single-file Plug-in install.rb copies collecta.yml to Rails’ config folder during installation. init.rb requires lib/collecta.rb, loads settings from installed collecta.yml and applies them to the Collecta class. lib/collecta.rb is the ‘heart’ of the plug-in.
  • 8. install.rb require "rubygems" require "fileutils" dir = File.dirname(__FILE__) templates = File.join(dir, "templates") files = [ File.join("config", "collecta.yml") ] files.each do |file| if !File.exist?(File.join(RAILS_ROOT, file)) FileUtils.cp File.join(templates, file), File.join(RAILS_ROOT, file) end end
  • 9. init.rb if defined? Rails require "collecta" config_file = File.join(RAILS_ROOT, "config", "collecta.yml") if File.exist?(config_file) config = YAML.load_file(config_file) if !config[RAILS_ENV.to_s].nil? && !config[RAILS_ENV.to_s]["api_key"].nil? Collecta.api_key = config[RAILS_ENV.to_s]["api_key"] end end end
  • 10. collecta.rb require "rubygems" require "net/http" require "uri" require "cgi" require "json" require "xml" class Collecta @@api_key = nil @@api_url = "http://api.collecta.com/search" # rest of the class... end
  • 12. Multi-file Plug-in init.rb requires all needed files from lib folder, and calls an init method too boot the plugin. Notice how all files are located under lib/facebooker_plus/. This avoids any naming collisions from other plug-ins, gems, or system.
  • 13. init.rb if defined? Rails if defined? Facebooker require 'facebooker_plus/facebooker_plus' require 'facebooker_plus/rails/fb_sig_add' require 'facebooker_plus/rails/controller' require 'facebooker_plus/rails/helper' require 'facebooker_plus/extensions/action_controller' require 'facebooker_plus/extensions/action_view' require 'facebooker_plus/extensions/session' FacebookerPlus::Base.init(defined?(config) ? config : nil) else STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n" end end
  • 15. One of the simplest things to implement in a Plug-in.
  • 17. action_view.rb ActionView::Base.send(:include, FacebookerPlus::Rails::Helper)
  • 19. helper.rb module FacebookerPlus module Rails module Helper def url_for(options = {}) options.is_a?(Hash) ? super(options) : fb_sig_add(super(options)) end def form_for(record_or_name_or_array, *args, &proc) args[0][:url] = fb_sig_add(args[0][:url]) if !args[0][:url].nil? super(record_or_name_or_array, *args, &proc) end end end end
  • 20. Controller Methods access custom methods in all controllers
  • 21. Makes it easy to control different aspects of your plug- in from within controllers. Easily create global before/after filters which run from your plug-in. Create class methods to enable/disable your plugin on a per-controller basis.
  • 23. action_controller.rb module ::ActionController class Base def self.inherited_with_facebooker_plus(subclass) inherited_without_facebooker_plus(subclass) if subclass.to_s == "ApplicationController" subclass.send(:include, FacebookerPlus::Rails::Controller) end end class << self alias_method_chain :inherited, :facebooker_plus end end end
  • 25. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def send_p3p_headers if !params[:fb_sig_in_iframe].blank? headers['P3P'] = 'CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"' end end def url_for(options = {}) fb_sig_add(super(options)) rescue super(options) end module ClassMethods def init_facebooker_plus(options = {}) before_filter :send_p3p_headers end end end end end
  • 27. application_controller.rb class ApplicationController < ActionController::Base init_facebooker_plus(:app_class => "App") end
  • 28. application_controller.rb class ApplicationController < ActionController::Base init_facebooker_plus(:app_class => "App") end
  • 29. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def set_facebooker_plus_options(options = {}) @facebooker_plus_options = options end def apply_facebooker_options(options = {}) if @facebooker_plus_options.has_key?(:app_class) then end end def create_session_cookie_if_needed # magic happens here end module ClassMethods def init_facebooker_plus(options = {}) before_filter { |controller| controller.set_facebooker_plus_options(options) } before_filter :create_session_cookie_if_needed before_filter :apply_facebooker_options end end end end end
  • 30. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def set_facebooker_plus_options(options = {}) @facebooker_plus_options = options end def apply_facebooker_options(options = {}) if @facebooker_plus_options.has_key?(:app_class) then end end def create_session_cookie_if_needed # magic happens here end module ClassMethods def init_facebooker_plus(options = {}) before_filter { |controller| controller.set_facebooker_plus_options(options) } before_filter :create_session_cookie_if_needed before_filter :apply_facebooker_options end end end end end
  • 31. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def set_facebooker_plus_options(options = {}) @facebooker_plus_options = options end def apply_facebooker_options(options = {}) if @facebooker_plus_options.has_key?(:app_class) then end end def create_session_cookie_if_needed # magic happens here end module ClassMethods def init_facebooker_plus(options = {}) before_filter { |controller| controller.set_facebooker_plus_options(options) } before_filter :create_session_cookie_if_needed before_filter :apply_facebooker_options end end end end end
  • 32. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def set_facebooker_plus_options(options = {}) @facebooker_plus_options = options end def apply_facebooker_options(options = {}) if @facebooker_plus_options.has_key?(:app_class) then end end def create_session_cookie_if_needed # magic happens here end module ClassMethods def init_facebooker_plus(options = {}) before_filter { |controller| controller.set_facebooker_plus_options(options) } before_filter :create_session_cookie_if_needed before_filter :apply_facebooker_options end end end end end
  • 33. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def set_facebooker_plus_options(options = {}) @facebooker_plus_options = options end def apply_facebooker_options(options = {}) if @facebooker_plus_options.has_key?(:app_class) then end end def create_session_cookie_if_needed # magic happens here end module ClassMethods def init_facebooker_plus(options = {}) before_filter { |controller| controller.set_facebooker_plus_options(options) } before_filter :create_session_cookie_if_needed before_filter :apply_facebooker_options end end end end end
  • 34. Controllers, Helpers & Views full controllers, helpers and views in your plug-in
  • 35. Very useful in some scenarios when complex functionality is needed. New Relic’s RPM plug-in uses it to display application performance under http://localhost:3000/newrelic. Decently complex to setup.
  • 36. init.rb if defined? Rails if defined? Facebooker require 'facebooker_plus/facebooker_plus' require 'facebooker_plus/rails/fb_sig_add' require 'facebooker_plus/rails/controller' require 'facebooker_plus/rails/helper' require 'facebooker_plus/extensions/action_controller' require 'facebooker_plus/extensions/action_view' require 'facebooker_plus/extensions/session' FacebookerPlus::Base.init(defined?(config) ? config : nil) else STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n" end end
  • 37. init.rb if defined? Rails if defined? Facebooker require 'facebooker_plus/facebooker_plus' require 'facebooker_plus/rails/fb_sig_add' require 'facebooker_plus/rails/controller' require 'facebooker_plus/rails/helper' require 'facebooker_plus/extensions/action_controller' require 'facebooker_plus/extensions/action_view' require 'facebooker_plus/extensions/session' FacebookerPlus::Base.init(defined?(config) ? config : nil) else STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n" end end
  • 39. facebooker_plus.rb module FacebookerPlus class Base def self.init(rails_config) controller_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'controllers') helper_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'helpers') $LOAD_PATH << controller_path $LOAD_PATH << helper_path if defined? ActiveSupport::Dependencies ActiveSupport::Dependencies.load_paths << controller_path ActiveSupport::Dependencies.load_paths << helper_path elsif defined? Dependencies.load_paths Dependencies.load_paths << controller_path Dependencies.load_paths << helper_path else to_stderr "ERROR: Rails version #{(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : ''} too old." return end if rails_config rails_config.controller_paths << controller_path else current_paths = ActionController::Routing.controller_paths if current_paths.nil? || current_paths.empty? to_stderr "WARNING: Unable to modify the routes in this version of Rails. Developer mode not available." end current_paths << controller_path end end # more code here end end
  • 40. facebooker_plus.rb controller_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'controllers') helper_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'helpers') $LOAD_PATH << controller_path $LOAD_PATH << helper_path
  • 41. facebooker_plus.rb if defined? ActiveSupport::Dependencies ActiveSupport::Dependencies.load_paths << controller_path ActiveSupport::Dependencies.load_paths << helper_path elsif defined? Dependencies.load_paths Dependencies.load_paths << controller_path Dependencies.load_paths << helper_path else to_stderr "ERROR: Rails version #{(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : ''} too old." return end
  • 42. facebooker_plus.rb if rails_config rails_config.controller_paths << controller_path else current_paths = ActionController::Routing.controller_paths if current_paths.nil? || current_paths.empty? to_stderr "WARNING: Unable to modify the routes in this version of Rails. " + "Developer mode not available." end current_paths << controller_path end
  • 43. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods view_path = File.join(File.dirname(__FILE__), "app", "views") if controller.public_methods.include?("append_view_path") # rails 2.1+ controller.append_view_path(view_path) elsif controller.public_methods.include?("view_paths") # rails 2.0+ controller.view_paths << view_path else # rails <2.0 controller.template_root = view_path end end end end end
  • 44. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods view_path = File.join(File.dirname(__FILE__), "app", "views") if controller.public_methods.include?("append_view_path") # rails 2.1+ controller.append_view_path(view_path) elsif controller.public_methods.include?("view_paths") # rails 2.0+ controller.view_paths << view_path else # rails <2.0 controller.template_root = view_path end end end end end
  • 46. Collecta_ruby source: http://github.com/jimeh/collecta_ruby Facebooker Plus source: http://github.com/jimeh/facebooker_plus Railscasts: Making a Plug-in: http://railscasts.com/episodes/33-making-a-plugin email: contact@jimeh.me — twitter: @jimeh slideshare: http://www.slideshare.net/jimeh