Section 4.3. Generating Scaffolding Code


4.3. Generating Scaffolding Code

Code generation is the other major form of scaffolding. You generate scaffolding with the ruby script/generate scaffold command. Run it without parameters to see the parameters you can specify and a description of the generator:

 >  ruby script/generate scaffold  Usage: script/generate scaffold ModelName [ControllerName] [action, ...] General Options:     -p, --pretend        Run but do not make any changes.     -f, --force          Overwrite files that already exist.     -s, --skip           Skip files that already exist.     -q, --quiet          Suppress normal output.     -t, --backtrace      Debugging: show backtrace on errors.     -h, --help           Show this help message.     -c, --svn            Modify files with subversion. (Note: svn must be in path) Description:     The scaffold generator creates a controller to interact with a model. ... 

Here, you need to specify a model and a controller name . So, to generate the scaffolding for the controller and views of our Photo model, type:

 >  ruby script/generate scaffold photo photos  ... 

Respond y when Rails asks if you want to replace a file. Any additional parameters are added as empty methods on the new controller. If you omit the name of the controller, Rails uses the English plural of the model name. So, to generate scaffolding for our slides, slideshows and categories, type:

  ruby script/generate scaffold slide  ...  ruby script/generate scaffold slideshow  ...  ruby script/generate scaffold category  ... 

4.3.1. Inside the Generated Code

Let's look at the controller Rails generated. Your version may be slightly different than the code you see here, but the principles should be the same. Open apps/controllers/photos_controller.rb :

 class PhotosController < ApplicationController   def index     list     render :action => 'list'   end   def list     @photo_pages, @photos = paginate :photos, :per_page => 10   end   def show     @photo = Photo.find(params[:id])   end   def new     @photo = Photo.new   end   def create     @photo = Photo.new(params[:photo])     if @photo.save       flash[:notice] = 'Photo was successfully created.'       redirect_to :action => 'list'     else       render :action => 'new'     end   end   def edit     @photo = Photo.find(params[:id])   end   def update     @photo = Photo.find(params[:id])     if @photo.update_attributes(params[:photo])       flash[:notice] = 'Photo was successfully updated.'       redirect_to :action => 'show', :id => @photo     else       render :action => 'edit'     end   end   def destroy     Photo.find(params[:id]).destroy     redirect_to :action => 'list'   end end 

Why Scaffolding Pluralizes Controller Names

When you run scaffolding, and you specify:

 ruby script/generate scaffold Photo 

you actually get a model called Photo and a controller called PhotosController . You get this behavior because the scaffolding generator takes two parameters: the model and the controller. If you omit the controller, the generator pluralizes the name. Often, that's what you want, because Rails controllers typically deal with collections of things.

Usually, you want a singular model name. For example, you might want an administration controller called Admin . If you usually use plurals, you can omit the name of the controller. If you want a singular controller name, specify both the model and controller name. For more information, you can get scaffolding help by typing:

 ruby script/generate scaffold 


As you can see, Rails generates a controller with each of the methods found in Table 4-1. Point your browser to http://localhost:3000/photos to verify that the generated code behaves identically to the code generated with the scaffold :photo method.

But the code is slightly different. Instead of generating the views from within the controller like the scaffold method, the generated code explicitly renders views in rhtml code. Let's look at one of the views. Open app/views/photos/list.rhtml :

 1 <% for column in  Photo.content_columns  %> 2 <p> 3 <b><%=  column.human_name  %>:</b> <%=h  @photo.send(column.name)  %> 4 </p> 5 <% end %> 6 7 <%= link_to 'Edit', :action => 'edit', :id => @photo %>  8 <%= link_to 'Back', :action => 'list' %> 

This view is be rendered by the list method of PhotosController . Let's look at the first and third lines in detail:



<% for column in Photo.content_columns %>

In line 1, the view loops through each column in the database. Recall that Active Record added metadata to Photo , maintaining an array with each column in the table. content_columns has all of the columns that are for public display. (You don't see foreign keys or the id property, for example.)



<b><%= column.human_name %>

The view renders a friendly name to serve as a label of the element.



<%=h @photo.send(column.name) %>

The view sends a message to @photo with the name of the column and renders the result. (For example, @photo.send "filename" would be the same as @photo.filename .)

Figure 4-5 shows the result. The view lists all the properties of a Photo record in the database. The Filename property was in the database from the beginning; the Created At, Thumbnail, and Description properties were added by a migration earlier in this chapter. Furthermore, if we add more properties, the list.rhtml view won't require any modification to display them.

Figure 4-5. This show view is dynamic

The show.rhtml view reflects changes in the database. Now, let's look at a view that's a little less dynamic. Open app/views/photos/_form.rhtml :

 <%= error_messages_for 'photo' %> <!--[form:photo]--> <p><label for="photo_created_at">Created at</label><br/> <%= datetime_select 'photo', '  created_at  '  %></p> <p><label for="photo_filename">Filename</label><br/> <%= text_field 'photo', '  filename  '  %></p> <p><label for="photo_thumbnail">Thumbnail</label><br/> <%= text_field 'photo', '  thumbnail  '  %></p> <p><label for="photo_description">Description</label><br/> <%= text_field 'photo', '  description  '  %></p> <!--[eoform:photo]--> 

This view is called a partial, and it's responsible for rendering a form for a photo in edit.rhtml and new.rhtml . (You'll learn more about partials in the next chapter.) The words in bold are attributes on Photo . Because you've generated explicit code to render the form, this view works only for the database columns that were present when you created the scaffolding. So here, you see one of the primary differences between scaffolding created through metaprogramming and generated scaffolding. When we used metaprogramming, because our scaffold :photo method generated scaffolding at runtime, the scaffolding reflects changes in the database. With our generated code, the scaffolding gives a one-time benefit, but must be maintained thereafter.

4.3.2. The Best of Both Worlds

Most Rails developers use both kinds of scaffolding. The scaffold method helps when you're revising your Active Record models quickly, because it reflects database changes in the user interface. Later, you can generate scaffolding and flesh out your controllers and user interfaces, starting from a foundation of generated code. Using both in combination is a powerful way to work.

Scaffolding does have its limits, though. You get a one- size -fits-all user interface and controller. It's not going to be right for all purposes, and it's not complete. One of the biggest deficiencies of scaffolding is the lack of relationship management. Scaffolding does not take relationships in the existing model under consideration when creating the scaffold.



Ruby on Rails[c] Up and Running
Ruby on Rails[c] Up and Running
ISBN: B003D3OGCY
EAN: N/A
Year: 2006
Pages: 94

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net