ASP.NET MVC and friendly URLs - asp.net-mvc

I'm trying to learn a bit more about creating friendly URLs, particularly in relation to something like an e-commerce site. If you take a look at this site as an example: http://www.wiggle.co.uk/
It basically lets you refine your search based on the categories. So if I go to http://www.wiggle.co.uk/mens/road-time-trial-bikes/ it will list all men's road bikes, if I then go to http://www.wiggle.co.uk/road-time-trial-bikes/ it will list men's and women's bikes, and if I go to http://www.wiggle.co.uk/bianchi-sempre-105/ it will display a particular bike.
I'm not really sure what the routing would look like for something like this, as you could have many filters in the URL. I'm also not sure how how it's able to distinguish between what's a filter and what's a product.

I'd say you are fairly close but would break out the second and third as it would be a little ambiguous for the one Action to interpret the two parameters. I'd suggest the following:
http://www.wiggle.co.uk/road-time-trial-bikes/
http://www.wiggle.co.uk/bikes/bianchi-sempre-105/
Thus /bikes/ could be routed clearly to a different controller and action. You would need to create a specific rule for the root or you could add a specific controller, say bike-types, to the first url
http://www.wiggle.co.uk/bike-types/road-time-trial-bikes/
The specifics on routing are well documented but a good place to start might be with writing some tests to help you understand what works and give you more confidence with making changes to your routes. It is very easy to create clashing routes and tests help prevent this.
http://mvccontrib.codeplex.com/wikipage?title=TestHelper#Routes

Related

Best practice for choosing nested resources in Rails?

What criteria do you use to decide whether or not to nest resources?
In the past, I have chosen to nest when the index action on a resource makes no sense without scoping to an associated resource (the parent).
Even as I write the above criteria, I realize it is ambiguous at best.
A colleague has stated:
Nest resources because it captures the relationship of the associated models visually in the url structure... And it makes it easy to modify the url to get back to just the post. If I see /posts/123/offers/555 -- I know that I can go to /posts/123 to see my post. Where as if I just saw /offers/555, I'd have no way to get back to the post other than manually navigating through the site.
To me, manipulation of the url by users should have no bearing on the architecture of the application, and flies against what I understand to be the generally held principle that nested resources should be avoided if at all possible. Additionally, this argument would seem to support multiple levels of nesting, which again, pretty much every article I read advises against.
What has been your experience?
I nest routes, as you put it first, when the later things in the route doesn't make sense without the former. Comments on a blog would be nested under resources articles because, though perhaps you want display an individual comment on it's own page (who knows why...), a comment belongs to an article.
This also has controller implementations. If you know the article, then you can find the specific comment scoped to the article. This makes for more effective queries.
Also, your colleague was correct that you have to deal with users messing around with your routes, though he had the wrong reason. It isn't for their convenience, but for their security.
Let's take an Amazon-like app with users and orders. If I am at users/5/orders/2 then I think "hey! I can just change that 5 to a 4 and then see someone else's orders!" If you don't scope orders, then the controller-level logic for authorizing a user to view orders/2 becomes far trickier. Scoping to the user allows for current_user.orders.find(params[:id]) in the orders controller. Current user can be found based on authentication so that they cannot just swap ids in the URL and become someone else.

How can I omit controllers for two models in rails 3 routes?

I'm building a rails3 application and at the moment I have the following line in my routes.rb file:
get "/:id" => 'tapes#show'
In other words, you can show a Tape using website.com/tapes/1 and also by using website.com/1
(I am also using friendly_id gem so the user sees in fact a friendly URL in the form of website.com/tapename)
Now, what I would like to achieve is to do the same thing for Users pages. So instead of showing a User page using website.com/users/alex I want to be able to also use website.com/alex.
Is there a way to implement this 'users' logic in routes.rb together with the existing 'tapes' rule and somehow set a priority?
So if someone accesses website.com/alex my app would search if there is a User record with id 'alex' and if none is found then look for a Tape with id 'alex'.
Could I use some kind of Advanced Constraints in routes?
Any ideas?
Many thanks for the help,
Alex
Rails would have no way to determine which controller you were trying to access. The only way that this would be possible, is if either:
you could determine which model it would resolve to based upon some regular expression on the name.
or
You knew that user names and tape names never conflicted, and were willing to suffer the cost of hitting the database to resolve the correct controller.
This is probably a bad idea for a number of reasons, it would have performance implications, it also doesn't conform to RESTful principles, and it would probably be confusing to users.

How can I change the way links look and act in my Rails 3 application?

