The Debian stable distribution (“squeeze”) includes JRuby 1.5.1, which is old.
This is how I installed the latest JRuby:
sudo apt-get install curl curl -L https://get.rvm.io | bash -s stable rvm install jruby rvm use jruby jruby —S gem install rails
The Debian stable distribution (“squeeze”) includes JRuby 1.5.1, which is old.
This is how I installed the latest JRuby:
sudo apt-get install curl curl -L https://get.rvm.io | bash -s stable rvm install jruby rvm use jruby jruby —S gem install rails
Recently, I had to implement the following feature in a Rails 3.2 application:
Example for a grouped value list: Cities where a company is present, grouped by global corporate regions.
The implementation also had to satisfy these design goals:
To reduce code duplication, I first tried Active Record bases class inheritance, with the common code in abstract base classes. But this did not work well with the uniqueness checks generated by the client_side_validations gem and so I used modules instead.
I keep all my modules in app/modules. To have them auto-loaded, I add this to config/application.rb:
config.autoload_paths += %W(#{config.root}/app/modules)
combo_common.rb
module ComboCommon
extend ActiveSupport::Concern
included do
attr_accessible :active, :description, :name, :order
default_scope order('"ORDER", name')
validates :name, :presence => true, :uniqueness => true
validates :order, :presence => true,
:numericality => {:only_integer => true, :greater_than => 0}
end
def is_active
active ? "Yes" : "No"
end
module ClassMethods
def title
name.demodulize.titleize
end
end
end
combo_with_category.rb
module ComboWithCategory
extend ActiveSupport::Concern
included do
attr_accessible :category_id, :category
validates :category_id, :presence => true
end
end
Example : cities grouped by region
combo/city.rb
class Combo::City < ActiveRecord::Base
include ComboCommon, ComboWithCategory
def self.category_type
Combo::Region
end
belongs_to :category, :class_name => category_type.name
end
combo/region.rb
class Combo::Region < ActiveRecord::Base
include ComboCommon
has_many :category_members, class_name: Combo::Location.name,
foreign_key: "category_id", readonly: true
end
combo/controller_base.rb
class Combo::ControllerBase < ApplicationController
before_filter :ensure_admin
def init_type(type)
@type = type
end
def index
@items = @type.all
render "combo/index"
end
def new
@item = @type.new(active: true, order: 100)
render :template => "combo/new", :layout => "popup"
end
def edit
@item = @type.find(params[:id])
render :template => "combo/edit", :layout => "popup"
end
def create
@item = @type.new(params[type_symbol])
if @item.save
redirect_to_index "was successfully created."
else
render "combo/new"
end
end
def update
@item = @type.find(params[:id])
if @item.update_attributes(params[type_symbol])
redirect_to_index "was successfully updated."
else
redirect_to_index "was NOT successfully updated."
end
end
def destroy
item = @type.find(params[:id])
begin
item.destroy if item
redirect_to_index("was successfully deleted.")
rescue ActiveRecord::StatementInvalid => e
msg = e.message
# See http://docs.oracle.com/cd/E11882_01/server.112/e17766/e2100.htm
# for reference documentation of Oracle error codes
if msg.include?("ORA-02292") and msg.include?("child record found")
redirect_to_index("could not be deleted because it is still in use! ")
else
raise
end
end
end
private
def type_symbol
@type.name.delete("::").underscore.to_sym
end
def redirect_to_index(message)
redirect_to polymorphic_path(@type), :notice => @type.title + " " + message
end
end
Example : cities grouped by region
combo/cities_controller.rb
class Combo::CitiesController < Combo::ControllerBase
before_filter { init_type(Combo::City) }
end
combo/regions_controller.rb
class Combo::RegionsController < Combo::ControllerBase
before_filter { init_type(Combo::Region) }
end
combo/index.html.erb
<div class="heading clearfix">
<h2><%= @type.title.pluralize %></h2>
<div class="actions">
<%= link_to 'New Entry', new_polymorphic_path(@type),
:class => "button colorbox" %>
</div>
</div>
<table id="index" class="display">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<% if @type.respond_to? :category_type %>
<th>Category</th>
<% end %>
<th>Order</th>
<th>Active</th>
<th>Created</th>
<th>Modified</th>
<th class="no-search no-sort"></th>
<th class="no-search no-sort"></th>
</tr>
</thead>
<tbody>
<% @items.each do |item| %>
<tr>
<td><%= item.name %></td>
<td><%= item.description %></td>
<% if item.respond_to? :category %>
<td><%= item.category.name %>
<% end %>
<td><%= item.order %></td>
<td><%= item.is_active %></td>
<td><%= item.created_at.to_s(:date) %></td>
<td><%= item.updated_at.to_s(:date) %></td>
<td><%= link_to 'Edit', edit_polymorphic_path(item),
:class => "colorbox" %></td>
<td><%= link_to 'Delete', item,
:confirm => 'Are you sure?',
:method => :delete %>
</td>
</tr>
<% end %>
</tbody>
</table>
combo/edit.html.erb
<h3>Editing <%= @type.title %></h3> <%= render "combo/form" %>
combo/new.html.erb
<h3>New <%= @type.title %></h3> <%= render "combo/form" %>
combo/_form.html.erb
<%= form_for @item, :validate => true do |f| %>
<% if @item.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@item.errors.count, "error") %>
prohibited this value list item from being saved:</h2>
<ul>
<% @item.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<table class="no-borders">
<tr>
<td><%= label_for f, :name %></td>
<td><%= f.text_field :name, :class => "required" %></td>
</tr>
<tr>
<td><%= label_for f, :description %></td>
<td><%= f.text_field :description %></td>
</tr>
<% if @type.respond_to? :category_type %>
<tr>
<td><%= label_for f, :category_id, "Category" %></td>
<td><%= combo(f, :category_id, @type.category_type) %>
</td>
</tr>
<% end %>
<tr>
<td><%= label_for f, :order %></td>
<td><%= f.number_field :order %></td>
</tr>
<tr>
<td><%= label_for f, :active %></td>
<td><%= f.check_box :active %></td>
</tr>
</table>
<br/>
<div class="actions">
<%= f.submit %>
<%= link_to 'Cancel', polymorphic_path(@type), :class => "button" %>
</div>
<% end %>
app/helper/application_helper.rb
module ApplicationHelper include ComboUtil end
app/modules/combo_util.rb
module ComboUtil
def combo_link(type)
link_to simple_plural(type).titleize, polymorphic_path(type)
end
def combo(form, attr, type, options = {}, html_options = {})
form.select(attr, combo_options(type, form.object.send(attr)), options,
html_options)
end
def combo_filter(type)
render 'combo_filter', type: type
end
private
def simple_plural(type)
type.name.demodulize.pluralize
end
def combo_options(type, id)
if type.respond_to? :category_type
grouped_options_for_select(all_grouped_options(type),
disabled: inactive_options(type),
selected: id)
else
options_for_select(all_options(type),
disabled: inactive_options(type),
selected: id)
end
end
def all_grouped_options(type)
type.category_type.all.map do |cat|
[cat.name, cat.category_members.map { |m| [m.name, m.id] }]
end
end
def all_options(type)
type.all.map { |m| [m.name, m.id] }
end
def inactive_options(type)
type.where(active: false).map { |m| m.id }
end
end