Creare un applicazione RESTful con rails è molto semplice:
C:>rails MyApp
In un sistema REST, l’applicazione è composta da risorse web aventi un insieme vincolato di operazioni. Con lo scaffold generiamo una risorsa e le quattro basilari funzioni per gestirla, denominate CRUD (Create, Read, Update, Delete)
C:>script/generate scaffold assets name:string
Abbiamo creato la base da cui partire per testare questo breve articolo.
Supponiamo di voler aggiungere una nuova operazione alla nostra risorsa risorsa Asset, per esempio vogliamo gestire la copia. Iniziamo creando il nuovo indirizzamento modificando quanto creato dallo scaffold:
#config/routes.rb map.resources :assets, :member => { :copy => :get }
Testiamo l’esito:
C:>rake routes
verificando che ci sia il nuovo percorso:
copy_asset GET /assets/:id/copy(.:format) {:controller=>"assets", :action=>"copy"}
La copia è un’operazione utile in molti contesti in quanto permette di effettuare l’inserimento di una nuova risorsa partendo da una già esistente.
Traduciamo in codice e andiamo a creare la nuova operazione nel 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
Eventualmente si può creare la view, dipende dall’operazione che si deve gestire. In questo esempio si sfrutta la view dell’operazione new in quanto sono molto simili e richiamano entrambe la :create.
Creare o non creare una nuova azione sulla risorsa è pura filosofia, tralasciando la questione vediamo come indirizzare una nuova create, ci riferiamo ad una collezione di risorse:
#config/routes.rb map.resources :assets, :member => { :copy => :get }, :collection => { :createcp => :put }
ho utilizzato una collezione perchè in questo caso non serve un riferimento ad una risorsa esistente, se avessi usato :member il path per la generazione dell’uri lo avrebbe richiesto.
se testiamo nuovamente le routes dovrebbe aggiungersi questa nuova:
createcp_asset PUT /assets/createcp(.:format) {:controller=>"assets", :action=>"createcp"}
creiamo quindi la nuova view e il form con la uri della nuova azione specificando il metodo (per precisione ho indicato put ma equivale ad utilizzare un 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 %>
e la nuova azione nel 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
Per richiamare la nuova operazione dalla index:
#app/views/assets/index.html.erb <%= link_to t(:copy), copy_asset_path(asset) %>
Infine ed eventualmente, queste sono le parole utilizzate dall’esempio per l’internazionalizzazione:
create: "Crea" copy: "Copia" created: "L'oggetto {{model}} è stato creato correttamente." name: "Nome" model: asset: "Allegato"