I have brands and products, and there is a nightly load that replaces them. A brand may end up with a new id, and a product will always end up with a new id. But I have customers that want static links to these dynamic ids.
I would like a link that now looks like:
.mysite.com/brands/17/products/168390
to look like:
.mysite.com/products/ABC123
where "ABC123" is an alphanumeric identifier not associated with the id. Think of it like a model number.
I don't need anyone to give me the answer, I am happy to do the work. But any pointers to where I can get started would help, as I apparently don't have the right terminology to do a successful Google search.
Thanks!
I would suggest watching the screencasts done by Ryan Bates at RailsCasts.
For your question on how to change the products URL away from id, the specific ones would be Model Name in URL or Semi-Static Pages (just the information on how the routing is accomplished). For your question on the shortening the nested URLS, what you want would be his cast on Nested Resources.
Those are the ones that have to do with your specific problems, however I would suggest watching all of them in order to learn more about the framework. One thing to note is that since those are fairly old, things may have changed some in Rails 3, however I imagine that once you get something to Google, you will be able to find how to do it in Rails 3 fairly easily.
Do it using rails routes. Something like:
match 'products/code/:product_code' => 'products#code'
There are lots of things you can do with routes - my suggestion would be to familiarize yourself with them.

Ruby on Rails simple website layout

I'm learning RoR, I've read some tutorials (railstutorial for the first one),
but I've a problem to define the logic layout of the my first simple website.
The structure is:
When you go to mysite.com you see a welcome page with the signup form or the link for login.
If you signup or you login into the site, you are at mysite.com/dashboard and you see a list of your messages.
You can go to mysite.com/$username and you see a page with a form where you can write a message for the $username.
Stop. That's it. It's very simple, I know, but is for learning.
The problem is this: I'm new to MVC paradigm and I don't know how structure the logic layout of my app. Of course there'll two models: User and Message. But for controllers? And which functions in any controllers? Should I use scaffolding?
Please give me a help, I'm very confused.
Thank you.
Controllers are the logic for the data, so to login/sign-up is really validating/creating a user, if you need to view the users dash board, well that's a look up on the user data so he goes there as well.
The messages, that will be a separate controller that can create/view messages!
As others have pointed out, your controllers contain the logic for your code and invoke views based on that logic by rendering or redirecting to pages. You can define whatever actions you want in your controllers, and then use routes to map a particular URL to a controller action. That being said, Rails gets a lot easier if you "go with the flow" and make some simple assumptions about the actions that could happen. Both your users and your messages represent rows in their respective database tables. There's no much you can do to a row in a database table - you can Create it, Read it, Update it, or Delete it (CRUD). If you define your actions in terms of these four logical actions, Rails lets you generate some easy routes.
You can back into any URL schema that you want, but what you are describing is:
Read the messages that are for a user on the dashboard
Create a message for a user when you go to another page (mysite/username)
Each of these maps to a CRUD action that you should be defining in your controllers.
Agreed also with other advice to simply do a few more tutorials that will probably clear this up.
If you haven't already, read Getting Started with Rails. Look out for the discussion on MVC and scaffolding. Playing around with scaffolding can help you learn where things go and is a great place to start for beginners.
Also, I highly recommend this book: Agile Web Development with Rails. It is very hands on and an easy read.

Creating a different "genre" of my website (i.e., I have a stackoverflow-equivalent and I want to create a serverfault-equivalent)

My site, Rap Genius, explains rap lyrics. I want to create a new site, Rock Genius, that explains rock lyrics – otherwise it'll be the same (same layout, same DB schema; like Serverfault is to Stackoverflow)
What's the best way to do this?
Approach 1: Fork the code
Fork the Rap Genius code, change the relevant parts (e.g., "Rap" -> "Rock"), create a new database and go to town.
Pros: Can get it working quickly
Cons: It'll be somewhat painful to add a feature to both applications. Also it'll be impossible to give Rap Genius access to Rock Genius' data at the DB level
Approach 2: Keep it a single application
Whenever a request comes into my application, check the domain. If it's rapgenius.com, set the SITE_NAME constant to "rapgenius". Create a genre field on user-facing entities (songs, blog posts, etc) and update my queries to use the correct genre based on the SITE_NAME
Create a layer of abstraction above user-facing strings to that I can write <%= welcome_message %> instead of Welcome to Rap Genius! and have welcome_message() take SITE_NAME into account
Pros: Lots of flexibility
Cons: Lots of work!
Thoughts?
The second approach sounds better to me.
You've already highlighted the main pros and cons - it will definitely be more work, but will be much friendlier to maintain. Is there any chance of a third, fourth, fifth site? If so, there's no question that this is the right way to go.
You'll likely also be able to share user accounts, reputation, and any other kind of community based functionality more easily.
It might be worth looking at Rails i18n stuff for 'translating' static text, based on the domain name. That way you could avoid writing helper methods for every string you want to display.
Then you should be able to 'franchise' the site really easily - add translations of static strings, a handle for the new domain, and maybe some site specific images or CSS and you're done!

Resources