Wednesday, 17 September 2014

Say "Hello", Rails

4.2 Say "Hello", Rails

To get Rails saying "Hello", you need to create at minimum a controller and a view.
A controller's purpose is to receive specific requests for the application. Routing decides which controller receives which requests. Often, there is more than one route to each controller, and different routes can be served by different actions. Each action's purpose is to collect information to provide it to a view.
A view's purpose is to display this information in a human readable format. An important distinction to make is that it is the controller, not the view, where information is collected. The view should just display that information. By default, view templates are written in a language called eRuby (Embedded Ruby) which is processed by the request cycle in Rails before being sent to the user.
To create a new controller, you will need to run the "controller" generator and tell it you want a controller called "welcome" with an action called "index", just like this:
$ bin/rails generate controller welcome index
Rails will create several files and a route for you.
create  app/controllers/welcome_controller.rb
 route  get 'welcome/index'
invoke  erb
create    app/views/welcome
create    app/views/welcome/index.html.erb
invoke  test_unit
create    test/controllers/welcome_controller_test.rb
invoke  helper
create    app/helpers/welcome_helper.rb
invoke    test_unit
create      test/helpers/welcome_helper_test.rb
invoke  assets
invoke    coffee
create      app/assets/javascripts/welcome.js.coffee
invoke    scss
create      app/assets/stylesheets/welcome.css.scss
Most important of these are of course the controller, located at app/controllers/welcome_controller.rb and the view, located at app/views/welcome/index.html.erb.
Open the app/views/welcome/index.html.erb file in your text editor. Delete all of the existing code in the file, and replace it with the following single line of code:
<h1>Hello, Rails!</h1>

Hello, Rails!

4 Hello, Rails!

To begin with, let's get some text up on screen quickly. To do this, you need to get your Rails application server running.

4.1 Starting up the Web Server

You actually have a functional Rails application already. To see it, you need to start a web server on your development machine. You can do this by running the following in the blog directory:
$ bin/rails server
Compiling CoffeeScript to JavaScript requires a JavaScript runtime and the absence of a runtime will give you an execjs error. Usually Mac OS X and Windows come with a JavaScript runtime installed. Rails adds the therubyracer gem to the generated Gemfile in a commented line for new apps and you can uncomment if you need it. therubyrhino is the recommended runtime for JRuby users and is added by default to the Gemfile in apps generated under JRuby. You can investigate about all the supported runtimes at ExecJS.
This will fire up WEBrick, a web server distributed with Ruby by default. To see your application in action, open a browser window and navigate to http://localhost:3000. You should see the Rails default information page:
Welcome aboard screenshot
To stop the web server, hit Ctrl+C in the terminal window where it's running. To verify the server has stopped you should see your command prompt cursor again. For most UNIX-like systems including Mac OS X this will be a dollar sign $. In development mode, Rails does not generally require you to restart the server; changes you make in files will be automatically picked up by the server.
The "Welcome aboard" page is the smoke test for a new Rails application: it makes sure that you have your software configured correctly enough to serve a page. You can also click on the About your application's environment link to see a summary of your application's environment.

Creating the Blog Application

3.2 Creating the Blog Application

Rails comes with a number of scripts called generators that are designed to make your development life easier by creating everything that's necessary to start working on a particular task. One of these is the new application generator, which will provide you with the foundation of a fresh Rails application so that you don't have to write it yourself.
To use this generator, open a terminal, navigate to a directory where you have rights to create files, and type:
$ rails new blog
This will create a Rails application called Blog in a blog directory and install the gem dependencies that are already mentioned in Gemfile using bundle install.
You can see all of the command line options that the Rails application builder accepts by running rails new -h.
After you create the blog application, switch to its folder:
$ cd blog
The blog directory has a number of auto-generated files and folders that make up the structure of a Rails application. Most of the work in this tutorial will happen in the app folder, but here's a basic rundown on the function of each of the files and folders that Rails created by default:
File/Folder Purpose
app/ Contains the controllers, models, views, helpers, mailers and assets for your application. You'll focus on this folder for the remainder of this guide.
bin/ Contains the rails script that starts your app and can contain other scripts you use to deploy or run your application.
config/ Configure your application's routes, database, and more. This is covered in more detail in Configuring Rails Applications.
config.ru Rack configuration for Rack based servers used to start the application.
db/ Contains your current database schema, as well as the database migrations.
Gemfile
Gemfile.lock
These files allow you to specify what gem dependencies are needed for your Rails application. These files are used by the Bundler gem. For more information about Bundler, see the Bundler website.
lib/ Extended modules for your application.
log/ Application log files.
public/ The only folder seen by the world as-is. Contains static files and compiled assets.
Rakefile This file locates and loads tasks that can be run from the command line. The task definitions are defined throughout the components of Rails. Rather than changing Rakefile, you should add your own tasks by adding files to the lib/tasks directory of your application.
README.rdoc This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.
test/ Unit tests, fixtures, and other test apparatus. These are covered in Testing Rails Applications.
tmp/ Temporary files (like cache, pid, and session files).
vendor/ A place for all third-party code. In a typical Rails application this includes vendored gems.

