I am not quite sure what would be a good API design for my scenario below.
We have a model ticket that has an ID and a QR code, both of which are always unique.
To query the status of a ticket, I'm sure this should look obviously like this:
GET /tickets/:id
But what should the design of the QR code API look like?
By also using GET /tickets/:id it would be unclear to the user which locator is being searched for.
GET /tickets?qr_code=:qr_code
would be the second option, but I find this so unpleasant because the returned element is always exactly one and not an array which usually would be the expected response of such a request.
How would a proper API design look like here to query the status of a single ticket by its QR code?
When there are multiple attributes that are unique then that means that each attribute can serve as an identifier in the URL.
Therefore I would document the route in the API like this
GET /tickets/:id_or_qr_code
What basically boils down to the default resource path
GET /tickets/:id
with a controller method like this
def show
#ticket = Ticket.find_by(id: params[:id]) ||
Ticket.find_by(qr_code: params[:id]) ||
# ...
end
Related
(Learning RoR on my own, so pls forgive me if this is an obvious question)
I have an app to track books stored on shelves in libraries. A request should come in like:
GET books/library_id => shows all books on every shelf in a library
GET books/library_id/shelf_id => shows all books on one shelf in a library
GET books/library_id/shelf_id/book_id => shows a particular book
POST would use similar formats, except I will be using JSON in the POST body to supply the information (author, pub date, length, etc) for the book, shelf, or library
My question is, [:params] passed in to my controller seems to hold query (anything after a ?) and POST body parameters, but not the URL, which I need to parse and use to determine what to show. Is there a way to get this out of the parameters? I'm trying to avoid something like GET /books/?library_id/shelf_id
You can set up a route so that params will contain specific URL fragments in addition to the query string and/or post data.
In config/routes.rb:
get 'books/:library_id(/:shelf_id(/:book_id))', to: 'books#show'
In app/controllers/books_controller.rb:
class BooksController < ApplicationController
def show
library_id = params[:library_id]
shelf_id = params[:shelf_id] # may be nil
book_id = params[:book_id] # may be nil
# TODO: Do something with library_id, shelf_id (if present),
# book_id (if present).
end
end
Alternatively, if you wanted to process the URL with some very custom logic, you could have a wildcard route like get 'books/*sometext', to: 'books#show'. Then, in your controller action you could manually parse params[:sometext]. This would be considered "not the Rails way" but it's there if you need complete flexibility.
Finally, maybe it is worth mentioning that in your controller action you can get information about the request such as request.path, request.fullpath, request.url. But it doesn't sound like you need this in your case.
I've used params in a URL for the index page successfully. But, I'm not getting the same success with the show page.
This is what I'm trying to use:
def show
#workorder = Workorder.find(params[:id])
#workorder = Workorders.where("wonum = #{params[:wonum]}") if params[:wonum].present?
Then I'm trying those URLs:
http://localhost:3000/workorders/?wonum='14-21291'
http://localhost:3000/workorder?wonum='14-21291'
Thanks for the help!
UPDATE 1
Rake Routes:
UPDATE2
What I would really like is this url to work:
http://localhost:3000/workorder?wonum='14-21263'
Could I add a route to the workorder show function?
You are almost there, you just need some minor changes and you'll get what you need.
It's important to understand that rails expects route ids to corrospond to database ids like the following:
http://localhost:3000/workorder/32'
This will save 32 in params[:id]
This is the default behavior and you will see this in all the rails beginner examples.
You will run into problems because you are trying to find Work orders by a different field, not id. So you need to change the code in your workorders controller.
Try this:
def show
#workorder = Workorders.where(:wonum, params[:wonum]).first if params[:wonum].present?
#workorder = Workorder.find(params[:id]) if #workorder.nil?
The major differences are how I call the where method (this way where add security for you) and trying to find a workorder from the :wonum parameter before trying to find it using the id. I suspect in your attempt, you were getting a record not found, or routing exception because you didn't pass in an id at all in your example url.
With an id:
http://localhost:3000/workorder?333wonum='14-21263'
I suggest looking at the sql generated in your rails server window to see what is going on.
You should look at this gem for a cleaner, off the shelf solution to what you're trying to do -> https://github.com/norman/friendly_id/
I'm new to ruby on rails....I wanted to know if there is a way to change the URL displayed depending on the client's response. I mean... here's an example:
I'm making a project showing listings in various places...
Now in general I have a home page, a search page, and a detail page for listings. So, respective URLs are officespace/home, officespace/search?conditions, officespace/detailpage?id=(controller-officespace)[&Conditions eg.---price,size,place,type...]
So, every time the client makes a request for search, the same URL is shown, of course with the given conditions.
Now I want that if the client asks for only the place and mentions nothing about size, price, etc., the url should be /listing/location_name.
If he mentions other conditions, then it'll be listing/(office_type)/size(x sq feet)_office_for_rent_in_locationname)
B.t.w. (I already have a controller named listings and its purpose is something else.)
And so on ........... Actually, I want to change URLs for a number of things. Anyway, please help me. And please don't refer me to the manuals. I've already read them and they didn't give any direct help.
This is an interesting routing challenge. Essentially, your goal is to create a special expression that will match the kinds of URL's you want to display in the user's browser. These expressions will be used in match formulas in config/routes.rb. Then, you'll need to make sure the form actions and links on relevant search pages link to those specialized URL's and NOT the default pages. Here's an example to get started:
routes.rb
match "/listing/:officeType/size/:squarefeet/office_for/:saleOrRent/in/:locationName" => "searches#index"
match "/listing/*locationName" => "searches#index"
resources :searches
Since you explicitly mentioned that your listings controller is for something else, I just named our new controller searches. Inside the code for the index method for this controller, you have to decide how you want to collect the relevant data to pass along to your view. Everything marked with a : in the match expressions above will be passed to the controller in the params hash as if it were an HTTP GET query string parameter. Thus we can do the following:
searches_controller.rb
def index
if params[:squarefeet] && params[:officeType] && params[:locationName]
#listings = Listing.where("squarefeet >= ?", params[:squarefeet].to_i).
where(:officeType => params[:officeType],
:locationName => params[:locationName])
elsif params[:locationName]
#listings = Listing.where(:locationName => params[:locationName])
else
#listings = Listing.all
end
end
And to send the user to one of those links:
views/searches/index.html.erb
<%= link_to "Click here for a great office!", "/listing/corporate/size/3200/office_for/rent/in/Dallas" %>
The above example would only work if your Listing model is set up exactly the same way as my arbitrary guess, but hopefully you can work from there to figure out what your code needs to look like. Note that I wasn't able to get the underscores in there. The routes only match segments separated by slashes as far as I can tell. Keep working on it and you may find a way past that.
I have a very high level question that I cant find an answer to that makes sense to me. I understand it''s a terribly broad question but I'm only after some pointers in where to look for answers, not instructions on how to build my site.
So... If I want to render two different types of content in a single page using rails, how would I go about doing this? And how would I format the url? Say I create a gallery model and controller which has information about the gallery and perhaps a description, then I create a gallery-entry controller and model that belongs to the gallery which has an image and image name. If I want to create a url something like www.siteURL/galleryName/GalleryEntry that renders both the gallery info and description and all the associated gallery-entries but also a larger version of the gallery-entry that is named in the url where would i start and how would i structure this? How would i go about creating a url that has multiple attributes and how would i access them in the controller/view?
Thanks - and sorry for the vague question
There's several ways to go about it.
Your URL looks like a "vanity" URL that would exist in addition a normal RESTful route (galleries/:gallery_id/entries/:entry_id). The difference is that you don't want to show just the gallery entry.
If you want to specifically differentiate between different views of the same resource there are a number of ways it could be done, the two I'd consider first are adding another action, or adding a disambiguating query parameter. In this case, it's a hybrid, so I'd probably create a custom match and controller method.
The mapping might look like:
match ':galleryName/:entryName' => 'gallery#highlight_entry' # Or whatever
The action would be (more or less):
def highlight_entry
#gallery = Gallery.find_by_name(...)
#entries = #gallery.entries
#highlighted_entry = # pull from #entries, or retrieve
# Also, filter entries/etc. so the highlighted one doesn't show up
# etc
end
i'm having a situation (pretty standard for everybody i guess), where i have to do two things :
If a user asks for /user path, i have to present his/her personal information.
If a user asks for /user/:id path, i have to present information about that particular user, or the current user information if :id matches the current_user id.
There are definitely many ways to do that, but what is the best approach ? Should i have 2 different routes like /show/:id and /show_current, handled by different actions, or just have a /show/:id and do the handling in that action ?
Bear in mind that if this is the current view, i need to render a different more detailed view than the one about another view. I think the latter is probably the better way,but what do you think ?
If the current user is, say, 42 then /user/42 and /user would display the same information but /user/23 would display a stripped down public version of 23's data. So, the handler for /user/:id will have to know about the special case of :id being the current user; the handler for /user will also have to know about this special case as that's all it does.
If you use two routes then you'll either be duplicating code, wrapping the real code in an extra layer, or some other bit of busy work. I'd just send them both to the same controller method and that could start with something like this:
user = params['id'] ? User.find(params['id']) : current_user
And then later on you handle the special case of the requested user being the current user in just one place with something simple:
if(user == current_user)
# show the full blob of information
else
# show just the limited public information
end
You could, of course, slice it up into a bunch of little methods, such as show_current_user_info and show_other_user_info, inside the controller. The handler for /user could just be a call to show_current_user_info; the /user/:id handler could call show_current_user_info or show_other_user_info depending on what :id is. This approach smells like pointless layering to me.
In RESTful routing, you've described users_path and user_path(some_id). These map to User#index and User#show. The index method is normally a list of users, but if you are wanting index to show the current_user personal information, you can certainly do that. If you also need a list method, just add it to your controller and create a route to it.