Entries Tagged 'Rails' ↓

Rails and Restful Authentication

It’s been quite a while since my last Ruby on Rails post so let’s go over a little “gotcha” that you might encounter when using the restful_authentication plugin.

Getting started with restful_authentication is fairly easy.  After installing the plugin it’s just a matter of running the following generate command:

script/generate authenticated user sessions

This will create a migration for a users table, a model and controller for users and a sessions controller.  It will also add some named routes to config/routes.rb.

So far so good, right?  Well, a common mistake when generating the model and controllers is to user the singular form of both user and session.  The command will run successfully and do exactly what you told it to do.  You won’t become aware of a problem until you try to log in for the first time and see this:

NameError in SessionsController#create

uninitialized constant SessionsController

RAILS_ROOT: C:/rails/bookmarks

Application Trace | Framework Trace | Full Trace


Request

Parameters:

{"commit"=>"Log in",
"authenticity_token"=>"0c0f07222da8ed58d8c6ebcafb9bf32f0bc84143",
"login"=>"anthony",
"password"=>"mysupersecretpassword"}

Uh oh! what went wrong?  It looks like Rails is looking for a controller called SessionsController.  But we generated one named SessionController.  Why is this happening?  Take a look in the views/session/new.html.erb file.

<% form_tag session_path do -%>
<p><label for="login">Login</label><br/>
<%= text_field_tag 'login' %></p>
<p><label for="password">Password</label><br/>
<%= password_field_tag 'password' %></p>
<!-- Uncomment this if you want this functionality
<p><label for="remember_me">Remember me:</label>
<%= check_box_tag 'remember_me' %></p>
-->
<p><%= submit_tag 'Log in' %></p>
<% end -%>

The form_tag target is session_path.  session_path is created for us by magic because of its mapping in routes.rb.

map.resource :session

When mapping a resource like this Rails looks for the controller with the pluralized name of the resource name by default, which means session_path is getting SessionsController.  We can change the behavior by explicitly setting the controller for the resource.

map.resource :session, :controller => :session

Try to log in again and you will be authenticated!  Of course it may just be easier to remember to use the pluralized name of whatever controller you want to use for managing sessions.

Boston Scalability User Group

I’ve been digging around lately for a Boston area user group dedicated to architectural scalability and I haven’t been able to find one. Other user groups that I regularly attend have meetings centered around scalability once in a while, but I’m looking for something with a schedule dedicated to the topic. It’s a hot topic in the industry right now with a lot happening on different fronts and there should be some ongoing professional discussion dedicated what goes into growing an application.

Here are some of the topics I want to talk about:

  • Data growth and access - What kind of DBMS topologies allow maximum scalability without breaking the budget? What if the budget wasn’t a problem? How do you migrate your data model from hundreds of users to millions of users? Should you partition user data across shards or keep it in a central database? How do you profile data access paterns? Is your application mostly-read or mostly-write? When should you use an LDAP directory for data storage? When should you use MySQL and when should you use Oracle?
  • Application server scaling - app server clustering, web server integration, load balancing, application session management, data caching
  • Web Tier - load balancing reverse proxies, data caching, working with HTTP, considerations for exposing functionality via REST
  • Language conisderations and platform choices - Dynamic languages vs. Static languages, Linux vs. Windows, Solaris vs. Linux, RedHat vs. Oracle, IBM vs. Oracle - How do you make these choices? What evaluation critera are most important? Which ones are misleading?
  • Framework scalability - How can you scale if your framework can’t? Does Rails really scale better than Spring Web MVC? Where do PHP frameworks fit in? What are the alternatives? This is where we will investigate what you gain and lose by binding yourself to a particular framework, how to keep the coupling to a minimum and how to use your framework as a solid foundation instead viewing it as a cage.
  • Emerging technology - Should you become familiar with Map Reduce and Hadoop? What kind of impact do object databases have on your application? Should you buy your own Sun or Dell boxes or use Amazon’s EC2 and S3?
  • Application architecture - How do you write an application that scales? What does your application look like as it grows from servicing hundreds to millions of users? How does it handle session management? How does it access datastores? Are there any design patterns that are helpful? What are the anti-patterns to be aware of?

Like I said, I haven’t found a group dedicated to discussing these topics. If you know of one in the Boston area please let me know. Assuming there isn’t one I am willing to start one. I’d like to start off small and meet at coffee shops around Burlington or Lowell. I have no delusions that this is going to start off or even become as big as NEJUG is now. If it starts off as a few people getting together to talk about scalability trends, cool caching solutions and specific products then I’d call it a good start.

The meeting location is still TBD and will be based on how many people are interested in attending. It will probably be somewhere in Burlington, MA. There is no planned presentation at this time. Instead we will have a meet and greet and then discuss scalability trends and news, what approaches to scalability are commonly used now and what are the plans for the future.

If you are interested in coming or in finding out more information please email me at <my first name>@<my domain name>.<my tld> or leave a comment below. Please make sure to include your email address when you fill out the form so that I can get in touch with you - your email address will not be displayed on my site.

render, redirect_to and instance variables

I rediscovered something about Rails instance variables tonight after initially discovering it a few weeks ago and not writing it down. I spent a good 30 minutes trying to figure out why the following code segment would not produce my expected results in my browser.

  def save
    @bookmark_file = BookmarkFile.new(params[:bookmark_file])
    @bookmark_file.user_id = session[:user].id
    parse_file @bookmark_file.data
    @bookmark_file.parsed_on = Time.now
    @bookmark_file.save
    redirect_to :action => 'list_parsed_bookmarks'
  end

On the browser side I had:


      -- unimportant lines omitted --
      -- just display the bookmarks in the collection --

I had an instance variable @bookmark_file with a one_to_many relationship with bookmarks that I wanted to display on the page for a user. Unfortunately when I tried to display the page in Firefox I got the following error:

You have a nil object when you didn't expect it!
The error occured while evaluating nil.bookmarks

My @bookmark_file instance variable was nil in the view when it was clearly set in the controller's save method. On the surface it would seem that the @bookmark_file instance variable became nil somewhere between the controller and the view. Examining the redirect_to method yields a slightly different answer though.

According to the Rails documentation, ActionController::Base#redirect_to redirects the browser as its name implies. As far as the Rails routing engine is concerned this is a completely new request and all instance variables are thrown out. SO it's not that my @bookmark_file variable was set to nil on the way to the view, rather it wasn't even my @bookmark_file. The new request didn't set any @bookmark_file so there was nothing for the view to operate on.

ActionController::Base#render actually displays the HTML produced by the action or view specified when it is called. By replacing the call to redirect_to with a call to render in the controller the application works as expected because Rails will find the list_parsed_bookmarks view for the controller and use the current instance variables when rendering the view. WIth @bookmark_file already set in the save method the view is then free to use the initalized object.

It may be possible to get the desired behavior out of the original way the method was written by storing @bookmark_file in a session variable but I haven't tried and I don't think it would be a good idea to do so. Using session variables implies that data is shared across requests and creating another request to display the data rather than continue with the current request seems foolish in this situation. The potentially high volume of data stored across all sessions is also a good deterrent.

Any comments are welcome.