Creating a New Rails Project

3 Creating a New Rails Project


The best way to use this guide is to follow each step as it happens, no code or step needed to make this example application has been left out, so you can literally follow along step by step.
By following along with this guide, you'll create a Rails project called blog, a (very) simple weblog. Before you can start building the application, you need to make sure that you have Rails itself installed.
The examples below use $ to represent your terminal prompt in a UNIX-like OS, though it may have been customized to appear differently. If you are using Windows, your prompt will look something like c:\source_code>

3.1 Installing Rails

Open up a command line prompt. On Mac OS X open Terminal.app, on Windows choose "Run" from your Start menu and type 'cmd.exe'. Any commands prefaced with a dollar sign $ should be run in the command line. Verify that you have a current version of Ruby installed:
A number of tools exist to help you quickly install Ruby and Ruby on Rails on your system. Windows users can use Rails Installer, while Mac OS X users can use Tokaido.
$ ruby -v
ruby 2.0.0p353
If you don't have Ruby installed have a look at ruby-lang.org for possible ways to install Ruby on your platform.
Many popular UNIX-like OSes ship with an acceptable version of SQLite3. Windows users and others can find installation instructions at the SQLite3 website. Verify that it is correctly installed and in your PATH:
$ sqlite3 --version
The program should report its version.
To install Rails, use the gem install command provided by RubyGems:
$ gem install rails
To verify that you have everything installed correctly, you should be able to run the following:
$ bin/rails --version
If it says something like "Rails 4.1.1", you are ready to continue.

What is Rails

2 What is Rails?

Rails is a web application development framework written in the Ruby language. It is designed to make programming web applications easier by making assumptions about what every developer needs to get started. It allows you to write less code while accomplishing more than many other languages and frameworks. Experienced Rails developers also report that it makes web application development more fun.
Rails is opinionated software. It makes the assumption that there is the "best" way to do things, and it's designed to encourage that way - and in some cases to discourage alternatives. If you learn "The Rails Way" you'll probably discover a tremendous increase in productivity. If you persist in bringing old habits from other languages to your Rails development, and trying to use patterns you learned elsewhere, you may have a less happy experience.
The Rails philosophy includes two major guiding principles:
  • Don't Repeat Yourself: DRY is a principle of software development which states that "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system." By not writing the same information over and over again, our code is more maintainable, more extensible, and less buggy.
  • Convention Over Configuration: Rails has opinions about the best way to do many things in a web application, and defaults to this set of conventions, rather than require that you specify every minutiae through endless configuration files.

Sunday, 25 May 2014

File Uploading using Rails

You may have a requirement in which you want your site visitors to upload a file on your server. Rails makes it very easy to handle this requirement. Now we will proceed with a simple and small Rails project.
As usual, let's start off with a new Rails application called upload. So let's create basic structure of the application by using simple rails command.
C:\ruby> rails upload
Now let's decide where you would like to save your uploaded files. Assume this is datadirectory inside your public section. So create this directory and check the permissions.
C:\ruby> cd upload
C:\ruby> mkdir upload\public\data
Our next step will be as usual, to create controller and models, so let's do that:

Creating Model:

Because this is not a database based application so we can keep name whatever is comfortable to us. Assume we have to create a DataFile model.
C:\ruby> ruby script/generate model DataFile
      exists  app/models/
      exists  test/unit/
      exists  test/fixtures/
      create  app/models/data_file.rb
      create  test/unit/data_file_test.rb
      create  test/fixtures/data_files.yml
      create  db/migrate
      create  db/migrate/001_create_data_files.rb
Now we will create a method called save in data_file.rb model file. This method will be called by the application controller.
class DataFile < ActiveRecord::Base
  def self.save(upload)
    name =  upload['datafile'].original_filename
    directory = "public/data"
    # create the file path
    path = File.join(directory, name)
    # write the file
    File.open(path, "wb") { |f| f.write(upload['datafile'].read) }
  end
end
The above function will take CGI object upload and will extract uploaded file name using helper function original_filename and finally it will store uploaded file into "public/data" directory. You can call helper function content_type to know media type of the uploaded file.
Here File is a ruby object and join is a helper function will concatenate directory name alongwith file name and will return full file path.
Next, to open a file in write mode we are using open helper function provided by Fileobject. Further we are reading data from the passed data file and writing into output file.

Creating Controller:

