3.2. User Creation Form

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.

Figure 3.1. Figure 3-1

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.148.105