Ruby on Rails
HowtoBuildComponents (Version #9)

The following doc does not correspond to what I’ve read in other pages.
I think better ways are described in Components.

Because I’m a newb, I prefer not to remove it

- zimbatm
—-

Indeed, this article describes how to implement a partial with a helper. The partial displays a form that invokes an action. Components tell you how to implement Rails components.

- Patrick
—-

Say you want to create a little box of functionality you can just drop into any page – say a sidebar or a search box. Here’s one approach to solving this problem in Rails.

The view: app/views/component/_comment.rhtml


<form action="/component/comment/<%= category %>" method="post">
  Email: <input type="text" name="email" size="40" maxlength="80" /><br />
  Comment: <textarea rows="5" cols="65" name="text" /><br />
  <input type="hidden" name="return_url" value="<%= return_url %>">
  <input type="submit" value="Save">
</form>

<table>
  <tr>

    <th>Email</th>
    <th>Comment</th>
  </tr>
  <% for entry in entrylist do %>
  <tr>
    <td><%= entry.email %></td>
    <td><%= entry.text %></td>

  </tr>
  <% end %>
</table>

The helper: app/helpers/component_helper.rb


require 'action_view/partials'

require 'comment' # load the model

module <a href="http://wiki.rubyonrails.com/rails/pages/ComponentHelper" class="existingWikiWord">ComponentHelper</a>
  def self.append_features(controller) #:nodoc:
    controller.ancestors.include?(ActionController::Base) ? controller.add_template_helper(self) : super
  end

  def comment_component(comment_category)
    render_partial "component/comment", nil,
      {"category" => comment_category,
       "entrylist" => Comment.find(:all, :conditions => ["category = '%s'", comment_category]),
       "return_url" => @request.request_uri}
  end
end

The controller: app/controllers/component_controller.rb


require 'abstract_application'
require 'component_helper'

require 'comment' # load the model

class <span class="newWikiWord">ComponentController<a href="http://wiki.rubyonrails.com/rails/pages/ComponentController">?</a></span> < <a href="http://wiki.rubyonrails.com/rails/pages/AbstractApplicationController" class="existingWikiWord">AbstractApplicationController</a>
  include <a href="http://wiki.rubyonrails.com/rails/pages/ComponentHelper" class="existingWikiWord">ComponentHelper</a>

  def comment
    Comment.create(
      "category" => @params["id"],
      "email" => @params["email"],
      "text" => @params["text"])

    redirect_to_path @params["return_url"]
  end
end

The view that wishes to insert this component simply needs to contain:


<%
  require 'component_helper'
  extend <a href="http://wiki.rubyonrails.com/rails/pages/ComponentHelper" class="existingWikiWord">ComponentHelper</a>
%>
...
<%= comment_component("category") %>

It is a simple matter to add more functionality to the component – for example, the controller could read:


  def comment
    case @params["id"]
    when "create" 
      Comment.create(
        "category" => @params["category"],
        "email" => @params["email"],
        "text" => @params["text"])
    when "delete" 
      Comment.destroy(@params["target"].to_i)
    end

    redirect_to_path @params["return_url"]
  end

Then you could have a form for deleting comments which directed the browser to /component/comment/delete?target=3 (for example).

If the component is complex enough to warrant it, you could even give it its own helper and controller, but use the same technique to drop it into other pages.

It’s also a simple matter to add more components – just add more methods to the helper to display the components, and more methods to the controller to handle their behaviour.

There is an example of how to implement this same thing in IOWA at http://enigo.com/demos/components.html

The following doc does not correspond to what I’ve read in other pages.
I think better ways are described in Components.

Because I’m a newb, I prefer not to remove it

- zimbatm
—-

Indeed, this article describes how to implement a partial with a helper. The partial displays a form that invokes an action. Components tell you how to implement Rails components.

- Patrick
—-

Say you want to create a little box of functionality you can just drop into any page – say a sidebar or a search box. Here’s one approach to solving this problem in Rails.

The view: app/views/component/_comment.rhtml


<form action="/component/comment/<%= category %>" method="post">
  Email: <input type="text" name="email" size="40" maxlength="80" /><br />
  Comment: <textarea rows="5" cols="65" name="text" /><br />
  <input type="hidden" name="return_url" value="<%= return_url %>">
  <input type="submit" value="Save">
</form>

<table>
  <tr>

    <th>Email</th>
    <th>Comment</th>
  </tr>
  <% for entry in entrylist do %>
  <tr>
    <td><%= entry.email %></td>
    <td><%= entry.text %></td>

  </tr>
  <% end %>
</table>

The helper: app/helpers/component_helper.rb


require 'action_view/partials'

require 'comment' # load the model

module <a href="http://wiki.rubyonrails.com/rails/pages/ComponentHelper" class="existingWikiWord">ComponentHelper</a>
  def self.append_features(controller) #:nodoc:
    controller.ancestors.include?(ActionController::Base) ? controller.add_template_helper(self) : super
  end

  def comment_component(comment_category)
    render_partial "component/comment", nil,
      {"category" => comment_category,
       "entrylist" => Comment.find(:all, :conditions => ["category = '%s'", comment_category]),
       "return_url" => @request.request_uri}
  end
end

The controller: app/controllers/component_controller.rb


require 'abstract_application'
require 'component_helper'

require 'comment' # load the model

class <span class="newWikiWord">ComponentController<a href="http://wiki.rubyonrails.com/rails/pages/ComponentController">?</a></span> < <a href="http://wiki.rubyonrails.com/rails/pages/AbstractApplicationController" class="existingWikiWord">AbstractApplicationController</a>
  include <a href="http://wiki.rubyonrails.com/rails/pages/ComponentHelper" class="existingWikiWord">ComponentHelper</a>

  def comment
    Comment.create(
      "category" => @params["id"],
      "email" => @params["email"],
      "text" => @params["text"])

    redirect_to_path @params["return_url"]
  end
end

The view that wishes to insert this component simply needs to contain:


<%
  require 'component_helper'
  extend <a href="http://wiki.rubyonrails.com/rails/pages/ComponentHelper" class="existingWikiWord">ComponentHelper</a>
%>
...
<%= comment_component("category") %>

It is a simple matter to add more functionality to the component – for example, the controller could read:


  def comment
    case @params["id"]
    when "create" 
      Comment.create(
        "category" => @params["category"],
        "email" => @params["email"],
        "text" => @params["text"])
    when "delete" 
      Comment.destroy(@params["target"].to_i)
    end

    redirect_to_path @params["return_url"]
  end

Then you could have a form for deleting comments which directed the browser to /component/comment/delete?target=3 (for example).

If the component is complex enough to warrant it, you could even give it its own helper and controller, but use the same technique to drop it into other pages.

It’s also a simple matter to add more components – just add more methods to the helper to display the components, and more methods to the controller to handle their behaviour.

There is an example of how to implement this same thing in IOWA at http://enigo.com/demos/components.html