RSS
 

Add an operation to a resource in a RESTful system

20 Aug

My apologize in advance for having used a robot translator, a small help to save a little time:

To create a RESTful application with rails is very simple:

C:>rails MyApp

In a REST system, the application consists of Web resources with a set of linked transactions. With the scaffold generate a resource and the four basic functions to manage it, called CRUD (Create, Read, Update, Delete)

C:>script/generate scaffold assets name:string

We created the base from which to test this short article.

Suppose you want to add a new operation to our resource Asset, for example we want to handle the copy. We start by creating a new address by changing the scaffold created by:

#config/routes.rb
map.resources :assets, :member => { :copy => :get }

Let’s check the results:
C:>rake routes

…ensuring that there is the new path:

copy_asset GET /assets/:id/copy(.:format) {:controller=>"assets", :action=>"copy"}

The copy is useful in many contexts because it allows for the inclusion of a new resource from an existing.
Translate into code, and let’s create the new controller:

#app/controllers/assets_controller.rb
 
# GET /assets/copy
# GET /assets/copy.xml
def copy
  @asset = asset.new
  @asset.attributes = Asset.find(params[:id]).attributes
 
  respond_to do |format|
    format.html { render :new }
    format.xml  { render :xml => @asset }
  end
end

You can also create the view, depends on the transaction that has to be managed. This example uses the view of the new as they are very similar and both the recall: create.

Create or not create a new action on the resource is pure philosophy, leaving aside the question how we create a new target, we refer to a collection of resources:

#config/routes.rb
map.resources :assets, :member => { :copy => :get }, :collection => { :createcp => :put }

I used a collection because in this case does not need a reference to an existing resource, if I had used: the member for the path generation dell’uri would have required.

if we test again the routes should add this:

createcp_asset PUT /assets/createcp(.:format) {:controller=>"assets", :action=>"createcp"}

then we create the new view and form with the uri of the new action and specify the method (for detail put but I indicated to use an equivalent post):

#app/views/assets/copy.html.erb
 
<% form_for(@asset, :url => createcp_assets_path, :method=>:put do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label t(:name) %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.submit t(:create) %>
  </p>
<% end %>

and the new action in the controller:

#app/controllers/assets_controller.rb
 
# POST /assets/createcp
# POST /assets/createcp.xml
def createcp
  @asset = Asset.new(params[:asset])
 
  #do something
 
  respond_to do |format|
    if @asset.save
      flash[:notice] = I18n.t(:created, :model => I18n.t('model.asset'))
      format.html { redirect_to assets_path }
      format.xml  { render :xml => @asset, :status => :created, :location => @asset }
    else
      format.html { render :action => "copy" }
      format.xml  { render :xml => @asset.errors, :status => :unprocessable_entity }
    end
  end
end

To invoke the new operation by the index:

#app/views/assets/index.html.erb
<%= link_to t(:copy), copy_asset_path(asset) %>

Finally, these are the words used in the example for internationalization (if you need it):

create: "Crea"
copy: "Copia"
created: "The item {{model}} was created successfully."
name: "Name"
model:
  asset: "Asset"
 
Comments Off

Posted in Ruby on Rails

 

Tags: , ,

Comments are closed.