Restful resources rails - ruby-on-rails

What is the correct way to make this api 'restful'
I have a location,
GET location/:id
PUT location/:id
The spec has changed and now this location can have certain 'types' the client can update. One requirement is that the client get the allowed types (could be one of these from a fixed list - i.e.['urban', 'wilderness', 'private', etc..]) for all locations. This isn't a nested resource, its a column on the location table. I've implemented,
GET location/types_allowed
is there are better RESTFUL way?
Another example, a location can have neighbors, so I made GET locations/neighbors. I'm having trouble understanding the nuances of REST beyond CRUD and nested resources. Thanks!

Instead of a column as types_allowed, create a type resource and the relation can be like
location.rb
belongs_to :type
type.rb
has_many :locations
and with this your route file would be
resources :type do
resources :location
end

I strongly recommend against naming a model/column "type". That tends to break magic things inside of rails that you don't even know are there until you try that. It's one of those "undocumented features" :P
I'd instead recommend reading up on "single table inheritance" or "polymorphism" to figure out if either of these is right for you.
If not... then name something "kind" instead of "type" as it'll all work a lot better that way.
As to RESTful resources... you really can't go past the Rails Guides. If you follow the routing guide: (and all the other ones) you'll get an idea of how to do RESTful resources

Related

Maintaining REST with namespaced models in Rails

I'm building an online store and thought it best to namespace the various composite parts. Products, Orders, Users etc...
I currently have the Product Module defined and laid out as follows
Product::Base
The underlying product itself it defines dimensions, a type and available colours
Product::Type
High level product categorisation
Product::Colour
HABTM colour relationship with Base
Product::Unit
Expands on base for varying quantities and shipping prices
Now my question relates to the controller and routing. I want the module to appear as the resource and have one of the models (base) as sort of the "head". I've managed to get this working with
scope :module => "product" do
resources :base, path: "product"
end
which yields from rake routes
base_index GET /product(.:format) product/base#index
POST /product(.:format) product/base#create
new_base GET /product/new(.:format) product/base#new
edit_base GET /product/:id/edit(.:format) product/base#edit
base GET /product/:id(.:format) product/base#show
PUT /product/:id(.:format) product/base#update
DELETE /product/:id(.:format) product/base#destroy
This is exactly the behaviour I want but my question is, is this approach RESTful and correct? I'd rather be told now I've got it wrong than further down the line.
Thanks as ever.
That is RESTful, yes, but try this too:
Blah::Application.routes.draw do
namespace :product do
resource :base
end
end
Gives you:
product_base POST /product/base(.:format) product/bases#create
new_product_base GET /product/base/new(.:format) product/bases#new
edit_product_base GET /product/base/edit(.:format) product/bases#edit
GET /product/base(.:format) product/bases#show
PUT /product/base(.:format) product/bases#update
DELETE /product/base(.:format) product/bases#destroy

Refactor large routes file

I am making various routes with a format like below:
get "address/1000broadway"
get "address/300main"
This list of routes will likely grow into the thousands. What is the best way to manage this? Can I simply list them all out in the routes file? Or is better to require various files that include the routes? Are there any potential performance issues with the application having to load a large routes.rb file?
Reading the comments,
this feels very much like a CMS type problem.
For that I'd say "treat each address as a 'page', and chuck the custom layout in the database"
But you reckon the templating is too complex to deal with this way.
Have you looked at liquid?
Namely, it'd allow you to store the template in the database, but use conditional logic.
As a bare minimum,
I'd suggest organising your urls.
resources :address do
collection do
get :1000broadway
get :300main
end
end

In Rails 3.0, is there a way for UrlHelper's path method output a nested-resource's route without explicitly specifying the parent?

Let's say I have this setup: An Area has many :places
The routes.rb is something like:
resources :areas, :path=>"/" do
resources :places, :path=>'/places'
end
And so let's say I have the area "Midwest" and the place "Chicago"...to get to the Chicago place page, I do:
area_place_path(place, place.area)
I would really prefer a method that would be able to guess the place's area (since it's a many-to-one relationship) without having to explicitly pass it in as an argument. I know how to write one custom for my specific needs, but I was wondering if there was a magic Rails way that I'm ignorant of?
It seems like there should be a magic Rails way but there isn't. Such a feature can be added in theory but if you read the related Rails code you'll find that such a feature would be a violation of separation of concerns (UrlHelper is part of ActionView but this functionality would need to be aware of ActiveRecord associations) so I don't think this feature will be added any time soon if ever. I personally don't see any harm in writing your own path helpers and a path helper to give you this functionality would be trivial to write. My suggestion is to just write your own path helper. There really should be an easier way (a plugin perhaps?).

