Introduction to Active Scaffold Part I

I originally wrote this article for fifth issue of Rails Magazine. In addition to print version, you can download all issues of Rails Magazine in pdf for free. Not only that, they also allow authors to self-publish their articles on blogs etc. after 30 days of issue release. I hope rails beginners will particularly find this post useful.

In this two-part series, I will trying to explain Active Scaffold from the ground up using a real world example.

Introduction

ActiveScaffold is a rails plugin that generates an ajaxified management interface based on the database tables.  It is an incredibly powerful, configuration-driven framework that automatically provides all CRUD operations. It is easily and highly configurable. Let us have a walkthrough of active scaffold with details on configurability and customization options it provides using a sample application. The demo application which we are going to develop is a management site for a sports club.

Configuration

Here our example is about building an administration panel for a sports club “mysportsclub”. It consists of sports, players, coaches and equipments. There are various kinds of sports in the club. Each player can have membership for any number of sports. Each sport will have one trained coach for guidance and various equipments which will be issued to the players. Let’s begin with the implementation of “mysportsclub”

Let’s setup our rails application “mysportsclub”. Run the following commands:

Install the latest version of the plugin which is compatible with latest stable rails (2.3.x):

Note: Latest active scaffold version works only with rails version higher than 2.2. Also, install render_component plugin since it is now removed from rails 2.3 but used by active scaffold.

Layout:

This is the standard active scaffold layout admin.html.erb:

Model/Migrations:

Add the following code to the respective models. This code defines the associations for the various models:

sports.rb

coach.rb

player.rb

equipment.rb

players_sport.rb

Note I

Don’t forget to add the plural form of “equipment” as “equipments” in the config/intializers/inflections.rb.

Active Scaffold will throw an exception if we do not define the above inflection rule.  The controller generated for the ‘Equipment’ model will be ‘EquipmentsController’. But since active scaffold generates the controller name automatically using its inbuilt function: “active_scaffold_controller_for(class_name_of_the_model)”. It will not be able to guess the correct controller name and would throw an exception while we try to access the nested equipments:

Controllers:

Add the following code to your controllers:

sports_contrpller.rb

coaches_controller.rb

players_controller.rb

equipments_controller.rb

players_sports_controller.rb

routes.rb

The above code will generate a complete interface for our club.

Following code for your layout will provide a navigation bar in your view.

admin.html.erb

There are various customization options available. As per our requirement we can customize the columns, links, fields, actions etc. We would discuss them in the concluding part of the series.

Payal Gupta is working working as software engineer with Vinsol. She has over two years of industry
experience.


How to improve the image quality and generate random string image in the plugin validates_captcha

Validates captchais a good pluging to implement captcha in your rails application.
However i found that there is repetition of the string of the image and the quality of image is not that good. To get a good quality image and random string replace the code of the file /vendor/plugins/validates_captcha/lib/captcha_challenge.rb with the following code…


require 'digest/sha1'
module AngryMidgetPluginsInc #:nodoc:
# CaptchaChallenge
class CaptchaChallenge
include CaptchaConfig
extend CaptchaConfig
DEFAULT_TTL = 1200#Lifetime in seconds. Default is 20 minutes.

attr_reader :id, :created_at
attr_accessor :ttl
  def initialize(options = {}) #:nodoc:
    generate_id
    options = {
    :ttl => config['default_ttl'] || DEFAULT_TTL}.update(options)
    self.ttl = options[:ttl]
    @created_at = Time.now
    self.class.prune
  end

# Implement in subclasses.
  def correct? #:nodoc:
    raise NotImplementedError
  end

private

  def generate_id #:nodoc:
    self.id = Digest::SHA1.hexdigest(Time.now.to_s+rand.to_s)
  end

  def id=(i) #:nodoc:
    @id = i
  end

  def write_to_store #:nodoc:
    store.transaction{
    store[:captchas] = Array.new unless store.root?(:captchas)
    store[:captchas] <<> c.created_at+c.ttl
    store[:captchas].delete_at(i)
  end
}
end
}
end#prune
end#class << words =" 'gorilla" default_dir =" 'captcha'#public/images/captcha" write_dir =" File.join(RAILS_ROOT," default_filetype =" 'jpg'" options =" {})" options =" {" string =""> config['words'] ? config['words'][rand(config['words'].size)] : WORDS[rand(WORDS.size)],
:dir => config['default_dir'] || DEFAULT_DIR,
:filetype => config['default_filetype'] || DEFAULT_FILETYPE
}.update(options)

#changed
self.string = Digest::SHA1.hexdigest(Time.now.to_s)[0..4] #options[:string]
self.dir = options[:dir]
self.filetype = options[:filetype]
self.filename = options[:filename] || generate_filename

write_to_store
end

# Generates the image.
def generate(options = {})
options = {
:fontsize => 50,
:padding => 20,
:color => '#000',
:background => '#fff',
:fontweight => 'bold',
:rotate => true
}.update(options)

options[:fontweight] = case options[:fontweight]
when 'bold' then 700
else 400
end

#added
text = Array.new
0.upto(4) do |i|
text[i] = Magick::Draw.new
text[i].pointsize = options[:fontsize]
text[i].font_weight = 300 #options[:fontweight]
text[i].fill = 'blue' #options[:color]
text[i].gravity = Magick::CenterGravity
text[i].rotation = (rand(2)==1 ? rand(30) : -rand(30)) if options[:rotate]
end

metric = text[2].get_type_metrics(self.string)
#add bg
canvas = Magick::ImageList.new
fill = Magick::HatchFill.new('white','lime')
x = metric.width+options[:padding]
y = metric.height+options[:padding]

#ADDING LINES

img1 = Magick::Image.new(x,y,fill)
gc = Magick::Draw.new
gc.stroke_linejoin('round')
gc.stroke('blue')
gc.stroke_width(2)
gc.line(rand(x),rand(y),rand(x),rand(y))
gc.line(rand(x),rand(y),rand(x),rand(y))
gc.line(rand(x),rand(y),rand(x),rand(y))
gc.draw(img1)
canvas << background_color =" '#000F'" y_loc =" rand(y)" p =" Magick::Pixel.from_color(options[:background])" opacity =" Magick::MaxRGB" background_color =" p" image =" canvas.flatten_images.blur_image(1)" dir =" self.dir," filename =" self.filename)" downcase ="=">public/images.
def file_path
File.join(dir,filename)
end

class <<> c.created_at+c.ttl
if File.exists?(File.join(WRITE_DIR, c.file_path))
begin
File.unlink(File.join(WRITE_DIR, c.file_path))
rescue Exception
end
end
end
}
end
}
super
end#prune
end#class << image="(i)" image =" i">

visit Here to view the customized use of the plugin validates_captcha in RoR.