Now let's create a controller for our upload project:
C:\ruby> ruby script/generate controller Upload
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/upload
      exists  test/functional/
      create  app/controllers/upload_controller.rb
      create  test/functional/upload_controller_test.rb
      create  app/helpers/upload_helper.rb
Now we will create two controller functions first function index will call a view file to take user input and second function uploadFile takes file information from the user and passes it to the 'DataFile' model. We set the upload directory to the 'uploads' directory we created earlier "directory = 'data'".
class UploadController < ApplicationController
  def index
     render :file => 'app\views\upload\uploadfile.rhtml'
  end
  def uploadFile
    post = DataFile.save(params[:upload])
    render :text => "File has been uploaded successfully"
  end
end
Here we are calling function defined in model file. The render function is being used to redirect to view file as well as to display a message.

Creating View:

Finally we will create a view file uploadfile.rhtml which we have mentioned in controller. Populate this file with the following code:
<h1>File Upload</h1>
<%= start_form_tag ({:action => 'uploadFile'}, 
                        :multipart => true) %>
<p><label for="upload_file">Select File</label> : 
<%= file_field 'upload', 'datafile' %></p>
<%= submit_tag "Upload" %>
<%= end_form_tag %>
Here everything is same what we have explained in earlier chapters. Only new tag isfile_field which will create a button to select a file from user's computer.
By setting the multipart parameter to true, you ensure that your action properly passes along the binary data from the file.
Here, an important point to note is that we have assigned "uploadFile" as the method name in :action, which will be called when you click the Upload button.
This will show you a screen as follows:
Upload File
Now you select a file and upload it, this file will be uploaded into app/public/data directory with the actual file name and a message will be displayed to you saying that "File has been uploaded successfully".
NOTE: If a file with the same name already exists in your output directory then it will be over-written.

Files uploaded from Internet Explorer:

Internet Explorer includes the entire path of a file in the filename sent, so theoriginal_filename routine will return something like:
C:\Documents and Files\user_name\Pictures\My File.jpg
instead of just:
My File.jpg
This is easily handled by File.basename, which strips out everything before the filename.
def sanitize_filename(file_name)
  # get only the filename, not the whole path (from IE)
  just_filename = File.basename(file_name) 
  # replace all none alphanumeric, underscore or perioids
  # with underscore
  just_filename.sub(/[^\w\.\-]/,'_') 
end

Deleting an existing File:

If you want to delete any existing file then its simple and need to write following code:
  def cleanup
    File.delete("#{RAILS_ROOT}/dirname/#{@filename}") 
            if File.exist?("#{RAILS_ROOT}/dirname/#{@filename}")
  end
For a complete detail on File object, you need to go through Ruby Reference Manual.

AJAX on Rails Tutorial

Ajax stands for Asynchronous JavaScript and XML. Ajax is not a single technology; it is a suite of several technologies. Ajax incorporates the following:
  • XHTML for the markup of web pages
  • CSS for the styling
  • Dynamic display and interaction using the DOM
  • Data manipulation and interchange using XML
  • Data retrieval using XMLHttpRequest
  • JavaScript as the glue that meshes all this together
Ajax enables you to retrieve data for a web page without having to refresh the contents of the entire page. In the basic web architecture, the user clicks a link or submits a form. The form is submitted to the server, which then sends back a response. The response is then displayed for the user on a new page.
When you interact with an Ajax-powered web page, it loads an Ajax engine in the background. The engine is written in JavaScript and its responsibility is to both communicate with the web server and display the results to the user. When you submit data using an Ajax-powered form, the server returns an HTML fragment that contains the server's response and displays only the data that is new or changed as opposed to refreshing the entire page.
For a complete detail on AJAX you can go through our AJAX Tutorial

How Rails Implements Ajax:

Rails has a simple, consistent model for how it implements Ajax operations. Once the browser has rendered and displayed the initial web page, different user actions cause it to display a new web page (like any traditional web application) or trigger an Ajax operation:
  • Some trigger fires :This trigger could be the user clicking on a button or link, the user making changes to the data on a form or in a field, or just a periodic trigger (based on a timer)
  • The web client calls the server: A JavaScript method, XMLHttpRequest, sends data associated with the trigger to an action handler on the server. The data might be the ID of a checkbox, the text in an entry field, or a whole form.
  • The server does processing: The server-side action handler ( Rails controller action )-- does something with the data and returns an HTML fragment to the web client.
  • The client receives the response: The client-side JavaScript, which Rails creates automatically, receives the HTML fragment and uses it to update a specified part of the current page's HTML, often the content of a <div> tag.
These steps are the simplest way to use Ajax in a Rails application, but with a little extra work, you can have the server return any kind of data in response to an Ajax request, and you can create custom JavaScript in the browser to perform more involved interactions.

AJAX Example:

While discussing rest of the Rails concepts, we have taken an example of Library. There we have a table called subject and we had added few subjects at the time of Migration. Till now we have not provided any procedure to add and delete subjects in this table.
In this example we will provide, list, show and create operations on subject table. If you don't have any understanding on Library Info System explained in previous chapters then I would suggest you to complete previous chapters first and then continue with AJAX on Rails.

Creating Controller:

So lets start with creation of a controller for subject, this will be done as follows:
C:\ruby\library> ruby script/generate controller Subject
This command creates a controller file app/controllers/subject_controller.rb. Open this file in any text editor and modify it to have following content.
class SubjectController < ApplicationController
   layout 'standard'
   def list
   end
   def show
   end
   def create
   end
end
Now we will give implementation for all these functions in the same way we had given in previous chapters.

The list method implementation:

   def list
       @subjects = Subject.find(:all)
   end
This is similar to the example explained earlier and will be used to list down all the subjects available in our database.

The show method implementation:

   def show
       @subject = Subject.find(params[:id])
   end
This is also similar to the example explained earlier and will be used to display a particular subject corresponding to passed ID.

The create method implementation:

   def create
      @subject = Subject.new(params[:subject])
      if @subject.save
         render :partial => 'subject', :object => @subject
      end
   end
This is bit new here. Here we are not redirecting page to any other page but just rendering only changed part instead of whole page.
This happens possible only when using partial. We don't write complete view file, instead we will write a partial in /app/view/subject directory. We will see it in a moment. First let's create view files for other methods.

Creating Views:

Now we will create view files for all the methods except for create method for which we will create a partial.

Creating view for list method:

Create a file list.rhtml in /app/view/subject and populate it with the following code.
<h1>Listing Subjects</h1>
<ul id="subject_list">
<% @subjects.each do |c| %>
<li><%= link_to c.name, :action => 'show', :id => c.id %>
<%= "(#{c.books.count})" -%></li>
<% end %>
</ul>
Here you are iterating through the @subjects array and outputting a <li> element containing a link to the subject it is referencing for each item in the array. Additionally, you are outputting the number of books in that specific subject inside parentheses. Rails' associations make it easy to step through a relationship and get information like this.
Now try browsing your Subject list using http://localhost:3000/subject/list. It will show you following screen.
List Subjects

Creating view for show method:

Create a file show.rhtml in /app/view/subject and populate it with the following code.
<h1><%= @subject.name -%></h1>
<ul>
<% @subject.books.each do |c| %>
<%= link_to c.title, :controller => "book", 
                        :action => "show",:id => c.id -%>
<% end %>
</ul>
Now try clicking on any subject and you will find a listing of all the books available under that subject.

Creating view for create method:

We would not create view for create method because we are using partial instead of view. So in next section we will create a partial for create method.

Adding Ajax Support:

To get Ajax support in the Rails application, you need to include the necessary JavaScript files in the layout. Rails is bundled with several libraries that make using Ajax very easy. Two libraries prototype and script.aculo.us are very popular.
To add Prototype and script.aculo.us support to the application, open up the standard.rhtml layout file in app/views/layouts, add the following line just before the </head> tag, and save your changes:
<%= javascript_include_tag :defaults %>
This includes both the Prototype and script.aculo.us libraries in the template so their effects will be accessible from any of the views.
Now add the following code at the bottom of app/views/subject/list.rhtml
<p id="add_link"><%= link_to_function("Add a Subject",
"Element.remove('add_link'); Element.show('add_subject')")%></p>

<div id="add_subject" style="display:none;">
<%= form_remote_tag(:url => {:action => 'create'},
    :update => "subject_list", :position => :bottom,
    :html => {:id => 'subject_form'})%>
Name: <%= text_field "subject", "name" %>
<%= submit_tag 'Add' %>
<%= end_form_tag %>
</div>
We are using link_to_function instead of link_to method because The link_to_function method enables you to harness the power of the Prototype JavaScript library to do some neat DOM manipulations.
The second section is the creation of the add_subject <div>. Notice that you set its visibility to be hidden by default using the CSS display property. The preceding link_to_function is what will change this property and show the <div> to the user to take input required to add a new subject.
Next, you are creating the Ajax form using the form_remote_tag. This Rails helper is similar to the start_form_tag tag, but it is used here to let the Rails framework know that it needs to trigger an Ajax action for this method. The form_remote_tag takes the:action parameter just like start_form_tag.
You also have two additional parameters: :update and :position.
  • The :update parameter tells Rails' Ajax engine which element to update based on its id. In this case, it's the <ul> tag.
  • The :position parameter tells the engine where to place the newly added object in the DOM. You can set it to be at the bottom of the unordered list (:bottom) or at the top (:top).
Next, you create the standard form fields and submit buttons as before and then wrap things up with an end_form_tag to close the <form> tag. Make sure that things are semantically correct and valid XHTML.

