Nested Dynamic Routes

Hi,

I have a url scheme where I would like to include a public and private
interface, and I have a nested resource for it.

The two schemes are

/my/books/pages
/:username/books/pages

I would like to sperate the books and pages controllers into
MyBooks, MyPages #=> the user here will always be the currently logged
in
user
and
PublicBooks, PublicPages #=> The users books will be whatever user is
specified.

All public stuff is read only, although there will be a further nested
resource on both (comments) that should be mapped to one controller to
controll all comments, read and write.

I’m thinking at the moment that this will eliminate a lot of messy
controller logic that tries to decide if I can access things or not, and
tries to decide what user the context of the request is in etc.

The messiest that I can see this getting is if the user is accessing
thier
own book through a public interface and wants to say edit it. In this
case
I’m thinking of just re-directing to the edit action of the
MyBooksController

I really don’t have a clue how to proceed here. Here’s what I’m
thinking
but I don’t believe this works.

map.resources :books :path_prefix => ‘my’, :controller =>
‘my_books_controller’ do
books.resources :pages, :controller => ‘my_pages_controller’ do
pages.resources :comments
end
end

map.resources :books :path_prefix => ‘/:username’, :controller =>
‘public_books_controller’ do
books.resources :pages, :controller => ‘public_pages_controller’ do
pages.resources :comments
end
end

Can anyone give a little advice please? Is this even a good way to go,
or
should I be looking elsewhere for a solution?

Cheers
Daniel

Hey,

I’m assuming that you’re asking if using different controllers for
those routes is the way to go.

Whenever I’m presented with those sorts of decisions, the strategy I
reach for the most is “a separate controller for each map.resource(s)”.

It’s not always the strategy that I finish with, but I find it’s
always the best starting point.

Doing it like this stops me from over-generalizing too early. Once
the controllers have all been written with their specific use-cases
in mind (“Make it work”), everything is laid out in front of me. Any
ways I can make things DRYer are blindingly obvious (“Make it right”).

Sometimes I’ll decide to pull something back into a single do-
everything controller. Other times I’ll just create a few mixins or
maybe even an inheritance hierarchy to reduce duplication.

Nearly all of the time I’m just really grateful I resisted the
temptation to start off saying “hey, these are the same so I can just
use one controller!”.

HTH,
Trevor

On 6/22/07, Trevor S. [email protected] wrote:

Hey,

I’m assuming that you’re asking if using different controllers for
those routes is the way to go.

Whenever I’m presented with those sorts of decisions, the strategy I

Sometimes I’ll decide to pull something back into a single do-
everything controller. Other times I’ll just create a few mixins or
maybe even an inheritance hierarchy to reduce duplication.

Nearly all of the time I’m just really grateful I resisted the
temptation to start off saying “hey, these are the same so I can just
use one controller!”.

HTH,
Trevor

I think what your suggesting is that what I’m contemplating isn’t too
bad of
an idea :wink:

I guess what I’m really asking is not so much if the urls are right.
But if
the concept of splitting the controllers like this is correct for what
I’m
trying to achive. Ie having MY user resource, and a public interface to
OTHERs resources.

If this is the way to go. I would like to generate the urls I listed
since
I think they are self explanitory. So then in that case are these
routes on
the right track?

/my/books/pages
/:username/books/pages

map.resources :books :path_prefix => ‘my’, :controller =>
‘my_books_controller’ do
books.resources :pages, :controller => ‘my_pages_controller’ do
pages.resources :comments
end
end

map.resources :books :path_prefix => ‘/:username’, :controller =>
‘public_books_controller’ do
books.resources :pages, :controller => ‘public_pages_controller’ do
pages.resources :comments
end
end

Thanx for you help

Daniel

On 21-Jun-07, at 11:22 PM, Daniel N wrote:

I think what your suggesting is that what I’m contemplating isn’t
too bad of an idea :wink:

I guess what I’m really asking is not so much if the urls are
right. But if the concept of splitting the controllers like this
is correct for what I’m trying to achive. Ie having MY user
resource, and a public interface to OTHERs resources.

Yeah, what I’m saying is: absolutely yes, start by splitting the
controllers. You may end up consolidating them once you’ve fleshed
everything out, but start by coding the controllers to deal with
their specific use-cases in mind.

Once that’s done, the opportunities for doing this “right” will be
staring you right in the face because your code will be telling you
how it should be architected, not some random guy spouting rubbish on
a mailing list :slight_smile:

I.e. you may look at the code and say “gee, all my urls should
be /:username/books etc 'cause the only conditional would be a quick
check to see if the current user name == :username to determine
whether they can edit this resource”. You won’t know that for
certain until all your moving parts are actually doing what they are
supposed to do.

If this is the way to go. I would like to generate the urls I
listed since I think they are self explanitory. So then in that
case are these routes on the right track?

