First off, you'll edit the Rails-provided resource code to display the users as needed. To get the new user views to display in the same layout that you put together in Chapter 1, you need to add the following line to the top of the UserController in app/controllers/user_controller.rb:
layout "recipes"
This will ensure that the UserController looks to the recipes.html.erb layout file when generating HTML output for its actions, and keeps you from having to maintain multiple layout files.
There are a couple of somewhat quibbly things you should do. For instance, the listing from the index page contains all data for each user, including the encrypted password and salt. The security team probably won't be too happy about that, so go into the view file and remove those lines from the table header and the display loop, so that only the username, first and last names, and email are being displayed. The changed /app/views/users/index.html.erb file should look like this:
<% @title = "Users" %> <table> <tr> <th>Username</th> <th>Firstname</th> <th>Lastname</th> <th>Email</th> </tr> <% for user in @users %> <tr> <td><%=h user.username %></td> <td><%=h user.first_name %></td> <td><%=h user.last_name %></td> <td><%=h user.email %></td> <td><%= link_to 'Show', user %></td> <td><%= link_to 'Edit', edit_user_path(user) %></td> <td><%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %></td> </tr> <% end %> </table> <br /> <%= link_to 'New user', new_user_path %>
While you're at it, the display is probably much more useful if it's alphabetized, so change the first line of the index method in the user controller. The method, in app/controllers/users_controller.rb, should look like this:
def index @users = User.find(:all, :order => "username ASC") respond_to do |format| format.html # index.html.erb format.xml { render :xml => @users } end end
Before you make some changes to the user entry form, it's best to combine the common new and edit forms into a _form partial view template, the way you did for recipes back in Chapter 1. The form also contains entries for encrypted password and salt, when you actually just want a masked entry for passwords. Plus, you'll want the user to confirm the password and email address. Eventually, the view code should look like this:
<% form_for(@user) do |f| %> <table> <tr> <td class="tdheader">First Name:</td> <td class="tdheader">Last Name:</td> </tr> <tr> <td><%= f.text_field :last_name, :size => 20 %></td> <td><%= f.text_field :first_name, :size => 15 %></td> </tr> <table> <tr> <td class="tdheader">User Name:</td> <td><%= f.text_field :username, :size => 15 %></td> </tr> <tr> <td class="tdheader">Email Address:</td> <td><%= f.text_field :email %></td> </tr> <tr> <td class="tdheader">Confirm Email:</td> <td><%= f.text_field :email_confirmation %></td> </tr> <tr> <td class="tdheader">Password:</td> <td><%= f.password_field :password, :size => 10 %></td> </tr> <tr> <td class="tdheader">Confirm:</td> <td><%= f.password_field :password_confirmation, :size => 10 %></td> </tr> </table> <p> <%= f.submit "Create" %> </p> <% end %>
For that form to work, you need to add some attributes to the user object for the items in the form that are not in the database — the clear-text password, and the confirmation fields for the password and email address. In about a page or so, you'll need to actually create explicit getter and setter methods for the password. But for now, just add the validations that you'll need for user objects to app/models/user.rb, like this:
class User < ActiveRecord::Base has_many :recipes attr_accessor :email_confirmation, :password_confirmation, :password validates_presence_of :username, :email
validates_uniqueness_of :username validates_confirmation_of :email, :password validates_length_of :password, :minimum => 6 end
You could add a validation on the format of the user-entered email messages, but I don't think that's worth the effort at the moment. The validates_confirmation_of method assumes the convention of having two fields named something and something_confirmation, and tests for their equality before saving the model object.
How much you test these validations is something of a judgment call—because they are part of Rails Core, the validations probably don't need to be pounded extra hard. It is, however, indisputable that the new validations are breaking some of the default tests because the blank forms that are being sent to the new and update tests do not pass these validations. You need to add sample data that will pass the validations in test/unit/user_test.rb, as follows:
def user_form {:username => "kermit", :firstname => "Kermit", :lastname => "the Frog", :email => "[email protected]", :email_confirmation => "[email protected]", :password => "iheartpigs", :password_confirmation => "iheartpigs"} end def test_should_create_user assert_difference('User.count') do post :create, :user => user_form end assert_redirected_to user_path(assigns(:user)) end
Change the test_should_update_user test to also pass the user_form result to its method call, and the tests will pass. The resulting form, shown in Figure 3-1, has a slightly different layout than the default.
Not that you asked, but I much prefer the tabular layout for form data than the default layout with the caption above the text field. It's more compact and easier to scan.
3.133.139.105