views:

153

answers:

3

So I have a url like the following

localhost/users/:id/posts

which gives the posts of that particular user. Now this id can be either his login (which is a string) or the id (user.id) which is technically an Integer but params[:id] is always a string. So how do I implement this an action.

@user = params[:id].is_a?(String) ? User.find_by_login(params[:id]) : User.find(params[:id])

The above code miserably fails since params[:id] is always a string. Any thoughts? Thanks.

+4  A: 

When I've done this, I've actually had two separate controller actions-- show and show_by_login. I feel like it's less unpredictable that way, and I have more control.

Be sure to enforce uniqueness of your logins, index them, and if show_by_login can't find the record you have to raise ActiveRecord::RecordNotFound yourself.

  def show
    @user = User.find(params[:id])

    respond_to do |format|
      format.html
      format.xml  { render :xml => @user.to_xml }
    end
  end

  def show_by_login
    @user = User.find_by_login(params[:login])
    unless @user
      raise ActiveRecord::RecordNotFound
    end

    render :action => 'show'
  end
Ben
This is the only way you can allow purely numeric logins and be able to search with both.
Swanand
A: 

You could use a regular expression:

@user = params[:id] =~ /^\d+$/ ? User.find(params[:id]) : User.find_by_login(params[:id])
Mikael S
But, as the saying goes, "now you have two problems" (http://bit.ly/1G8lgA) -- so my username cannot be 8675309? It's my favorite song!
Ben
Yeah, but that's more of a problem with the design (using params[:id] for both ID and username) rather than regular expressions. ;)
Mikael S
@Mikael : Apparently, yes. But not quite. You can always use 2 separate paths to specify what to search with.
Swanand
@Swanand: Of course, that would be the better solution.
Mikael S
A: 

So long as you don't allow any logins to consist purely of digits, you could write your own finder/named_scope.

class User < ActiveRecord::Base
  named_scope :find_by_id_or_login, lambda {|id_or_login|
    { :conditions => ["id = ? OR login = ?", id_or_login, id_or_login]  }
  }
end

@user = User.find_by_id_or_login(params[:id])
EmFi
You have to be sure to enforce that rule (that a login cannot have only digits) at all places that a login can be set. Otherwise, there is potential for returning the wrong user's info. Especially if a user can change their login, and just enumerate through the user ids.
Ben
@Ben, if you've read the solution you'll notice the first sentence addresses that. Although, I didn't think the explanation was necessary, thanks for elaborating on why this solution depends on no being numeric.
EmFi