Component Development Tutorial

Version

This document applies to Rubricks-0.5.x

Introduction

Premise knowledge

You need the following knowledge to read this tutorial.

  • Ruby
  • Ruby on Rails(Here in after we call 'Rails')
  • Basic administration of Rubricks

Preparation

Please refer to Install Guide and prepare your development environment.

What is a component?

A component in Ruburicks is a unit which supplies extended functionality. You can use these ones combined.

+Image01 Component Architecture

Hello World

First of all, we make "Hello World" component and understand the atmosphere of the component development.

+Image02 Hello World Component

Generator

Ruburicks has generator to aid component development. You can generate skeletons of the component.

+List01 Format of rubricks_component generator

 ruby script/generate rubricks_controller [component_name/controller_name] [action_name_list]

Note: You can specify more than one action_name by using comma.

+List02 Generate HelloWorld Component

> ruby script/generate rubricks_component hello_world greet main
      create  components/hello_world
      create  components/hello_world/greet
      create  components/hello_world/languages
      create  components/hello_world/_install
      create  components/hello_world/_install/db
      create  components/hello_world/_install/images
      create  components/hello_world/greet_controller.rb
      create  components/hello_world/greet_helper.rb
      create  components/hello_world/greet/main.rhtml
      create  components/hello_world/languages/japanese.rb
      create  components/hello_world/languages/english.rb
      create  components/hello_world/_install/component_info.rb
      create  components/hello_world/_install/db/001_hello_world_schema.rb
      create  components/hello_world/_install/images/hello_world.gif
      create  components/hello_world/_install/images/hello_world_active.gif
     created  install/hello_world.rzip
== HelloWorldSchema: migrating ================================================
== HelloWorldSchema: migrated (0.0000s) =======================================

   installed  hello_world

The controller and view are generated for hello_wold component.

Implementation of the controller

You don't need to modify this controller if you wanna display only 'Hello World'. But in this tutorial, let's try adding current time with 'Hello World'. Please modify generated greet controller as follow.

+List03 /components/hello_world/greet_controller.rb

class HelloWorld::GreetController < ApplicationController
  define_page
  uses_component_template_root

  def main
    @time = Time.now.to_s.toutf8
  end

Implementation of the view

It is same as general view of the Rails mostly, except that only part of the page is necessary.

+List04 /components/hello_world/greet/main.rhtml

Hello World<br>
The current time is <%= @time %>

Operation check

Implementation of the Hello World is completed. Let's boot WEBrick and access.

Making news component

From this section, get into more detailed explanation through actual component development by developping the news component.

Specification

Functions of the news component are as follows.

  • Display 'Post News' and 'Refer News' menu.
  • User can post news.
  • Posted news is displayed in news block.

Design of the application

A table is needed to save posted news used by the news component. Start up MySQL and create news_item table.

+List05 SQL for news items table

CREATE TABLE news_items (
  id INTEGER UNSIGNED NOT NULL DEFAULT null AUTO_INCREMENT,       /* ID */
  title VARCHAR(192) NOT NULL,                                    /* Title */
  rubricks_user_id INTEGER(10) NOT NULL,                          /* Poster ID */
  article TEXT NOT NULL,                                          /* News */
  created_at DATETIME NOT NULL,                                   /* Last Modified Date */
  PRIMARY KEY(id)
)
TYPE=InnoDB;

Implementation of basic functions

Generate skelton

+List06 Generate News Component

> ruby script/generate rubricks_component news post main
      create  components/news
      create  components/news/post
      create  components/news/languages
      create  components/news/_install
      create  components/news/_install/db
      create  components/news/_install/images
      create  components/news/post_controller.rb
      create  components/news/post_helper.rb
      create  components/news/post/main.rhtml
      create  components/news/languages/japanese.rb
      create  components/news/languages/english.rb
      create  components/news/_install/component_info.rb
      create  components/news/_install/db/001_news_schema.rb
      create  components/news/_install/images/news.gif
      create  components/news/_install/images/news_active.gif
     created  install/news.rzip
== NewsSchema: migrating ======================================================
== NewsSchema: migrated (0.0000s) =============================================

   installed  news

Implementation of the model

Next step is the creation of the model to access news item table.

+List07 Format of rubricks_model generator

 ruby script/generate rubricks_model [component_name] [model_name]

+List08 Generate model

> ruby script/generate rubricks_model news news_item
      exists  components/news
      create  components/news/news_item.rb

Add index controller

Create controller to view news by using generate command.

+List09 Format of rubricks_controller generator

 ruby script/generate rubricks_controller [component_name] [controller_name] [action_name_list]

+List10 Add index controller

> ruby script/generate rubricks_controller news index main block
      exists  components/news
      create  components/news/index
      create  components/news/index/main.rhtml
      create  components/news/index/block.rhtml
      create  components/news/index_controller.rb
      create  components/news/index_helper.rb