Rails STI Association and nested resources

Ok, so I've got a weird pattern here that I can't figure out.
I have an STI set with CallList as the base model, and City & State inherited. A city belongs to a state (and a state has many cities).
A campaign has many call lists, so I want to display them all. I loop over campaign.call_lists and sometimes get Cities, sometimes States. When I want to link to them I do
link_to call_list.name, call_list
which works fine if I have these routes:
resources :cities, :states
When I nest cities inside states, however, the link_to helper can't figure out the appropriate route. Is there a simple way to do this, or am I going to have to do some manual path helper construction?
you need to check for kind of call_list and then use proper route..it can not be directly as route is nested..
link_to call_list.name, call_list.is_a?(City) ? call_list : state_city_path(call_list)

When should you use RESTful controllers in a Rails app, and when should you not?

I'm looking for guidelines on when to know when a RESTful approach to a model and it's associations is proper, and when it's not. Perhaps it's the nature of my current application, but I'm finding that simple models with no associations work well with REST, but complex models with many has_many assocations really seem to complicate the view and the setup required in the controller. form_for calls start to become especially complicated.
Or perhaps it's my neophyte understanding. I've been doing Rails for over three years now, but REST and form helpers together seem to mystify me.
Make a resource of each top-level model in your system. By top-level, I mean models that are independent and have meaning outside of the associated model. Generally, that's most models. In the following example Position and Candidate are top-level. You could consider Candidate to be composed of PastEmployment and positions to which she has applied. Applications to positions and prior work history can be accessed through the Candidate resource, since they don't exist on their own.
Models
class Position
has_many :candidate_positions
has_many :candidates, :through => :candidate_positions
end
class Candidate
has_many :candidate_positions
has_many :positions, :through => :candidate_positions
has_many :past_employments
accepts_nested_attributes_for :past_employments
accepts_nested_attributes_for :candidate_positions
end
class PastEmployment
belongs_to :candidate
end
class CandidatePosition
belongs_to :candidate
belongs_to :position
end
Routes
map.resources :positions
map.resources :candidates
Use a non-resourceful controller for interactions with the user that span models. For example, if you wanted to have a HomeController that shows available positions as well as recent candidates, that would be a new, plain controller. If you want to edit any of the information on this controller, cool! You already have controllers available to handle the form posts, that will automatically be wired with <% form_for #candidate %>. You can render your collection of positions with <%= render #positions %>, and because you've made them a resource, Rails will know to look in views/positions/_position.html.erb for the appropriate partial.
The end result should be that you're never writing logic to handle the persistence of an object in more than one place. That's when controllers get complex and forms get out of hand. It also means that Rails and external systems know where to retrieve and store objects. Same URL, same controller, just a different format.
You might check out this series of Railscasts, which talks about has-many relationships and forms in the context of REST:
Complex Forms Part 1
Complex Forms Part 2
Complex Forms Part 3
I don't know RoR, so I will make generate statements on REST.
REST and ROI treats the URLs as series of nouns, and it uses HTTP methods like GET, POST, PUT, and DELETE as the verbs. This model works for CRUD, and even for models with multiple associations. Since URLs represent resources, associated objects can be expressed as list of URLs.
However if your system requires more fine-grain verbs like validate, move, copy, honk, read, write etc. it may not suit REST.
disclaimer: I know rails, but I still am pretty much a newbie.
Short Answer: REST and form helpers are completely different areas.
Long answer:
As I understand it,Representational State Transfer is only loosely related to the actual rendering of forms and views.
REST really has to do with controllers, and to a certain extend models. The idea is that instead of trying to think about an entire conversation with a client, you write a webapp to respond in specific, predictable ways to individual client messages.
i.e., if a client GETs a model, you just retrieve it, format it for them, send it to them, and forget about it.
if a client POSTS an update of some sort, you change the webapps state to reflect that, send back any response, and then forget about it. Any future GET or POST will look at the new state, but not the message that created it.
So, really, whether or not an application is RESTful depends not really on how complicated the model is, but on how users interact with it. An app meant to be at least somewhat client-agnostic, that is data-centric, is a good candidate for REST. Something that relies heavily on sessions, and interacting with a specific user, and is process-centric, might not be such a good candidate.
On the other hand, you have Rails form helpers. These are great for scaffolding, but sometimes can be frustrating when you try to use them in more complicated ways.
So, what is your main question? Do you have a specific question about rails form helpers? about rails controllers? or something specific to REST?

Resources