# Relative Linking in Radiant

**URL:** <https://www.ruby-forum.com/t/relative-linking-in-radiant/106585>\
**Category:** Radiant CMS\
**Created:** [June 12, 2007, 7:30am UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585 "2007-06-12T07:30:03Z")\
**Posts on this page:** 13\
**Page:** 2

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 13, 2007, 7:04pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/21 "2007-06-13T19:04:50Z")

</div>

Chris P. wrote:

> |- C  
> Given the above if I am on A and want to link to F or G, I generally  
> use:

F or G

Granted the extra dot is more explicit, but it seems more semantic,  
especially when you compare it to how you link to siblings:

B or C

But perhaps I’m strange.

–  
John L.  
[http://wiseheartdesign.com](http://wiseheartdesign.com)

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 13, 2007, 7:30pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/22 "2007-06-13T19:30:38Z")

</div>

Back on track… I see three possible methods:  
1.) Current behavior with trailing slashes (slash & no-slash are the  
same)  
2.) Force a trailing slash (redirect the user’s browser to address  
ending in a slash) except for certain file types (CSS, JS, etc).  
3.) Strip all trailing slashes (redirect to the address not ending in a  
slash)

Which are acceptable for Radiant to support/permit?

If more than one way is permitted, we need some sort of configuration.  
How would you like that done/named?

-Chris

P.S. your ./ thing is wild. If I ever learned that one, I’ve long  
forgotten it. I don’t think I’ve ever seen it used.

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 13, 2007, 7:46pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/23 "2007-06-13T19:46:57Z")

</div>

Chris P. wrote:

> Back on track… I see three possible methods:  
> 1.) Current behavior with trailing slashes (slash & no-slash are the  
> same)  
> 2.) Force a trailing slash (redirect the user’s browser to address  
> ending in a slash) except for certain file types (CSS, JS, etc).  
> 3.) Strip all trailing slashes (redirect to the address not ending in a  
> slash)

I favor only 1 and 2. For configuration, I’d recommend an inherited  
class attribute on Page:

Page.trailing\_url\_slash = true  
StylesheetPage.trailing\_url\_slash = false

Combined with an attribute on SiteController:

SiteController.normalize\_urls = true

Or something of that nature.

–  
John L.  
[http://wiseheartdesign.com](http://wiseheartdesign.com)

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 13, 2007, 7:20pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/24 "2007-06-13T19:20:22Z")

</div>

John W. Long wrote:

> F or G
> 
> Granted the extra dot is more explicit, but it seems more semantic,  
> especially when you compare it to how you link to siblings:
> 
> B or C
> 
> But perhaps I’m strange.
> 
> –  
> John L.  
> [http://wiseheartdesign.com](http://wiseheartdesign.com)

Perhaps.

But you make up for it in not being opinionated like I am. 😉

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 13, 2007, 8:04pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/25 "2007-06-13T20:04:00Z")

</div>

Brian G. wrote:

> other-site host) will return “site.css”, which is horribly  
> incorrect.

I am not sure I understand this. If main.css is an alias page, its model  
should make sure that it returns the alias’s canonical URL instead of  
the destination page’s URL.

Cheers,  
Oliver

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 13, 2007, 7:52pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/26 "2007-06-13T19:52:59Z")

</div>

On Jun 13, 2007, at 10:39 AM, John W. Long wrote:

> > deciding if a trailing slash should be added. If we then want to have  
> > CSS and XML without trailing slashes, we can just add a new derived  
> > page model that computes the canonical URL differently.
> 
> I’m fine with it being implemented through Page#url, but I would  
> suggest  
> that the default implementation check the file extension to  
> determine if  
> the trailing slash is necessary.

I’m not. It suggests that there is only one URL to access a page,  
and that may not be the case.

My example:

/ (Virtual Domain Page)  
/main-site  
/main-site/site.css  
/other-site  
/other-site/site.css  
/other-site/main.css (Alias Page) (to /main-site/site.css)

This would allow certain pages in the “other site” to look like the  
main site (an organizational theme to override a site theme, for  
example). However, doing Page.find\_by\_url(’/main.css’).url (from the  
other-site host) will return “site.css”, which is horribly  
incorrect. Perhaps I’m being overly cautious, but I don’t think that  
Radiant should enforce a redirect to the “one true URL” anywhere. It  
seems to seriously limit extensions.

That said, I do think that the trailing slash addition or removal is  
useful. Personally, I think of a radiant page similarly to the  
index.html of a directory in most cases. (So a sibling is actually  
“…/sibling”.) YMMV. Adding .html to the slug of pages that  
shouldn’t be directories (or a trailing slash to those that should)  
isn’t a bad idea, I think.