Implementation of posting news

+List11 /components/news/post_controller.rb

class News::PostController < ApplicationController
  define_page
  uses_component_template_root

  # Display news post form
  def main
    @news_items = News::NewsItem.new
  end

  # Save posted news to DB
  def create
    news_item = News::NewsItem.new(params[:news_item])
    # Add user ID to news
    news_item.rubricks_user_id = current_user.id
    # Save posted news
    if news_item.save
      flash[:notice] = "Posted."
    end
    # Display news post form
    render :action => 'main'
  end
end

+List12 /components/news/post/main.rhtml

<h1>Post News</h1>
<%= @flash[:notice] if @flash[:notice] %>
<%= form_main_tag :url => {:action => 'create'} %>
  <table style="width:100%">
    <tr>
      <th colspan=2>Posting Item</th>
    </tr>
    <tr>
      <td style="width:20%;">Title</th>
      <td style="width:80%;">
        <%= text_field 'news_item', 'title', :size => 32 %>
      </td>
    </tr>
    <tr>
      <td>Article</td>
      <td><%= text_area 'news_item', 'article', :cols => 70, :rows => 4 %></td>
    </tr>
    <tr>
      <td style="padding-right:20px; text-align:right;" colspan=2>
        <%= submit_tag "Post" %>
      </td>
    </tr>
  </table>
<%= end_form_tag %>

Implementation of listing news

+List13 /components/news/index_controller.rb

class News::IndexController < ApplicationController
  define_page
  uses_component_template_root
  # Display News List
  def main
    @pages, @news_items = paginate(
      :'/news/news_item',
      :per_page => 20,
      :order => 'created_at DESC'
    )
  end

  def block
  end
end

+List14 /components/news/index_helper.rb

module News::IndexHelper
  # Get poster's name
  def news_author(news)
    # Get guest name from general setting if posted by guest user.
    # Get poster's name from DB if other case.
    if news.rubricks_user_id == RubricksUser::GUEST_USER_ID
      RubricksConfig.get('guest_display')
    else
      RubricksUser.find(news.rubricks_user_id).name
    end
  end

  # Get formatted post date.
  def news_publish_date(news)
    news.created_at.strftime("%Y/%m/%d")
  end
end

+List15 /components/news/index/main.rhtml

<h1>News List</h1>
<% for news_item in @news_items %>
  <table border=1>
    <tr>
      <th colspan=2><%= news_item.title %></th>
    </tr>
    <tr>
      <td><%= news_author(news_item) %></td>
      <td><%= news_publish_date(news_item) %></td>
    </tr>
    <tr>
      <td colspan=3><%= news_item.article %></td>
    </tr>
  </table>
  <br>
<% end %>
<%= pagination_remote_links(@pages) %>

Add menu

Add menu by using rubricks_menu generator.

+List16 Format of rubricks_menu generator

 ruby script/generate rubricks_menu [component_name] [controller_name] [action_name]

+List17 Add menu

> ruby script/generate rubricks_menu news index
      created  Menu item

Operation check

News component came to operate at least. Let's boot WEBrick and access.

Left problems

  • Add news block
  • Apply theme
  • For making to several languages
  • Make it distributable

Add news block

Add the block where has the title and updated date of news.

Implementation of news block

+List18 /components/news/index_controller.rb

class News::IndexController < ApplicationController
  define_page
  uses_component_template_root
  # Display News List
  def main
    @pages, @news_items = paginate(
      :'/news/news_item',
      :per_page => 20,
      :order => 'created_at DESC'
    )
  end

  def block
    @news_items = News::NewsItem.find(:all, :order => 'created_at DESC', :limit => 5)
  end
end

+List19 /components/news/index/block.rhtml

<table>
  <% @news_items.each do |news_item| %>
    <tr>
      <td><%= news_item.title %></td>
      <td><%= news_publish_date(news_item) %></td>
    </tr>
  <% end %>
  <tr>
    <td colspan=2 >
      <%= link_to_main hl("[_News_Title_List]"),:url => {:controller => '/news/index', :action => 'main'} %>
    </td>
  </tr>
</table>

Add news block

Add news block by using rubricks_block generator.

+List20 Format of rubricks_block generator

 ruby script/generate rubricks_block [block_title] [component_name] [controller_name] [action_name]

+LIst21 Add news block

> ruby script/generate rubricks_block News news index block
     created  Block.
     created  Block views.

Apply theme

Rubricks has the theme that composes the screen design. All components can put in order by specifying the defined class. Please see the Design Guide?.

+List22 /components/news/post/main.rhtml

