I've got a need where each user can customize their own page on a replicated site. In grails it seems the most straightforward way to do this is:
somedomain.com/someController/JohnDoe
spelling out a controller, except this forces folks to type in a longer domain name, versus something like
somedomain.com/JohnDoe
Using sub-domains may be another approach, however they would need to be created automatically, i.e. when someone joins.
Can you please clarify the main ways Grails supports this kind of requirement/need (replicated site), and some of the pros/cons of each?
Thanks, Ray
Edit: Per Tomasz's edit below, the simplest course of action isn't clear. If you have insights on this please do share.
It is called UrlMappings in grails. You need to declare:
"/$username?" {
controller = 'someController'
action = 'user'
}
It redirects to someController, action user and optional variable called username.
This solution has one catch. Every one level path you visit passes this rule and takes you to someController. You cannot go to somedomain.com/books because it passes rule above and it follows you to someController#user with params['username']='books'. Then you can't use default actions. But if you decide that all your other paths have at least one slash, e.g. /books/list then you can follow this solution
Edit: I was wrong. It doesn't work as I've expected. I thought that UrlMappings are applied in order they are defined. That's not true, as explained here. Even worse - it's not documented (GRAILS-6246). Most specific explanation comes from Peter Ledbrook :
It uses a specificity algorithm, so the most specific match should apply
You must experiment then. I suggest you use safest solution and stick with /user/username solution.
Related
I'm working on a new advert website and want to implement some good SEO URLs.
I got category URLs like:
/category
/category/sub-category
This seems ok. What about detail pages?
Option 1:
/announcements-and-notices/announcements-various/15880/suscipit-dis-molestie-malesuada-vestibulum-ut.html
Option 2:
/adverts/15880/suscipit-dis-molestie-malesuada-vestibulum-ut.html
In reality my website has a pretty long URLs due to multiple areas you can shop. So it would become:
/en/area-name/announcements-and-notices/announcements-various/15880/suscipit-dis-molestie-malesuada-vestibulum-ut.html
/en/area-name/adverts/15880/suscipit-dis-molestie-malesuada-vestibulum-ut.html
Which detail page would be a better URL? The first option seems to be better if the product has no long/good title. The second seems better as its the most relevant one and shortest especially with long category names.
I would like to hear your thoughts!
EDIT:
I found this two google docs:
http://www.google.nl/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDYQFjAA&url=http%3A%2F%2Fwww.google.com%2Fwebmasters%2Fdocs%2Fsearch-engine-optimization-starter-guide.pdf&ei=lXyaT6T_L8zR4QSM4c2qDw&usg=AFQjCNEMj8KHxhxQz9cMLoMxMDiLdrAbJw
http://support.google.com/webmasters/bin/answer.py?hl=en&answer=76329
I think I will be going for /adverts. Anyone disagree?
i have seen many of SEO analysts miss something about optimizing their webpage and that is your page will be optimized for only some keywords not all keywords. it is not important how length is your URL. you should first analyze whether the contents in your webpage is rich enough to have such URL with these keywords or not. if the answer for every keyword is yes then the more length will give you the more rank.
I think you can even set your pages up in a way to use only the slug and skip the id, such as:
/adverts/suscipit-dis-molestie-malesuada-vestibulum-ut
or even just:
/suscipit-dis-molestie-malesuada-vestibulum-ut
like this and refer straight to the adverts controller and the advert itself, which has this slug assigned to it (the one with id 15880).
This way you'll have nice and clean URLs. Just assign and keep an unique slug for each advert and handle it using .htaccess, or dynamically inside the code of your site, if the system allows it.
Cheers.
I'm relatively new to Spring, but very new to Spring Security and Grails. To be brief, I know its recommended to not allow .jsp files to be servable, you should toss them in WEB-INF, and set up your controllers to pull them from the right place.
How would I go about doing this in Grails? It seems that I would destroy the idea of "convention over configuration" by tossing gsp's into WEB-INF and then writing logic into all my controllers (if that's even immediately possible...) It seems I would have to alter some basic Grails configurations.
Any ideas?
OK, I haven't seen a complete answer for this here (or elsewhere one StackOverflow) that provides a full valid result, so here's what I've come up with:
First, create a new controller:
grails create-controller gspForbidden
Open this up, and add this to the index action:
index = {
response.status = 404
}
Then, open grails-app/conf/UrlMappings.groovy and add this under the static mappings closure:
"/grails-app/**.gsp"(controller:"gspForbidden")
This will redirect any attempts to view a GSP directly to the gspForbidden controller. That controller, in turn, simply renders a 404 - a file not found response. The best thing about this is that it's completely hidden - there's nothing showing that the GS path was correct, so there's less chance of exposing something important about the application design.
I tried repeatedly to figure out how to use UrlMappings to show a 404 without the controller, but I had no success. If you can think of a way, please let me know. I'd much rather have this happen without any explicit controllers.
Slight correction to earlier post:
Just adhering to the convention in Grails doesn't prevent someone who guesses where a gsp lives from hitting it directly (I just tried it, it works).
From Spring Security Plugin Documentation:
package com.testapp
import grails.plugins.springsecurity.Secured
class SecureController {
#Secured(['ROLE_ADMIN'])
def index = {
render 'Secure access only'
}
}
you can secure your GSP pages as the example above. Secured annotation will provide access only to a user if they have the admin rights.
for more information , refer to :
http://grails-plugins.github.com/grails-spring-security-core/docs/manual/
tutorials are nice as a start.
You actually don't need to worry about this in Grails. If you follow the conventions of using views and controllers it will handle all the details about making sure the GSP pages aren't directly accessible.
As far as integration with Spring Security is concerned, again if you follow one of the recommended patterns (URL security or annotation within your controllers) you should be fine.
Spoiler alert: this is NOW a question, so apologies to anyone that read it purely as a discursive topic :)
Anyway, I was doing a little research today re adding routes via javascript when i thought that a bit of google research wouldn't hurt. Basically, my aim was to do away with the following type of construct within my views:
and replace it with something akin to:
well, i lucked out a little today after finding this fantastic article (which isn't mine nor do i have any affiliation other than respect for the piece of work):
http://weblogs.asp.net/zowens/archive/2010/12/20/asp-net-mvc-javascript-routing.aspx
this really has been a missing link (or so i thought) for me when dealing with routes via javascript. However, the 2nd code example is misleading and actually won't produce what the example leads on. Can anyone suggest a fix for this and/or an alternative solution to allow this fluent convention of js routes within mvc views??
cheers...
[edit] - question edited 22:16 GMT to explore deeper options on this topic, plus changed title (removed OT portion).
So the question is why the second code example won't work as expected. Here's the answer, post currently doesn't return anything. This is an example of a certain developer not looking at the details of the code. When you use homePageUrl, the value will be undefined.
To actually get the home page URL, you'd do the following:
$.routeManager.action({controller:'Home', action:'Index'}).toUrl()
So, the moral of the story is that the code is a bit broken. The post action SHOULD return an object where you can put "toUrl()" right after the post is performed, like this:
$.routeManager.action({controller:'Home', action:'Index'})
.post(function(data){ alert(data); })
.toUrl();
I'll be fixing this bug in a bit!
This is a new application, and I have an index method on a Search controller. This also serves as the home page for the application, and I'm trying to decide if I am headed down the wrong path from a design pattern perspective.
The method is already 35 lines long. Here is what the method does:
3 lines of setting variables to determine what "level" of hierarchical data is being searched.
Another 10 lines to populate some view variables based on whether a subdomain was in the request or not.
A 10 line section to redirect to one of two pages based on:
1) If the user does not have access, and is signed in, and has not yet requested access, tell them "click here to request access to this brand".
2) If the user does not have access, is signed in, and has already requested access, tell them "so and so is reviewing your request".
Another 10 lines to build the dynamic arel.
I can't get it straight in my head how to separate these concerns, or even if they should be separated. I appreciate any help you can offer!
Summarizing what you've said in something codelike (sorry, don't know ruby; consider it pseudocode):
void index() {
establishHierarchyLevel();
if (requestIncludedSubdomain())
fillSubdomainFields();
else
fillNonsubdomainFields();
if (user.isSignedIn() && !user.hasAccess()) {
if (user.hasRequestedAccess())
letUserIn();
else
adviseUserOfRequestUnderReview();
}
buildDynamicArelWhateverThatIs();
}
14 lines instead of 35 (of course, the bodies of the extracted methods will lengthen the overall code, but you can look at this and know what it's doing). Is it worth doing? That really depends on whether it's clearer to you or subsequent programmers. My guess is it's worth doing, that splitting out little code blocks into their own method will make the code easier to maintain.
That's a lot of variables being set. Maybe this is a good opportunity for a module of some kind? Perhaps your module can make a lot of these decisions for you, as well as acting as a wrapper for a lot of these variables. Sorry I don't have a more specific answer.
Without your code it's somewhat difficult to suggest actual fixes, but it definitely sounds like a really wrong approach and that you're making things much harder than they need to be:
3 lines of setting variables to
determine what "level" of hierarchical
data is being searched
if there is a search form, I would think you would want to pass those straight from the params hash into scopes or Model.where() calls. Setup scopes on your model as appropriate.
Another 10 lines to populate some view variables based on whether a subdomain was in the request or not.
This seems to me like it should be at most 1 line. or that in your view, you should use if statements to change what you'd like your output to be depending on your subdomain.
A 10 line section to redirect to one of two pages based on:
the only thing different in your explanation of the 2 views is "whether the user has requested access" surely this is just a boolean variable? You only need 1 view. Wrap the differences into 2 partials and then in your view and write one if statement to choose between them.
Another 10 lines to build the dynamic arel.
It might be necessary to go into Arel, but I highly highly doubt it. Your actual search call can in most cases (and should aim to be) 1 line, done through the standard ActiveRecord query interface. You want to setup strong scopes in your models that take care of joining to other models/narrowing conditions, etc. through the ActiveRecord Query interface.
Why is this:
http://MySite.com/Project/24/Search/32/Edit/49
preferred over this?
http://MySite.com/Project/24?Search=32&Edit=49
I'm not sure where your premise is coming from? It looks like an artificial example, which makes it hard to comment on.
A better comparison would be something like:
http://MySite.com/Project/24/Members/Edit
As opposed to:
http://MySite.com/Projects.aspx?id=24§ion=Members&action=Edit
Where, among other things, the hierarchy of entities is immediately obvious from the first example (ie, a Project contains Members). It also suggests that you can use other URLs that contain similar structures to the first (ie, /Projects/24 and /Projects/24/Members), so in that sense it's more concise.
If it comes down to actions that have a variable number of parameters, such as searching, then it's totally fine to use URL parameters as this will give you more flexibility, eg:
http://MySite.com/Projects/Search?name=KillerApp&type=NET
You could construct a URL using the first style, but you don't really gain anything, and managing the route could add unnecessary overhead:
http://MySite.com/Projects/Search/name/KillerApp/type/NET
I would argue that this (or any similar construction, eg if you removed the param names) suffers from an artificial hierarchy - the action in this case is really Search, and everything else is just a parameter of the Search, so it's in the same hierarchy, not some "sub" hierarchy.
Not really a fair comparison. The style allows you to drop the GET parameter names, so the routed one should read something like
http://MySite.com/Project/24/32/49
It's really an aesthetic improvement, though -- it's both neater-looking, and easier to type or read out to someone.
Its mostly a human readability issue, although (since most search engine ranking algorithms are not publically disclosed), it is believed to have SEO value as well.
In the example case, it may not be any better. But it's a Search Engine Optimization in general. Here are some SEO best practices -- from that article ...
Ideally, the URL structures should be
static, and reveal what the page is
about. A simple and clear URL
structure is much easier for both
search engine spiders and human
beings.
Easier to remember as well. It's easier for a user to remember /Employee/1 to get the information for employee #1 rather than understand a querystring. Not a reason to use it but I think its a small improvement.