Restful URL - how to design a URL to update a resource based on property, not id - restful-url

If book is a resource, and the server assigns an id to every single book, we can think of the id as a resource id.
/POST /books/ - create a new book resource
/GET /books/12345 - retrieve book resource with id 12345
/POST /books/12345 - update book 12345
But book resources can have some properties, like ISBN.
If I want to update a book resource based on given ISBN, how do I design the URL?

/POST /books/isbn/{isbn_id}
or if you project just need isbn for the book identification, and not the id of each book, you can just replace book id with isbn id.
/POST /books/{isbn_id}

Related

How to get the id of the model I am currently viewing

So lets say I am in /post/2. Which shows me the post with the ID of 2.
Now in controller, how can I see what the current post id is that is being viewed?
My case is a bit different because I am also rendering a partial from another controller into the posts page. And if I delete one of the entries from that partial, I will also need to know the current post id that is being watched.
I'm not sure I completely understand your question, but you can access the ID of any model by simply calling the id method on it. For example if you have a model called Post and an instance of it called #post you would get the id by calling #post.id.
You can get the ID of a model by simply calling id on it. Example: #post.id
If you didn't fetch the model from the database yet, you can get the ID parameter from the URL by accessing params[:id]

add new author to book

Say I have Author and Book domain classes (one Author has many Books). The user goes to book/create to enter the details for a new Book. One of the fields in the form is a select with all Author instances in the database, but this Book belongs to an Author who is not in the database.
What is the best way to implement the interface to add a new Author in grails, but keep the whole process relatively painless for the user? This is what I am thinking:
add Author fields to Book create view in a hidden div
add a link which will show the above mentioned fields and a save button
post the Author fields via Ajax to save them
update the author select to include the newly created Author
auto select the new Author in the select
I will work, but it seems a bit of a nasty approach (hacking the Book create view with non-Book fields). Is there a nicer way?
I don't think placing non-book fields in Book view is nasty.
What I don't understand is the need for separate Ajax call to save new Author - why not do this in the same action that the book is created in? If user chose an existing Author, set up the book as usually. If not, retrieve the author field values, create new Author instance, save it and then set book's author field to it.

ASP.NET MVC routing by string id?

In ASP.NET 2, how do I create a route that allows lookup of an object (eg Product) by a string id (eg ProductCode)? The route for looking up the same object by it's integer id (eg ProductId) is automatic, so I don't actually know how it works.
The automatic route by id is:
/Product/1
How do I also create a 2nd route that uses a string id?
/Product/red-widget
And how do I do it so that both routes are available?
You should take a look at using a route constraint to do this. See http://www.asp.net/mvc/tutorials/creating-a-route-constraint-cs
routes.MapRoute(
"Product",
"Product/{productId}",
new {controller="Product", action="DetailsByName"},
new {productId = #"\w+" }
);
In the above, the constraint regex "\w+" should limit to routes that match only "word" characters (take a look at regex docs for more details on patterns used here).

mvc how can i return back to an action that calls RedirectToAction(..)?

I have an action Create() on my BooksController, where I create a new Book class. Part of this create process is to add one or more Authors, where Author is a class.
Here's the way I envision this working:
When user clicks "Create a new book" they are returned the Create view.
User can click "Add Author" button at any time. "Add Author" posts and saves all data in session, then RedirectToAction("Search", "Author", new { returnController="Books" returnAction="AddAuthor" } (pseudo)
That will return an AuthorId to the AddAuthor Action, which gets the new Book class out of session, updates with author, and redirects back to Create()
My question - is this the best way to handle a 'return to' with MVC? What if I wanted to have the Author Search include an 'add new author' option? I'd want to return to one URL, that returned the ID to a second URL. seems really confusing, could use some help. thanks.
I suggest that u make your AddAuthor controller takes nullable id of the author.
So when u have null id, you can redirect to an action to create an author, that will later return an id of the author that was created and then add it to the book.
And when you do pass the id it will just add the author to the specified book.

asp.net MVC:hierarchical domain model and controllers

My domain model is this: we have a bunch of schools as the root of the "hierarchy". Each school has teachers and courses, and each course has one teacher. I am trying to model this with the logic of the mvc framework and I 'm quite confused. For example, the \school\details\x should give the first page of a school. That should contain a link to a list of its teachers, and a list to each courses.
A list of teachers means that the index action should be parametric to the school the user is looking at: \teacher\id where id is the school. The same with the course list. And then create teacher or course should also be parametric to what school we are looking at:\teacher\create\x where x=school.
How do I carry around the school id? Is there some neat way to do it, or do I need to pass it around all the time, into every view that needs it? It also makes the site URLs very cryptic. I was thinking of a way to make the url structure like {school-alias}\{controller}\{action}\{id}, still I have to find a way to pass around the school. If this is accomplished, then I need to implement some kind of filter that will not allow a user to perform certain actions if the schoolId he is requesting does not match the one in his profile.
I figure that if I 'm carrying the schoolid around the URL, the site is more REST-like, compared to, for example, getting the schoolId from the user's profile.
I would create acronym for every school. For example:
School no. 1 - ABC
School no. 2 - DEF
If i wanted to list teachers, I would write
http://site-address/ABC/teachers/list or just http://site-address/ABC/teachers
To show basic information about school
http://site-address/ABC
The code for routing would be:
routes.MapRoute(
"Default", // Route name
"{acronym}/{controller}/{action}/{id}", // URL with parameters
new {controller = "School", action = "Details", id = ""} // Parameter defaults
);
I would create authorization action filter on teachers,school and classes controller to check if user has access to school defined by acronym parameter in URL. You can check it by comparing filterContext.RouteData.Values["acronym"] with data stored in profile.
Write an extension method to overload rendering of links that extracts the school identifier ( acronym or whatever you choose to use ) from the routing data and adds it to the route values already passed in. This way your action can choose to use the identifier if it is present but is not required to add it to the view data and you do not have to remember to include it in any action links ( you just have to remember to use your action link overload ).
I would make the action link overload quite obviously different so anyone following behind you can see you are doing something unusual. This could be as simple as Html.SchoolActionLink( ...).
For example:
If your url is http://mydomain.com/abc/teachers/list and your route is defined as {school}/{controller}/{action} then the route value dictionary will have the value "abc" at the key "school". The route values can be accessed via HtmlHelper.ViewContext.RouteData.Values.
In the end I 'm answering my own question.
The real solution to this is :Restfull Routing. It implements the functionality in RoR, which is exactly what I need. Too bad this is not a requirement from more people so that it can go into mvc-trunk.

Resources