<div class="rubricks_general_frame_borderless">
  <h1 class="rubricks_general_title_borderless">Post News</h1>
  <%= @flash[:notice] if @flash[:notice] %>
  <%= form_main_tag :url => {:action => 'create'} %>
    <table class="rubricks_general_table1" style="width:100%">
      <tr class="rubricks_general_table1_title">
        <th class="rubricks_general_table1_cell_borderless" colspan=2>Posting Item</th>
      </tr>
      <tr class="rubricks_general_table1_even">
        <td class="rubricks_general_table1_cell_bordered" style="width:20%;">Title</th>
        <td class="rubricks_general_table1_cell_bordered" style="width:80%;">
          <%= text_field 'news_item', 'title', :size => 32 %>
        </td>
      </tr>
      <tr class="rubricks_general_table1_even">
        <td class="rubricks_general_table1_cell_bordered">Article</td>
        <td class="rubricks_general_table1_cell_bordered"><%= text_area 'news_item', 'article', :cols => 70, :rows => 4 %></td>
      </tr>
      <tr class="rubricks_general_table1_footer">
        <td class="rubricks_general_table1_cell_borderless" style="padding-right:20px; text-align:right;" colspan=2>
          <%= submit_tag "Post", :class => 'submit' %>
        </td>
      </tr>
    </table>
  <%= end_form_tag %>
</div>

For making to several languages

Rubricks has mechanism of the internationalization. The messages are defined in languages file, and write them at the view. Then, let's make title of news post internationalized at this tutorial. Please internationalize other messages similarly.

+List23 /components/news/languages/english.rb

module RubricksLanguage
  def define_lang
    @lang['_News_Title'] = 'News'
    @lang['_News_Component_Description'] = ''
    @lang['_News_Menu'] = 'News'
    @lang['_News_Title_Post'] = 'News Post'
  end
end

+List24 /components/news/languages/japanese.rb

module RubricksLanguage
  def define_lang
    @lang['_News_Title'] = 'News'
    @lang['_News_Component_Description'] = ''
    @lang['_News_Menu'] = 'News'
    @lang['_News_Title_Post'] = 'ニュース投稿'
  end
end

+List25 /components/news/post/main.rhtml

<div class="rubricks_general_frame_borderless">
  <h1 class="rubricks_general_title_borderless"><%= hl('[_News_Title_Post]') %></h1>
  <%= @flash[:notice] if @flash[:notice] %>
  <%= form_main_tag :url => {:action => 'create'} %>
    <table class="rubricks_general_table1" style="width:100%">
      <tr class="rubricks_general_table1_title">
        <th class="rubricks_general_table1_cell_borderless" colspan=2>Posting Item</th>
      </tr>
      <tr class="rubricks_general_table1_even">
        <td class="rubricks_general_table1_cell_bordered" style="width:20%;">Title</th>
        <td class="rubricks_general_table1_cell_bordered" style="width:80%;">
          <%= text_field 'news_item', 'title', :size => 32 %>
        </td>
      </tr>
      <tr class="rubricks_general_table1_even">
        <td class="rubricks_general_table1_cell_bordered">Article</td>
        <td class="rubricks_general_table1_cell_bordered"><%= text_area 'news_item', 'article', :cols => 70, :rows => 4 %></td>
      </tr>
      <tr class="rubricks_general_table1_footer">
        <td class="rubricks_general_table1_cell_borderless" style="padding-right:20px; text-align:right;" colspan=2>
          <%= submit_tag "Post", :class => 'submit' %>
        </td>
      </tr>
    </table>
  <%= end_form_tag %>
</div>

Make it distributable

When the component is distributed, you may make some files as follow and compress them into the RZIP.

  • _install/component_info.rb
  • _install/installation_script.rb
  • _install/db/001_news_schema.rb
  • _install/images/news.gif
  • _install/images/news_active.gif

Component information

About details, please refer to the Component Infomation?.

+List26 Format of rubricks_component_info generator

 ruby script/generate rubricks_component_info [component_name]

List27 Make component information

> ruby script/generate rubricks_component_info news
      exists  components/news
      exists  components/news/_install
      exists  components/news/_install/db
overwrite components/news/_install/component_info.rb? [Ynaq] a
forcing rubricks_component_info
       force  components/news/_install/component_info.rb

Make schema

It follows the rule of Migration.

+List28 /components/news/_install/db/001_news_schema.rb

class NewsSchema < ActiveRecord::Migration
  def self.up
    create_table "news_items", :force => true do |t|
      t.column "title", :string, :limit => 192, :default => "", :null => false
      t.column "rubricks_user_id", :integer, :limit => 10, :default => 0, :null => false
      t.column "article", :text, :default => "", :null => false
      t.column "created_at", :datetime, :null => false
    end
  end

  def self.down
    drop_table :news_items
  end
end

Make rzip file

Make rzip using rzip script. "news.rzip" will be at current directory.

+List29 Make rzip file

> ruby script/rzip news

Install

Let's try to install news component as follow.

  • Back up news directory
  • Login as admin and uninstall current news component
  • Put news.rzip into RAILS_ROOT/install
  • Login as admin and install news.rzip

Appendix

Attachments