Creating partial for create method:

As we are calling create method while adding a subject and inside this create method we are using one partial. So lets implement this partial before going for actual practical.
Under app/views/subject, create a new file called _subject.rhtml. Notice that all the partials are named with an underscore (_) at the beginning.
Add the following code into this file:
<li id="subject_<%= subject.id %>">
<%= link_to subject.name, :action => 'show', :id => subject.id %>
<%= "(#{subject.books.count})" -%>
</li>
You are done now....you can now easily add several subjects without having to wait for the page to refresh after each subject is added. Now try browsing your Subject list using http://localhost:3000/subject/list. It will show you following screen. Try to add some subject.
Add Subject
When you press Add button, subject would be added at the bottom of all available subjects and you would not have a feel of page refresh.

Rails Scaffolding

While you're developing Rails applications, especially those which are mainly providing you with a simple interface to data in a database, it can often be useful to use the scaffold method.
Scaffolding provides more than cheap demo thrills. Here are some benefits:
  • You can quickly get code in front of your users for feedback.
  • You are motivated by faster success.
  • You can learn how Rails works by looking at generated code.
  • You can use the scaffolding as a foundation to jumpstarts your development.

Scaffolding Example:

To understand scaffolding lets create a database called cookbook and a table calledrecipes:

Creating an Empty Rails Web Application:

Open a command window and navigate to where you want to create this cookbook web application. I used c:\ruby. So run the following command to create complete directory structure.
C:\ruby> rails cookbook

Setting up the Database:

Here is the way to create database:
mysql> create database cookbook;
Query OK, 1 row affected (0.01 sec)

mysql> grant all privileges on cookbook.*
to 'root'@'localhost' identified by 'password';
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
To tell Rails how to find the database, edit the configuration file c:\ruby\cookbook\config\database.yml and change the database name to cookbook. Leave the password empty. When you finish, it should look something like
development:
  adapter: mysql
  database: cookbook
  username: root
  password: [password]
  host: localhost
test:
  adapter: mysql
  database: cookbook
  username: root
  password: [password]
  host: localhost
production:
  adapter: mysql
  database: cookbook
  username: root
  password: [password]
  host: localhost
Rails lets you run in development mode, test mode, or production mode, using different databases. This application uses the same database for each.

Creating the database tables:

We will use following table for our practical purpose. So create recipes table from sql prompt as follows:
mysql> USE cookbook;
Changed database
mysql> CREATE TABLE recipes (
    -> id INT(11) NOT NULL AUTO_INCREMENT,
    -> title VARCHAR(40),
    -> instructions VARCHAR(255),
    -> PRIMARY KEY (id));
Query OK, 0 rows affected (0.06 Sec)
NOTE: If you wish you can use Rails Migrations to create and maintain tables.

Creating Model:

First, create a Recipe model class that will hold data from the recipes table in the database. Use the following command inside cookbook directory.
C:\ruby\cookbook > ruby script\generate model Recipe
Notice that you are capitalizing Recipe and using the singular form. This is a Rails paradigm that you should follow each time you create a model.
This will create a file named app/models/recipe.rb containing a skeleton definition for the Recipe class.

Creating Controller:

Now we have to create a recipe controller with actions to manipulate the recipes in the database via the standard CRUD operations: create, read, update, and delete.
C:\ruby\cookbook > ruby script\generate controller Recipe
Notice that you are capitalizing Recipe and using the singular form. This is a Rails paradigm that you should follow each time you create a controller.
This will create a file named app/controllers/recipe_controller.rb containing a skeleton definition for the RecipeController class. Edit this file and add the line scaffold:recipe as shown
class RecipeController < ApplicationController
   scaffold:recipe
end
This single line of code will bring the database table to life. This will provide with a simple interface to your data, and ways of:
  • Creating new entries
  • Editing current entries
  • Viewing current entries
  • Destroying current entries
When creating or editing an entry, scaffold will do all the hard work of form generation and handling for you, and will even provide clever form generation, supporting the following types of inputs:
  • Simple text strings
  • Textareas (or large blocks of text)
  • Date selectors
  • Datetime selectors
Now go into cookbook directory and run Web Server using following command:
C:\ruby\cookbook> ruby script/server
Now open a browser and navigate to http://127.0.0.1:3000/recipe/new, This will provide you a screen to create new entries in recipes table. A screen shot is shown below:
Create Recipe
Once you press Create button to create anew recipe, your record is added into recipes table and it shows following result:
Create Recipe
You can see option to edit, show and destroy the records. So play around these options.
You can also list down all the recipes available in the recipes table using URL http://127.0.0.1:3000/recipe/list

Enhancing the Model:

Rails gives you a lot of error handling for free. To understand this, add some validation rules to the empty recipe model:
Modify app/models/recipe.rb as follows and then test your application:
class Recipe < ActiveRecord::Base
   validates_length_of :title, :within => 1..20
   validates_uniqueness_of :title, :message => "already exists"
end
These entries will give automatic checking that:
  • validates_length_of: the field is not blank and not too long
  • validates_uniqueness_of: duplicate values are trapped. I don't like the default Rails error message - so I have given my custom message.

The Generated Scaffold Code:

With the scaffold action, Rails generates all the code it needs dynamically. By runningscaffold as a script, we can get all the code written to disk where we can investigate it and then start tailoring it to our requirements.
So now let's start once again to generate Scaffold code manually by using scaffold helper script:
C:\ruby\cookbook> ruby script/generate scaffold recipe
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/recipes
      exists  app/views/layouts/
      exists  test/functional/
  dependency  model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
   identical    app/models/recipe.rb
   identical    test/unit/recipe_test.rb
   identical    test/fixtures/recipes.yml
      create  app/views/recipes/_form.rhtml
      create  app/views/recipes/list.rhtml
      create  app/views/recipes/show.rhtml
      create  app/views/recipes/new.rhtml
      create  app/views/recipes/edit.rhtml
      create  app/controllers/recipes_controller.rb
      create  test/functional/recipes_controller_test.rb
      create  app/helpers/recipes_helper.rb
      create  app/views/layouts/recipes.rhtml
      create  public/stylesheets/scaffold.css
C:\ruby\cookbook>

The Controller:

Let's look at the code behind the controller.This all code is generated by scaffoldgenerator. So if you will open app/controllers/recipes_controller.rb then you will find something as follows:
class RecipesController > ApplicationController
  def index
    list
    render :action => 'list'
  end

  verify :method => :post, :only => [ :destroy, :create, :update ],
         :redirect_to => { :action => :list }

  def list
    @recipe_pages, @recipes = paginate :recipes, :per_page => 10
  end

  def show
    @recipe = Recipe.find(params[:id])
  end

  def new
    @recipe = Recipe.new
  end

  def create
    @recipe = Recipe.new(params[:recipe])
    if @recipe.save
      flash[:notice] = 'Recipe was successfully created.'
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
  end

  def edit
    @recipe = Recipe.find(params[:id])
  end

  def update
    @recipe = Recipe.find(params[:id])
    if @recipe.update_attributes(params[:recipe])
      flash[:notice] = 'Recipe was successfully updated.'
      redirect_to :action => 'show', :id => @recipe
    else
      render :action => 'edit'
    end
  end

  def destroy
    Recipe.find(params[:id]).destroy
    redirect_to :action => 'list'
  end
end
When the user of a Rails application selects an action . e.g. "Show" - the controller will execute any code in the appropriate section - "def show" - and then by default will render a template of the same name - "show.rthml". This default behavior can be overwritten:
The controller uses ActiveRecord methods such as find, find_all, new, save, update_attributes, and destroy to move data to and from the database tables. Note that you do not have to write any SQL statements, rails will take care of it automatically.

The Views:

All the views and corresponding all the controller methods are created by scaffoldcommand and they are available in app/views/recipes directory.

How Scaffolding is Different?

If you have gone through previous chapters then you must have seen that we had created methods to list, show, delete and create data etc but scaffolding does that job automatically.

Rails Layouts:

A layout defines the surroundings of an HTML page. It's the place to define common look and feel of your final output. Layout files reside in app/views/layouts:
The process involves defining a layout template and then letting the controller know that it exists and to use it. First, let's create the template.
Add a new file called standard.rhtml to app/views/layouts. You let the controllers know what template to use by the name of the file, so following a sane naming scheme is advised.
Add the following code to the new standard.rhtml file and save your changes:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;.
charset=iso-8859-1" />
<meta http-equiv="Content-Language" content="en-us" />
<title>Library Info System</title>
<%= stylesheet_link_tag "style" %>
</head>
<body id="library">
<div id="container">
<div id="header">
<h1>Library Info System</h1>
<h3>Library powered by Ruby on Rails</h3>
</div>
<div id="content">
<%= yield -%>
</div>
<div id="sidebar"></div>
</div>
</body>
</html>
Everything you just added were standard HTML elements except two lines. Thestylesheet_link_taghelper method outputs a stylesheet <link>. In this instance we are linking style.css style sheet. The yield command lets Rails know that it should put the RHTML for the method called here.
Now open book_controller.rb and add the following line just below the first line:
class BookController < ApplicationController
   layout 'standard'
   def list
      @books = Book.find(:all)
   end
...................
This tells to controller that we want to use a layout available in standard.rhtml file. Now try browsing books it will give following screen.
Layout Example

Adding Style Sheet:

Till now we have not created any style sheet, so Rails is using default style sheet. Now let's create a new file called style.css and save it in /public/stylesheets. Add the following code to this file.
body {
   font-family: Helvetica, Geneva, Arial, sans-serif;
   font-size: small;
   font-color: #000;
   background-color: #fff;
}
a:link, a:active, a:visited {
   color: #CD0000;
}
input { 
   margin-bottom: 5px;
}
p { 
   line-height: 150%;
}
div#container {
   width: 760px;
   margin: 0 auto;
}
div#header {
   text-align: center;
   padding-bottom: 15px;
}
div#content {
   float: left;
   width: 450px;
   padding: 10px;
}
div#content h3 {
   margin-top: 15px;
}
ul#books {
   list-style-type: none;
}
ul#books li {
   line-height: 140%;
}
div#sidebar {
   width: 200px;
   margin-left: 480px;
}
ul#subjects {
   width: 700px;
   text-align: center;
   padding: 5px;
   background-color: #ececec;
   border: 1px solid #ccc;
   margin-bottom: 20px;
}
ul#subjects li {
   display: inline;
   padding-left: 5px;
}
Now refresh your browser and see the difference:
Layout Example

What is Next?

Next chapter will explain you how to develop application with Rails Scaffolding concept to give user access to add, delete and modify the records in any database.

Rails Views - ActionView

A Rails View is an ERb program that shares data with controllers through mutually accessible variables.
If you look in the app/views directory of the library application, you will see one subdirectory for each of the controllers we have created: book. Each of these subdirectories was created automatically when the same-named controller was created with the generate script.
Now, assuming your web server is up and running. Try to give following in your browser's address box:
http://localhost:3000/book/list
You get following error message because you have not defined any view file for any method defined in controller.
Missing Template
Rails lets you know that you need to create the view file for the new method. Each method you define in the controller needs to have a corresponding RHTML file, with the same name as the method, to display the data that the method is collecting.
So lets create view files for all the methods we have defined in book_controller.rb.

Creating view file for list method:

Create a file called list.rhtml using your favorite text editor and save it to app/views/book. After creating and saving the file, refresh your web browser. You should see a blank page; if you don't, check the spelling of your file and make sure that it is the exactly the same as your controller's method.
Now display actual content lets put following code into list.rhtml.
<% if @books.blank? %>
<p>There are not any books currently in the system.</p>
<% else %>
<p>These are the current books in our system</p>
<ul id="books">
<% @books.each do |c| %>
<li><%= link_to c.title, {:action => 'show', :id => c.id} -%></li>
<% end %>
</ul>
<% end %>
<p><%= link_to "Add new Book", {:action => 'new' }%></p>
The code to be executed is to check whether the @books array has any objects in it. The.blank? method returns true if the array is empty and false if it contains any objects. This @books object was created in controller inside list method.
The code between the <%= %> tags is a link_to method call. The first parameter of link_to is the text to be displayed between the <a> tags. The second parameter is what action is called when the link is clicked. In this case, it is the show method. The final parameter is the id of the book that is passed via the params object.
Now try refreshing your browser and you should get following screen because we don't have any book in our library.
No Book Message

Creating view file for new method:

Till now we don't have any book in our library. We have to create few books in the system. So lets design a view corresponding to new method defined in book_controller.rb.
Create a file called new.rhtml using your favorite text editor and save it to app/views/book. Add the following code to the new.rhtml file.
<h1>Add new book</h1>
<%= start_form_tag :action => 'create' %>
<p><label for="book_title">Title</label>:
<%= text_field 'book', 'title' %></p>
<p><label for="book_price">Price</label>:
<%= text_field 'book', 'price' %></p>
<p><label for="book_subject">Subject</label>:
<%= collection_select(:book,:subject_id,@subjects,:id,:name) %></p>
<p><label for="book_description">Description</label><br/>
<%= text_area 'book', 'description' %></p>
<%= submit_tag "Create" %>
<%= end_form_tag %>
<%= link_to 'Back', {:action => 'list'} %>
Here start_form_tag() method interprets the Ruby code into a regular HTML <form> tag using all the information supplied to it. This tag, for example, outputs the following HTML:
<form action="/book/create" method="post">
Next method is text_field that outputs an <input> text field. The parameters for text_field are object and field name. In this case, the object is book and the name is title
Rails method called collection_select, creates an HTML select menu built from an array, such as the @books one. There are five parameters, which are as follows:
  • :book - The object you are manipulating. In this case, it's a book object.
  • :subject_id - The field that is populated when the book is saved.
  • @books - The array you are working with.
  • :id - The value that is stored in the database. In terms of HTML, this is the <option> tag's value parameter
  • :name- The output that the user sees in the pull-down menu. This is the value between the <option> tags.
