Testimony Part II: Model evolution
Note: The Testimony app is now live. This url will always for the latest installment in this series.
Before we go too much farther, we need to make a couple of adjustments to the default behaviour. The first revolves around time: ActiveRecord stores time in local time by default. In today’s world, applications should be storing time as UTC, especially on a server. To make Rails use UTC, set default_timezone = :utc as shown below.
The second tweak involves sessions. Out of the box, Rails tracks user sessions in the file store (i.e., on disk). I prefer to store mine in the database for ease of use, management, and better performance, and if this app needed to scale I’d want to look at using memcached. Luckily, ActiveRecord knows how to use a table for session data. First, change the session_store to be the database:
config.action_controller.session_store = :active_record_store config.active_record.default_timezone = :utc
When ActiveRecord needs to reference a session object, it will create one from the database, using the session id found in the http request but we don’t have a table defined for a session…yet! Let’s create one using the built in rake task db:sessions:create:
# rake db:sessions:create
exists db/migrate
create db/migrate/002_add_sessions.rb
# rake db:migrate
== AddSessions: migrating =====================================================
-- create_table(:sessions)
-> 0.0663s
-- add_index(:sessions, :session_id)
-> 0.4341s
-- add_index(:sessions, :updated_at)
-> 0.1018s
== AddSessions: migrated (0.6029s) ============================================
Note that the task generated a migration for us. As usual, running the migration creates the table.
On to today’s changes…when we generated the testimonial controller, we also generated a static scaffold that gave us forms for the basic operations: list, new, edit, delete. Rails uses a technique called reflection to create these forms that have entries for each field in the model (technically, the fields in the model come from the database). For this application, however, letting the user edit all fields isn’t appropriate — we don’t want the user marking a new testimonial ‘approved’ do we? We’re going to remove the fields created_on, updated_on and approved from the view, which isĀ app/views/testimonial/new.rthml, we see that the form is actually rendered using a partial template (a partial is an application of the DRY idiom by factoring out duplicate code):
New testimonial
< % form_tag :action => 'create' do %> < %= render :partial => 'form' %> < %= submit_tag \"Create\" %> < % end %> < %= link_to 'Back', :action => 'list' %>
The call to render will look for _form.rhtml (the Rails Way is that partial templates are named with a leading underscore).This form is used by the new and edit actions. Here’s what the form looks like:
< %= error_messages_for 'testimonial' %> < %= text_field 'testimonial', 'email' %> < %= text_area 'testimonial', 'testimony' %> < %= date_select 'testimonial', 'created_on' %> < %= date_select 'testimonial', 'updated_on' %>
ActiveRecord will maintain the xxx_on fields for us, so let’s remove them. We said that the administrator will be the one to approve a particular testimonial, so let’s remove that as well.
Wait… if we remove approved, from this shared form, it will never be shown to anyone, not even our administrator. There’s a couple of different ways to handle this. One is to create a new partial to be used just for administrators; this violates the DRY principle. Another is to add a conditional within the partial and only show approved if the user is an administrator. The only problem we have is that we don’t have a User model yet. We’ll tackle that in the next installment. Stay tuned!
Filed under: Rails, walkthrough, webdev

Leave a Reply