Scriptorama.nl

Header image showing a keyboard, mouse, laptop and books on design patterns

Rails versie 1.2

Afgelopen week heeft David Heinemeier Hansson de release candidate 1 van de nieuwe versie van Rails bekend gemaakt. Versie 1.2 van het geweldige framework bevat een groot aantal updates.

Een overzicht van de wijzigingen aan de verschillende onderdelen van Rails kan je vinden op de weblog van Rails: nieuw in ActionPack, nieuw in ActiveRecord en nieuw in ActiveSupport.

Een grote aanpassing is de ondersteuning voor REST-full resources. Een simpel voorbeeld is hieronder te vinden:

RUBY:
  1. class PeopleController  @people.to_xml }
  2.     end
  3.   end
  4.  
  5.   # GET /people/1
  6.   # GET /people/1.xml
  7.   def show
  8.     @person = Person.find(params[:id])
  9.  
  10.     respond_to do |format|
  11.       format.html # show.rhtml
  12.       format.xml  { render :xml => @person.to_xml }
  13.     end
  14.   end
  15.  
  16.   # GET /people/new
  17.   def new
  18.     @person = Person.new
  19.   end
  20.  
  21.   # GET /people/1;edit
  22.   def edit
  23.     @person = Person.find(params[:id])
  24.   end
  25.  
  26.   # POST /people
  27.   # POST /people.xml
  28.   def create
  29.     @person = Person.new(params[:person])
  30.  
  31.     respond_to do |format|
  32.       if @person.save
  33.         flash[:notice] = 'Person was successfully created.'
  34.         format.html { redirect_to person_path(@person) }
  35.         format.xml  { head :created, :location => person_path(@person) }
  36.       else
  37.         format.html { render :action => "new" }
  38.         format.xml  { render :xml => @person.errors.to_xml }
  39.       end
  40.     end
  41.   end
  42.  
  43.   # PUT /people/1
  44.   # PUT /people/1.xml
  45.   def update
  46.     @person = Person.find(params[:id])
  47.  
  48.     respond_to do |format|
  49.       if @person.update_attributes(params[:person])
  50.         flash[:notice] = 'Person was successfully updated.'
  51.         format.html { redirect_to person_path(@person) }
  52.         format.xml  { head :ok }
  53.       else
  54.         format.html { render :action => "edit" }
  55.         format.xml  { render :xml => @person.errors.to_xml }
  56.       end
  57.     end
  58.   end
  59.  
  60.   # DELETE /people/1
  61.   # DELETE /people/1.xml
  62.   def destroy
  63.     @person = Person.find(params[:id])
  64.     @person.destroy
  65.  
  66.     respond_to do |format|
  67.       format.html { redirect_to people_path }
  68.       format.xml  { head :ok }
  69.     end
  70.   end
  71. end

Door de HTTP method aan te passen kan je dus verschillende acties aanroepen binnen een controller. Dit zorgt voor nog nettere URL's dan al het geval was in Rails. Het bovenstaande voorbeeld is een scaffold voorbeeld dat Rails zelf voor je kan genereren met het volgende commando:

script/generate scaffold_resource

Doordat de meeste browsers geen ondersteuning hebben voor andere HTTP methoden dan GET en POST, moet Rails een omweg maken om dit toch te kunnen gebruiken. Daarom voegen ze aan formulieren die de PUT methode gebruiken een extra hidden field toe met de naam '_method' en de waarde PUT. In het framework lezen ze dit uit en baseren mede daarop de aan te roepen actie.

Tot zover geen probleem. Formulieren met extra velden is nog te overzien. Maar dan kom je bij een destroy methode die met de DELETE method aangeroepen kan worden. Meestal bereik je die actie door middel van een linkje. En daar voeg je niet zomaar even een veld aan toe, want dan ben je gelijk je nette URL's weer kwijt.

De link_to methode heeft een extra parameter method gekregen die je als volgt kunt gebruiken:

RUBY:
  1. link_to 'Destroy', person_path(person), :confirm => 'Are you sure?', :method => :delete

En wat maakt Rails daar van:

HTML:
  1. <a href="/people/1" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;">Destroy</a>

(Te)veel code voor een simpel linkje. Daarnaast zal onze grote vriend Google of de buurman zonder JavaScript gewoon op /people/1 uitkomen en dus nooit meer iets kunnen verwijderen. Conclusie is dat deze leuke techniek alleen bruikbaar is in backend situaties waarbij je eisen kunt stellen aan de omgeving van de gebruiker en Google niet zo snel langs zal komen.

Misschien moeten we dan toch maar de URL wat minder netjes willen hebben.

Reageer ook!

Je wilt natuurlijk sowieso niet dat Google je delete-links spidert maar dat is niet helemaal het punt.

Ik lig niet echt wakker van mensen die Javascript uit hebben staan, maar wat ik wel wat ranzig is vind is dat ze de javascript code direct in de HTML code gevrot hebben kennelijk. Je kunt dit veel netter attachen.

Als Google (of wie of wat ook) een ongewenste respons via GET kan indexeren dan lijkt me dat je site/applicatie wagenwijd open staat voor misbruik.

Rails gebruikt dus nog steeds inline JavaScript.
Dat kan ik niet rijmen met DHH die vaak hamert op 'code beauty' en semantiek.
Gelukkig zijn er initiatieven als http://www.ujs4rails.com/

Leave a comment
Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>