Hide FW/1 actions without controller method (view only)

1.4k views Asked by At

Currently I am using "partials" concept in my FW/1 views: these chunks of layout that can be re-used by different views. They are prefixed with underscore for easier maintenance, but unlike the CFWheels these still can be used as implicit views which is not very good.

For example, there's a directory structure:

/views/member/_user.cfm
/views/member/profile.cfm
/views/member/register.cfm

This way actual user form is in the _user.cfm and can be included to the two others using #view('member/_user')#.

What I want is to prevent access to the pages like member._user on the website.

One solution is to create the _user method in member.cfc controller and redirect user somewhere. But creating such methods for each partial is kinda inefficient approach.

Alternative to this would be parsing the rc.action in before and checking if there's underscore in the prefix, but I'm not sure this is clean solution.

Is it possible to disable the action (throw 404) if there's no corresponding method in controller? Or maybe there are some framework events/flags which would allow me to handle "missing method" situation in before?

Thank you.

4

There are 4 answers

4
azawaza On BEST ANSWER

You can create a method in a controller that checks rc.action to see if the item part starts with a _ and redirects elsewhere (or throws an error, or whatever you want to do). Then call this method using controller() function in your setupRequest() method in Application.cfc.

For example, I have a controllers/security.cfc controller with checkItem() method as follows:

function checkItem( rc ) {
    //check if restricted item hss been requested and redirect to main.default
    if ( left(variables.fw.getItem(), 1) eq "_" ) {
        variables.fw.redirect('main');
    }
}

And call it in setupRequest() in Application.cfc:

function setupRequest() {
    //controller( 'security.authorize' );
    controller( 'security.checkItem' );
}

This way it is automatically called on every request - no need to define a separate method for each _item in controllers.

7
baynezy On

The easiest way to do this is to put them in a folder that is not in the web root. Therefore they are not web accessible. Then use a ColdFusion mapping to make them available to ColdFusion.

Make sense?

0
Peter Boughton On

You could use mod_rewrite to detect URLs containing /_ and block/redirect as appropriate.

For example:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^/\w+/_
RewriteRule ^.* /error/404 [L]


The first RewriteCond makes sure that the file does not exist - so if you have a real file /css/_default.css any requests for that will fail this condition and not redirect.

The second RewriteCond accepts any alphanumeric for the first segment, then continues if there is a _ at the start of the second segment. (It's not necessary to match the entire URI, just the start is enough.)

Finally, the RewriteRule is applied only if both conditions were true, but matches all URLs, and performs a server-side redirect to /error/404 - you can update that part as appropriate. (The [L] flag tells mod_rewrite not to attempt any further rewrites.)

0
Sergey Galashyn On

OK, since there's no answer which I've expected (which is fine), here's one more approach which I am using for email templates already.

In the /views/emails/ all the views are email templates which do not have actions, but invoked only like this:

local.body = variables.fw.view("emails/registration_confirmation", local.attrs);
local.template = variables.fw.view("emails/default", {body = local.body});

Where registration_confirmation.cfm is template for specific email body and default.cfm (could call it differently) is email template itself.

To prevent the problem I've described in question controller emails.cfc looks like this:

component extends="components.helpers.controller" {

    public void function before(required struct rc) {
        variables.fw.redirect("user.forbidden");
    }

}

I guess it would be possible to create one more such controller partials.cfc and keep all views in /views/partials/.

But this is my first real-life FW/1 project and I came with idea too late to refactor so many views (1), plus I think having partials in same directory is worse from maintenance point of view, than having them where it makes sense for them (2).

These are two reasons why I've asked this question.