~~ Brian

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 13, 2007, 8:26pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/27 "2007-06-13T20:26:06Z")

</div>

On Jun 13, 2007, at 2:00 PM, Oliver B. wrote:

> > example). However, doing Page.find\_by\_url(’/main.css’).url (from the  
> > other-site host) will return “site.css”, which is horribly  
> > incorrect.
> 
> I am not sure I understand this. If main.css is an alias page, its  
> model  
> should make sure that it returns the alias’s canonical URL instead of  
> the destination page’s URL.

Not in the way that I wrote the alias page. My Alias Page extension  
simply returns the source page directly rather than attempting to re-  
route and correct method calls. This was primarily done for  
simplicity, as all I had to implement was find\_by\_url to return pages  
from a different portion of the tree. But even if I did that, then  
the children of the aliased page would be problematic.

The current design allows children of the AliasPage to override pages  
of the source Page. The idea was for directories that contain mostly  
the same information (CSS pages?) to be copied across sites but still  
have local customizations. If I had to correct the url method of  
these, I’d have to do some odd trickery with creating AliasPage  
instances that don’t exist in the database.

The Alias Page I wrote is amazingly simple and useful. If the core  
team decides that it’s fundamentally flawed in some method that  
requires me to change it, I understand. But I simply used it as an  
example near to my heart. Changing Radiant to have “One True URL”  
for pages limits the power of virtual pages and extensions, and  
that’s all I wish to speak against.

~~ Brian

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 13, 2007, 10:40pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/28 "2007-06-13T22:40:33Z")

</div>

Brian G. wrote:

> The Alias Page I wrote is amazingly simple and useful. If the core  
> team decides that it’s fundamentally flawed in some method that  
> requires me to change it, I understand. But I simply used it as an  
> example near to my heart. Changing Radiant to have “One True URL”  
> for pages limits the power of virtual pages and extensions, and  
> that’s all I wish to speak against.

Hi Brian,

That is reasonable. I don’t suggest to force an entirely different URL  
onto something that was addressed via an alias, virtual or other  
abstract page. However, if you have a virtual page or an alias page, I  
don’t think it is too much to ask for what its canonical URL should be.  
Something similar is already done with the Archive page, that generates  
URLs that are not only composed of the slug of the page and the slugs of  
the page’s ancestors. All I am suggesting is to redirect if  
clean\_url(Page#url) != request url [1]. The model can then decide how to  
compute the URL. I suspect your alias page model’s url method already  
computes /other\_site/alias\_page instead of /first\_site/source\_page.

Cheers,  
Oliver

[1] I believe clean\_url currently adds a trailing slash, which has to be  
fixed and left up to the model to do if necessary.

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 14, 2007, 2:24am UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/29 "2007-06-14T02:24:02Z")

</div>

On Jun 13, 2007, at 4:37 PM, Oliver B. wrote:

> All I am suggesting is to redirect if  
> clean\_url(Page#url) != request url [1]. The model can then decide  
> how to  
> compute the URL. I suspect your alias page model’s url method already  
> computes /other\_site/alias\_page instead of /first\_site/source\_page.

Actually, it doesn’t. And I think that redirect is broken for any  
site that has multiple ways to access the same page. And it sucks  
from a performance point of view as we have to do find\_by\_url twice  
for the page twice before displaying it.

~~ Brian

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 14, 2007, 5:28am UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/30 "2007-06-14T05:28:21Z")

</div>

On 13/06/07 09:22 PM, Brian G. was heard to say:

> On Jun 13, 2007, at 4:37 PM, Oliver B. wrote:
> 
> > All I am suggesting is to redirect if  
> > clean\_url(Page#url) != request url [1]. The model can then decide  
> > how to  
> > compute the URL. I suspect your alias page model’s url method already  
> > computes /other\_site/alias\_page instead of /first\_site/source\_page.
> 
> Actually, it doesn’t.

I think it should. I don’t see why not.

> And I think that redirect is broken for any  
> site that has multiple ways to access the same page.

There is no reason for accessing the _same_ page via multiple ways.  
That’s just bad design. Compared to a Unix file system, there are  
directory entries and there is data. Two directory entries may point  
to the same data, but still are distinct directory entires. Asking  
either of them for their path will return two different paths.

> And it sucks from a performance point of view as we have to do find\_by\_url twice  
> for the page twice before displaying it.

Only if it actually needs to be redirected. Apache does not seem to  
have a problem to stat a directory twice for the same reason.  
Redirects should be fairly infrequent if the web-author is paying  
attention.

Cheers,  
Oliver

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 14, 2007, 4:54pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/31 "2007-06-14T16:54:54Z")

</div>

On Jun 13, 2007, at 11:27 PM, Oliver B. wrote:

> I think it should. I don’t see why not.

