Tuesday, August 26, 2008

RESTful Rails in Short

What is REST?
coined by Roy Fielding stands for REpresentational State Transfer
describes an architecture for web apps centered around resources

REST constraints
  • client-server
  • stateless
  • cache
  • uniform interface
  • layered system
  • code-on-demand

REST data elements
  • resource
  • resource identifier
  • representation
  • representation metadata
  • resource metadata
  • control data

Rails resource

  • manipulated via HTTP methods
  • URL addressable entity
  • represented in different formats
Rails resource manipulations

operation SQL REST
create insert POST
read select GET
update update PUT
delete delete DELETE

Rails resource URLs

Traditional Rails RESTful Rails
POST /post/create POST /post
GET /post/show/1 GET /post/1
POST /post/update/1 PUT /post/1
POST /post/destroy/1 DELETE /post/1

Creating a resource
./script/generate scaffold_resource \
post \
title:string \
content:text \
created_at:datetime

creates
model, views, controller, helper
fixtures, unit tests, functional tests,
migration (fully functional!)
modifies
config/routes.rb

Model
app/models/post.rb
class Post < ActiveRecord::Base
end
nothing new!

View
app/views/posts/show.rhtml

Title:<%=h @post.title %>


Content:<%=h @post.content %>


Created at:<%=h @post.created_at %>


<%= link_to ‘Edit’, edit_post_path(@post) %> |
<%= link_to ‘Back’, posts_path %>
new syntax for link_to URLs!

Views: routes
config/routes.rb
ActionController::Routing::Routes.draw do |map|
map.resources :posts
end
defines path methods and URL methods

Action `````HTTP request````````` Path method
index GET /posts projects_path
show GET /posts/1 project_path(1)
new GET /posts/new new_project_path
edit GET /posts/1;edit edit_project_path(1)
create POST /posts projects_path
update PUT /posts/1 project_path(1)
delete DELETE /posts/1 project_path(1)

new
form_for(:post, :url => post_path) ...
edit
form_for(:post, :url => post_path(@post), \
:html => {:method => :put}) ...
destroy
link_to ‘Destroy’, post_path(post), :method => :delete

Controller
app/controllers/posts_controller.rb
def destroy
@post = Post.find(params[:id])
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.xml { head :ok }
end
end
uses respond_to and post_url

Controller: routes

Traditional Rails
redirect_to :controller => ‘posts’, \
:action => ‘show’, :id => @post.id

RESTful Rails
redirect_to post_url(@post)
Each path method has equivalent URL method
Remember: use URL methods for redirect_to

Controller: respond_to
multiple representations of the resource
respond_to uses
accept HTTP-Header of the request
format appended to the request URL
register new formats in config/environment.rb
to extend responds_to
Mime::Type.register ‘image/png’, :png

Migration

db/migrate/001_create_posts.rb
class CreatePosts < ActiveRecord::Migration
def self.up
create_table :posts do |t|
t.column :title, :string
t.column :content, :text
t.column :created_at, :datetime
end
end

def self.down
drop_table :posts
end
end

Nested resources
strongly coupled resources
expressed in the URLs
creating a nested resource

./script/generate scaffold_resource comment \
post_id:integer created_at:datetime \
author:string content:text

models
models must be edited to express relationship

app/models/post.rb

class Post < ActiveRecord::Base
has_many :comments
end
app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :post
end

routes
routes must be edited to reflect relationship

config/routes.rb

map.resources :comments
becomes
map.resources :posts do |posts|
posts.resources :comments
end

Path method Path
comments_path(1) /posts/1/comments
comment_path(1, 2) /posts/1/comments/2
new_comment_path(1) /posts/1/comments/new
edit_comment_path(1) /posts/1/comments/2;edit

controller
nested resources controllers must be adapted
def index
post = Post.find(params[:post_id])
@comments = post.comments.find(:all)
...
end

REST benefits
  • clean URLS
  • multiple representations
  • less code
  • CRUD oriented controllers
  • clear application design
  • scalability

Friday, August 22, 2008

SQL Injection in Ruby On Rails

SQL Injection
One of the most common security holes in web applications is that they pass user input
directly to the database without quoting. Thus, a malicious user can fairly easily run all the SQL
he wants to on the server. An example of this would be a search form submission that is handled
by the following code:

@courses = Course.find(:conditions => "name = '#{params[:q]'")

Now let’s say JHON puts the following string into the search form:

"science'; delete from courses; --"

The resulting SQL query will be as follows:

SELECT * from courses where name = 'science'; delete from courses; --'

This is a perfectly valid SQL query and will effectively wipe out the whole courses table. Thus,
you should never, ever, pass anything unquoted to the :conditions parameter of ActiveRecord
finders. Instead, use the bind variable syntax:

@courses = Course.find(:conditions => ["name = ?", params[:q]])

You can pass in as many question mark/variable pairs you need. They will be parsed and
quoted in the order they are specified.

Another option in simple cases is to use the magic finders, where the parameter value is
automatically quoted, too:
@courses = Course.find_by_name(params[:q])

Tuesday, August 19, 2008

Dojo Button and Rails Helpers

Dojo Button and Rails Helpers

When i tried to use dojo buttons on rails partials , i felt happy about dojo widgets.

But if i have to use save_tag button or i want to include button in link_to_remote function,
I dont have option to get dojo style button.

I have used firebug to get the required dojo classes for dojo button and created following helper methods.

def dojo_button(name)
''
end
def dojo_button_class
"dijit dijitLeft dijitInline dijitStretch dijitButtonNode dijitButtonContents dijitButton"
end

save_tag to avoid multiple click in IE and Firefox

##############################################################################
# Overrides sumit_tag for disable save after click event --JAGAN REDDY
##############################################################################
def commit_tag(value,options={})
options.stringify_keys!
submit_tag value, options.merge(:onclick => '

if(window.addEventListener)
{
this.disabled = true;
}
else
{ // IE
var element = window.event.srcElement;
var tag = element.tagName.toLowerCase();
if(tag == "input")
{
var click = element.onclick;
var keypress = element.onkeypress;
setTimeout(function() { element.disabled = true; element.onclick = null; element.onkeypress = null; }, 0);
setTimeout(function() { element.disabled = false; element.onclick = click; element.onkeypress =keypress; }, 20000);
}
}
')
end
use this in apllication_helper.rb