How to use custom url formats?


#1

I’m new to Rails and am trying to use a field called “code” instead of
“id” in my URLs. For example, assuming I’ve got a database of
motorcycles makes where the codes are “Honda”, “Yamaha”, “Suzuki”, and
“Kawasaki”, etc. To show the info about Honda I want to use this url:

http://www.mysite.com/makes/honda/

instead of:

http://www.mysite.com/makes/show/1/

I have a controller called makes_controller.rb, a model called make.rb,
and a layout called makes.rhtml. What would I need to modify? And if
you don’t mind, could you be specific about where the changes go since
I’m new to rails.

Mucho thanks in advance.


#2

Mike Schinkel wrote:

I’m new to Rails and am trying to use a field called “code” instead of
“id” in my URLs. For example, assuming I’ve got a database of
motorcycles makes where the codes are “Honda”, “Yamaha”, “Suzuki”, and
“Kawasaki”, etc. To show the info about Honda I want to use this url:

http://www.mysite.com/makes/honda/

instead of:

http://www.mysite.com/makes/show/1/

I have a controller called makes_controller.rb, a model called make.rb,
and a layout called makes.rhtml. What would I need to modify? And if
you don’t mind, could you be specific about where the changes go since
I’m new to rails.

Mucho thanks in advance.

try ‘routes.rb’

and read this…

http://manuals.rubyonrails.com/read/chapter/65


#3

Wow, that was quick! Thanks.

Routes solved 1/2 of the problem. For good measure, here is what I have
in routes.rb:

# i.e. http://www.imcdb.com/makes/
map.connect ':controller', :action => 'list'

# i.e. http://www.imcdb.com/makes/list/
map.connect ':controller/list', :action => 'list'

# i.e. http://www.imcdb.com/makes/new/
map.connect ':controller/new', :action => 'new'

# i.e. http://www.imcdb.com/makes/honda/
map.connect ':controller/:code', :action => 'show'

# i.e. http://www.imcdb.com/makes/honda/edit/
map.connect ':controller/:code/:action'

One of the remaining problems is that I can “Show” links in the List
action look like this (and the edit and destroy links are similar):

http://localhost:3000/makes/1
http://localhost:3000/makes/2
http://localhost:3000/makes/3
http://localhost:3000/makes/4

Further, when I type http://localhost:3000/makes/honda/ I get:

ActiveRecord::RecordNotFound in Makes#show
Couldn't find Make without an ID

I’ve programmed in ASP and SQL Server before so am very familar with the
concept of database driven websites, but I can’t figure out exactly what
syntax to use. For example, I tried adding the following to the ‘Make’
class:

def to_param
	code
end

but it tells me:

NameError in Makes#list
Showing app/views/makes/list.rhtml where line #15 raised:

undefined local variable or method `code' for #<Make:0x3986410>

I’m so confused! Your help is definitely appreciated in advance.


#4

On Jan 10, 2006, at 9:27 PM, Mike Schinkel wrote:

I have a controller called makes_controller.rb, a model called
make.rb,
and a layout called makes.rhtml. What would I need to modify? And if
you don’t mind, could you be specific about where the changes go since
I’m new to rails.

Mucho thanks in advance.

When you create a new rails project, there is a directory structure
that gets built. Something like this:

(your app’s root)
|- app
|- db
|- config
|- public
|- test
|- log
|- vendor

etc.

In the config directory is routes.rb where you can edit the “pattern”
for your urls.

You’ll want to add this one above the default route (the default
looks like “connect ‘:controller/:action/:id’”):

connect ‘makes/:code’, :controller => ‘makes’, :action => ‘show’

The reason we hard-code ‘makes’ in to the pattern and then go ahead
and tell it that the controller is ‘makes’ too is because we want to
be sure that the routing system knows this route is specifically for
anything in the url that begins with ‘makes/’.

One other note: You would normally use this instead:

connect ‘makes/:id’, :controller => ‘makes’, :action => ‘show’

but I used ‘code’ because it seemed like you wanted that in
particular. Not sure if it’s important or not :slight_smile:

Take care,
Duane J.
(canadaduane)
http://blog.inquirylabs.com/


#5

Further, when I try to add “.code” to “make” in list.rhtml list so:

<% for make in @makes %>
  <tr>
  <% for column in Make.content_columns %>
    <td><%=h make.send(column.name) %></td>
  <% end %>
    <td><%= link_to 'Show', :action => 'show', :code => make.code 

%>

<%= link_to ‘Edit’, :action => ‘edit’, :code => make.code
%>
<%= link_to ‘Destroy’, { :action => ‘destroy’, :code =>
make.code }, :confirm => ‘Are you sure?’ %>

<% end %>

I get the following error:

NoMethodError in Makes#list
Showing app/views/makes/list.rhtml where line #15 raised:

undefined method `code' for #<Make:0x3a7c080>

VERY confused!

(BTW, I’ve been reading ‘Agile Web D. with Rails’ and it
implies that the above should work, or at least I think it does.)


#6

Sebastian Grä�l wrote:

Rails searches for an Record in the db with ID = “honda”… got it?

Am 11.01.2006 um 05:27 schrieb Mike Schinkel:

That part is obvious; it’s the standard behavior. I’m trying to get
something other than standard behaviour. What I’m asking is how do I
get it to search for a Record in the db with code = “honda”?


#7

Rails searches for an Record in the db with ID = “honda”… got it?

Am 11.01.2006 um 05:27 schrieb Mike Schinkel:


#8

Mike Schinkel wrote:

Sebastian Grä�l wrote:

Rails searches for an Record in the db with ID = “honda”… got it?

Am 11.01.2006 um 05:27 schrieb Mike Schinkel:

That part is obvious; it’s the standard behavior. I’m trying to get
something other than standard behaviour. What I’m asking is how do I
get it to search for a Record in the db with code = “honda”?

you will need to add ‘:conditions => [“code = ?”, params[:code] ]’ to
your finds.
Particularly the paginate function in the list action.

_Kevin


#9

That part is obvious; it’s the standard behavior. I’m trying to get
something other than standard behaviour. What I’m asking is how do I
get it to search for a Record in the db with code = “honda”?

you will need to add ‘:conditions => [“code = ?”, params[:code] ]’ to
your finds.
Particularly the paginate function in the list action.

Thanks. This isn’t working.

Using this URL:

http://localhost:3000/makes/honda/

And this “show” in “makes_controller.rb”:

def show
@make = Make.find(params[:id], :conditions => [“code = ?”,
params[:code] ])
end

I get this error:

ActiveRecord::RecordNotFound in Makes#show
Couldn’t find Make without an ID AND (code = ‘1’)

Changing to:

def show
@make = Make.find(params[:code], :conditions => [“code = ?”,
params[:code] ])
end

I get this error:

ActiveRecord::RecordNotFound in Makes#show
Couldn’t find Make with ID=honda AND (code = ‘honda’)

Changing to:

def show
@make = Make.find(:all, :conditions => [“code = ?”, params[:code] ])
end

I get this error:

NoMethodError in Makes#show
Showing app/views/makes/show.rhtml where line #3 raised:

undefined method `Name’ for []:Array

Extracted source (around line #3):

1: <% for column in Make.content_columns %>
2:


3: <%= column.human_name %>: <%=h @make.send(column.name) %>
4:


5: <% end %>
6:

There are other problems no ones answered, but I can’t even get past
this. Help?

Thanks in advance.

-Mike
P.S. You can read all my questions here:
http://www.ruby-forum.com/topic/51328


#10

You almost had it. Change the .find(:all…) to .find(:first…)

And the make.code part should work alright, ecspecially if your finds
are working as you have listed…not sure on that one. Whats your
list method look like?

-Nick


#11

Mike Schinkel wrote:

Changing to:

def show
@make = Make.find(:all, :conditions => [“code = ?”, params[:code] ])
end

Change the above to
def show
@make = Make.find(:first, :conditions => [“code = ?”, params[:code]
])
end

or even
def show
@make = Make.find_by_code(params[:code])
end

The second example makes use of RoR’s dynamic finders.

Hope this works

joey__


#12

joey__ wrote:

Change the above to
def show
@make = Make.find(:first, :conditions => [“code = ?”, params[:code] ])
end

or even
def show
@make = Make.find_by_code(params[:code])
end

Thanks! FYI, the first works but the second gives this error:

NoMethodError in Makes#show
undefined method `find_by_code’ for Make:Class

Also, can you tell me why :first worked but :all did not? What’s the
difference when my conditions limit to one record?


#13

Nick S. wrote:

not sure on that one. Whats your list method look like?

Here’s app/views/makes/list.rhtml:

<table>
  <tr>
  <% for column in Make.content_columns %>
    <th><%= column.human_name %></th>
  <% end %>
  </tr>

<% for make in @makes %>
  <tr>
  <% for column in Make.content_columns %>
    <td><%=h make.send(column.name) %></td>
  <% end %>
    <td><%= link_to 'Show', :action => 'show', :code => make %></td>
    <td><%= link_to 'Edit', :action => 'edit', :code => make %></td>
    <td><%= link_to 'Destroy',
    	    	    { :action => 'destroy', :code => make },
    	    	    :confirm => 'Are you sure?' %>
    </td>
  </tr>
<% end %>
</table>

Here is the list method in app\controllers\makes_controller.rb:

def list
   @make_pages, @makes = paginate :makes, :per_page => 10
end

These result in URLs to Show that look like this:

http://localhost:3000/makes/1

Instead of the desired:

http://localhost:3000/makes/honda

I tried adding “.code” to “make” in list.rhtml above, but get this
error:

NoMethodError in Makes#list
Showing app/views/makes/list.rhtml where line #15 raised:

undefined method `code' for #<Make:0x36f2fe0>

Again, thanks in advance for helping me understand what I’m doing wrong
here.

-Mike


#14

I just want to chime in that I am also having problems with dynamic
finders. I thought it might be related to the complexity of my
configuration (legacy schema MSSQL DB from linux rails app server using
freeTDS and ODBC), but if others are having problems with dynamic
finders,
then maybe it is more general. The thread I started in this mailing
list is
called “Repost - Do dynamic finders work with legacy schemas?”**. I
also
opened a ticket against ActiveRecord in Trac (Ticket #3452). Can anyone
else confirm a problem like this (find(with conditions) works, but
find_by_condition doesnt)?

Eden


#15

Mike Schinkel wrote:

I think I figured it out. I was trying:

make.code

But instead I needed to do:

make.attributes[‘Code’]

BTW, is there any other way that isn’t as verbose?

Duh… make.Code works (I’m not used to case-sensitivity, yet ironically
I’m usually anal about consistent casing!)


#16

I think I figured it out. I was trying:

make.code

But instead I needed to do:

make.attributes[‘Code’]

BTW, is there any other way that isn’t as verbose?