Flat out simplicity. The AliasPage just has a find\_by\_url that  
returns the other page. And since a page can have child pages, if I  
didn’t just re-route the request I’d either have to have an alias for  
each subchild (ugly) or do some complicated trickery involving  
creating Page objects on the fly that don’t actually exist in the  
database (which I don’t like, but can do if it becomes necessary).

I’ll admit the AliasPage extension is a dumb hack. But it works, and  
I think it’s simplicity is an example of how the simple framework of  
Radiant is powerful. I have no objection to altering the extension  
to do these things so that the resulting page gives the correct URL,  
if there is a compelling reason for it. But you haven’t given me one.

> > And I think that redirect is broken for any  
> > site that has multiple ways to access the same page.
> 
> There is no reason for accessing the _same_ page via multiple ways.  
> That’s just bad design. Compared to a Unix file system, there are  
> directory entries and there is data. Two directory entries may point  
> to the same data, but still are distinct directory entires. Asking  
> either of them for their path will return two different paths.

Hard Links. Symbolic Links. Used all the time in Unix to have the  
same file in multiple places. And, AFAIK, you can’t ask “where is  
this file” once you’ve opened it. The best you can get is “what path  
did I open this file with”. Ext2 inodes don’t even know what their  
parent is. Directory entries point back to their parents with the  
“…” link, but files have no concept of where they are stored and it  
makes links significantly easier.

My use of it is to have the same CSS file(s) across multiple sites.  
But I could see an extension that publishes an address book with URLs  
like /addresses//. If a person is in multiple groups,  
should I have to update multiple pages when their contact information  
changes? Or shouldn’t I be allowed to have a single page with their  
information and a “groups” part the describes all the groups they are  
in? What if we added authorization so that not everyone can see  
every group? How do we handle your redirect now?

> > And it sucks from a performance point of view as we have to do  
> > find\_by\_url twice  
> > for the page twice before displaying it.
> 
> Only if it actually needs to be redirected. Apache does not seem to  
> have a problem to stat a directory twice for the same reason.  
> Redirects should be fairly infrequent if the web-author is paying  
> attention.

find\_by\_url is one of the biggest time issues in Radiant, as far as I  
can tell. Avoiding it would be useful. And I don’t see what  
redirecting to the “one true URL” would help. A site-wide setting  
for “add a trailing slash” or “remove a trailing slash” (possibly  
with don’t add slashes if there’s an extension on the URL), it would  
be faster and solve the original problem without adding additional  
cost or complication.

Doing what you suggest adds a limitation to Radiant and doesn’t  
provide a significant bonus.

That’s my issue.

~~ Brian

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 14, 2007, 8:00pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/32 "2007-06-14T20:00:24Z")

</div>

Brian G. wrote:

> On Jun 13, 2007, at 11:27 PM, Oliver B. wrote:
> 
> > I think it should. I don’t see why not.
> 
> Flat out simplicity. The AliasPage just has a find\_by\_url that  
> returns the other page. And since a page can have child pages, if I  
> didn’t just re-route the request I’d either have to have an alias for  
> each subchild (ugly) or do some complicated trickery involving  
> creating Page objects on the fly that don’t actually exist in the  
> database (which I don’t like, but can do if it becomes necessary).

I see how this works now. It’s clever, but I don’t agree with that  
choice. I think an AliasPage should be a separate entity and its  
attributes, i.e. #url, should be consistent with how you access it. But  
that’s just me.

> this file" once you’ve opened it.  
> True, but you _can_ ask a page where it is. Assume I am asking an  
> AliasPage for its path, you say it is alright to return a different path  
> than the one I used to find the page.

> My use of it is to have the same CSS file(s) across multiple sites.  
> But I could see an extension that publishes an address book with URLs  
> like /addresses//. If a person is in multiple groups,  
> should I have to update multiple pages when their contact information  
> changes?

No, I think an AliasPage is a good extensions and I understand your  
reasons for it. I don’t agree with those reasons, but that again is just  
me. I just don’t think the AliasPage should not even be aware of its own  
existence when accessed.

> What if we added authorization so that not everyone can see  
> every group? How do we handle your redirect now?

I don’t know what you mean by that. If you are asking whether I think if  
an AliasPage should delegate authorization to the target page, then  
the answer is yes. In fact, I would have the AliasPage inherit the  
authorization rules from the target page and provide the option to  
overwrite/augment them.

> > > And it sucks from a performance point of view as we have to do  
> > > find\_by\_url twice  
> > > for the page twice before displaying it.  
> > > Only if it actually needs to be redirected. Apache does not seem to  
> > > have a problem to stat a directory twice for the same reason.  
> > > Redirects should be fairly infrequent if the web-author is paying  
> > > attention.
> 
> find\_by\_url is one of the biggest time issues in Radiant, as far as I  
> can tell. Avoiding it would be useful.