The next used is submit_tag, which outputs an <input> button that submits the form. Finally, there is the end_form_tag method that simply translates into </form>.
Go to your browser and visit http://localhost:3000/book/new. This will give you following screen.
New Book
Enter some data in this form and then click at Create button. This will result in a call tocreate method which does not need any view because this method is using either list ornew methods to view the results. So when you click at Create button, the data should submit successfully and redirect you to the list page, in which you now have a single item listed as follows:
Create Book
If you click the link, you should see another Template is missing error since you haven't created the template file for show method yet.

Creating view file for show method:

This method will display complete detail about any book available in the library. Create a show.rhtml file under app/views/book and populate it with the following code:
<h1><%= @book.title %></h1>
<p><strong>Price: </strong> $<%= @book.price %><br />
<strong>Subject :</strong> <%= @book.subject.name %><br />
<strong>Created Date:</strong> <%= @book.created_at %><br />
</p>
<p><%= @book.description %></p>
<hr />
<%= link_to 'Back', {:action => 'list'} %>
This is the first time you have taken full advantage of associations, which enable you to easily pull data from related objects.
The format used is @variable.relatedObject.column. In this instance, you can pull the subject's name value through the @book variable using the belongs_to associations. If click on any listed record then it will show you following screen.
Show Book

Creating view file for edit method:

Create a new file called edit.rhtml and save it in app/views/book. Populate it with the following code:
<h1>Edit Book Detail</h1>
<%= start_form_tag :action => 'update', :id => @book %>
<p><label for="book_title">Title</label>:
<%= text_field 'book', 'title' %></p>
<p><label for="book_price">Price</label>:
<%= text_field 'book', 'price' %></p>
<p><label for="book_subject">Subject</label>:
<%= collection_select(:book, :subject_id,
                         @subjects, :id, :name) %></p>
<p><label for="book_description">Description</label><br/>
<%= text_area 'book', 'description' %></p>
<%= submit_tag "Save changes" %>
<%= end_form_tag %>
<%= link_to 'Back', {:action => 'list' } %>
This code is very similar to new method except action to be updated instead of creating and defining an id.
At this point we need some modification in list method's view file. Go to the <li></li> element and modify it to look like the following:
<li>
<%= link_to c.title, {:action => "show", :id => c.id} -%>
<b> <%= link_to 'Edit', {:action => "edit",
:id => c.id} %></b>
</li>
Now try to browse books using http://localhost:3000/book/list. It will give you listing of all the books along with Edit option. When you click Edit option then you will have next screen as follows:
Edit Book
Now you edit this information and then click at Save Changes button. This will result in a call to update method available in controller file and it will update all the changed attribute. Notice that update method does not need any view file because it's using either show oredit methods to show its results.

Creating view file for delete method:

Removing information from a database using Ruby on Rails is almost too easy. You do not need to write any view code for delete method because this method is using list method to display the result. So let's just modify list.rhtml again and add a delete link.
Go to the <li></li> element and modify it to look like the following:
<li>
<%= link_to c.title, {:action => 'show', :id => c.id} -%>
<b> <%= link_to 'Edit', {:action => 'edit', :id => c.id} %></b>
<b> <%= link_to "Delete", {:action => 'delete', :id => c.id},
:confirm => "Are you sure you want to delete this item?" %></b>
</li>
The :confirm parameter presents a JavaScript confirmation box asking if you really want to perform the action. If the user clicks OK, the action proceeds, and the item is deleted.
Now try browsing books using http://localhost:3000/book/list. It will give you listing of all the books along with Edit and Delete options as follows:
Delete Book
Now using option Delete you can delete any listed record.

Creating view file for show_subjects method:

Create a new file, show_subjects.rhtml, in the app/views/book directory and add the following code to it:
<h1><%= @subject.name -%></h1>
<ul>
<% @subject.books.each do |c| %>
<li><%= link_to c.title, :action => "show", :id => c.id -%></li>
<% end %>
</ul>
You are taking advantage of associations by iterating through a single subject's many books listings.
Now modify the Subject: line of show.rhtml so that the subject listing shows a link.
<strong>Subject: </strong> <%= link_to @book.subject.name,
:action => "show_subjects", :id => @book.subject.id %><br />
This will output a list of subject on the index page, so that users can access them directly.
Modify list.rhtml to add the following to the top of the file:
<ul id="subjects">
<% Subject.find(:all).each do |c| %>
<li><%= link_to c.name, :action => "show_subjects", 
:id => c.id %></li>
<% end %>
</ul>
Now try browsing books using http://localhost:3000/book/list. It will display all subjects with links so that you can browse all the books related to that subject.
List Subjects

What is Next?

Hope now you are feeling comfortable with all the Rails Operations.
Next chapter will explain you how to use Layouts to put your data in better way. I will show you how to use CSS in your Rails Applications.