/my/books/pages
/:username/books/pages

Don’t forget to make sure a user can’t use the word ‘my’ as their
username :slight_smile:

HTH,
Trevor

On 6/23/07, Trevor S. [email protected] wrote:

is correct for what I’m trying to achive. Ie having MY user
how it should be architected, not some random guy spouting rubbish on
If this is the way to go. I would like to generate the urls I
HTH,
Trevor

Thanx for the explianation.

At this stage it doesn’t seem as simple as a quick check because the
required permission set makes it all a bit nasty together. Having said
that, I currently have them all together and it smells a bit. Hence the
question.

Thanx again.
Daniel

Sorry if this comes twice. I’m having some trouble with gmail

On 6/23/07, Daniel N [email protected] wrote:

too bad of an idea :wink:
their specific use-cases in mind.
certain until all your moving parts are actually doing what they are

required permission set makes it all a bit nasty together. Having said
that, I currently have them all together and it smells a bit. Hence the
question.

Thanx again.
Daniel

I’ve created a branch to modify my code to reflect this, and it has
quite
suddenly occured to me that this will make views very difficult to do
and
keep them DRY. I would need to duplicate my views for each controller
because of the named routes.

For example and forms where I have

<% form_for @book do |f| %>

No longer work since they look for a book_path. If I then change this
to a
my_book_path in the routes, then my new public controller will not be
able
to use it.

This isn’t so bad for forms, since the public controller doesn’t have
write
access to anything and so these should never be rendered for it.

Where the issue lies is in the link generation. e.g.

<%= link_to @book.title, book_url( @book ) -%> needs to become
my_book_url(
@book ) OR public_book_url( @book ) depending on how it is accessed.

If I have to duplicate my views, or have a bunch of logic in every time
I
want to set a link, I don’t think I will change over since I think this
would be messier in the long run.

Any ideas on how to avoid this?

Thanx
Daniel

Hey,

comments inline:

On 23-Jun-07, at 7:27 AM, Daniel N wrote:

this to a my_book_path in the routes, then my new public controller
will not be able to use it.

This isn’t so bad for forms, since the public controller doesn’t
have write access to anything and so these should never be rendered
for it.

Cool, so we can just ignore that one.

Where the issue lies is in the link generation. e.g.

<%= link_to @book.title, book_url( @book ) -%> needs to become
my_book_url( @book ) OR public_book_url( @book ) depending on how
it is accessed.

If I have to duplicate my views, or have a bunch of logic in every
time I want to set a link, I don’t think I will change over since I
think this would be messier in the long run.

Okay, first I’ll give you the “roll your own, low-impact” version.

The important thing to remember is that book_url etc are just
methods. I’m guessing that you’re not going to permit editing and
deleting so really it’s just book_path(book) and books_path() that
are important at the moment. Note that I didn’t say book_url -
because you really only need to use that for redirects (which implies
editing, and the public controller doesn’t need that).

Anyhow, in the public controller, you just do:

class PublicBooksController
protected
def book_path(*args)
public_book_path(*args)
end
def books_path(*args)
public_books_path(*args)
end
helper_method :book_path, :books_path
end

So any time a request that’s being served by PublicBooksController
sees a book_path or books_path call, it calls the relevant method.
Now MyBooksController and PublicBooksController can use the same
partials.

Now, there are times when you want to re-use views completely
(rather than just sharing partials), and when it’s much more than
just book_path or books_path that you’re calling. If this is one of
those cases then I’ve got a plugin called resource_fu which makes
wiring that up much easier:

http://agilewebdevelopment.com/plugins/resource_fu

But if the code I quote above is enough for you then I’d just stick
with that.

HTH,
Trevor

On 6/23/07, Daniel N [email protected] wrote:

too bad of an idea :wink:
their specific use-cases in mind.
certain until all your moving parts are actually doing what they are

required permission set makes it all a bit nasty together. Having said
that, I currently have them all together and it smells a bit. Hence the
question.

Thanx again.
Daniel

I’ve created a branch to modify my code to reflect this, and it has
quite
suddenly occured to me that this will make views very difficult to do
and
keep them DRY. I would need to duplicate my views for each controller
because of the named routes.

For example and forms where I have

<% form_for @book do |f| %>

No longer work since they look for a book_path. If I then change this
to a
my_book_path in the routes, then my new public controller will not be
able
to use it.

This isn’t so bad for forms, since the public controller doesn’t have
write
access to anything and so these should never be rendered for it.

Where the issue lies is in the link generation. e.g.

<%= link_to @book.title, book_url( @book ) -%> needs to become
my_book_url(
@book ) OR public_book_url( @book ) depending on how it is accessed.

If I have to duplicate my views, or have a bunch of logic in every time
I
want to set a link, I don’t think I will change over since I think this
would be messier in the long run.

Any ideas on how to avoid this?

Thanx
Daniel