I agree, but as mentioned before, duplicates occur rarely and only if  
the “wrong” URL was used to begin with. Instead of redirecting we could  
just produce a 404.

\< And I don’t see what

> redirecting to the “one true URL” would help. A site-wide setting  
> for “add a trailing slash” or “remove a trailing slash” (possibly  
> with don’t add slashes if there’s an extension on the URL), it would  
> be faster and solve the original problem without adding additional  
> cost or complication.

Also mentioned before, an extension is not a sufficient criteria to  
decide whether something should have a trailing slash or not. If it  
would, what extensions would you choose? Or do you treat everything  
after the last dot as an extensions, thus limiting your choice of slug?  
Only allowing up to 4 characters as extension?

Cheers,  
Oliver

---

<div class="post-metadata">

**Author:** ![mahadewa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9e8a1a/32.png) [@mahadewa](https://www.ruby-forum.com/u/mahadewa)\
**Post date:** [June 14, 2007, 10:19pm UTC](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585/33 "2007-06-14T22:19:51Z")

</div>

On Jun 14, 2007, at 1:58 PM, Oliver B. wrote:

> I see how this works now. It’s clever, but I don’t agree with that  
> choice. I think an AliasPage should be a separate entity and its  
> attributes, i.e. #url, should be consistent with how you access it.  
> But  
> that’s just me.

The AliasPage extension falls into the category of “quick and dirty  
hack.” It works. Nowhere will I claim that it’s implementation is  
perfect. There are improvements that could be made (proxying the  
desired page and it’s children in the way you describe, for example).

> True, but you _can_ ask a page where it is. Assume I am asking an  
> AliasPage for its path, you say it is alright to return a different  
> path  
> than the one I used to find the page.

It works so far and I don’t see a compelling reason why it’s not  
alright. The url attribute should be a canonical way to access the  
page but I don’t see why it has to be the _only_ way, as you suggest.

> > But I could see an extension that publishes an address book with URLs  
> > like /addresses//. If a person is in multiple groups,  
> > should I have to update multiple pages when their contact information  
> > changes? What if we added authorization so that not everyone can see  
> > every group? How do we handle your redirect now?

At this point, I am discussing a hypothetical extension, not the  
AliasPage in particular. This is a simple address book extension,  
where the tree appears as:

/addresses/ (AddressBookPage)  
/person  
/person2  
/person3

and each person page has two parts: main and groups. The groups part  
is a list of what groups that person belongs to. The AddressBookPage  
then gives the following URLs:

/addresses/  
/addresses/group1/  
/addresses/group1/person/  
/addresses/group1/person2/  
/addresses/group2/  
/addresses/group2/person2/  
/addresses/group2/person3/

Should we forbid person2 from being accessed from two different  
URLs? Why? Perhaps there is additional logic in the display that  
shows slightly different parts based on the group. Or there is an  
authorization extension that only shows you certain groups. What  
should person2.url return? Why should we redirect group2/person2 to  
group1/person2 (or vice versa)?

> > find\_by\_url is one of the biggest time issues in Radiant, as far as I  
> > can tell. Avoiding it would be useful.
> 
> I agree, but as mentioned before, duplicates occur rarely and only if  
> the “wrong” URL was used to begin with. Instead of redirecting we  
> could  
> just produce a 404.

I try to produce human-readable (and therefore typeable) URLs. I’d  
argue that the URL would be mis-typed (regarding trailing slashes) on  
a regular basis. And producing a 404 is wrong when we should be able  
to easily correct it.

> Also mentioned before, an extension is not a sufficient criteria to  
> decide whether something should have a trailing slash or not. If it  
> would, what extensions would you choose? Or do you treat everything  
> after the last dot as an extensions, thus limiting your choice of  
> slug?  
> Only allowing up to 4 characters as extension?

I don’t care. I’m all for adding a trailing slash to each and every  
page. Or removing it from them all. Or making it based on the  
page’s class or layout. (Although I’m less for that due to the  
lookups required, but not against.) Actually, thinking about it now  
I think that the presence or absence of the trailing slash is a  
matter for the layout, not the page type. After all, a Page can be a  
HTML or CSS file based on it’s layout. It would simply be a boolean  
field on the layout.

But I’m still whole-heartedly against redirecting everything to  
Page#url. It only seems to add limits without adding functionality.  
And that’s my problem with it. I’m not arguing about it to keep my  
extension from breaking. I’m arguing against it because I think it’s  
wrong for Radiant to do conceptually.

~~ Brian

[Previous page](https://www.ruby-forum.com/t/relative-linking-in-radiant/106585.md?page=1)
