checking restful features of the action in controller - ruby-on-rails

when drawing restful routes in ruby on rails you specify
if a controller action applies to a member or collection and
what http verb is used. http://guides.rubyonrails.org/routing.html
How can I check 1 from within the controller instance?
(The HTTP verb can be checked via request.method)
The ugly hack is to check if the named route exists with singular or plural, but the route can have alternative name.
Yet another is to check for the request param used for identifying the member, but collection routes could have the same (optional) param.

If the route is following restful conventions, then running rake routesshould give you the answers you are looking for.
You will see what http verb is expected (answer to 2) and the path should answer your 1) question. For a member action, you need the ID, so typically the path contains the id
This route configuration:
resources :photos do
member do
get 'preview'
end
end
will give you the path photos/:id/preview -> ment to preview a single photo
And the route configuration:
resources :photos do
collection do
get 'preview'
end
end
will give you the path photos/preview -> ment to preview a list of photos
If you need to get this information from within the code of an action:
Inspect the params[:id] to distinguish the intent. If it is for a member, that value will be not nil.

Have you looked at the Journey gem for such a method? Assuming 3.2, that would have it, if anywhere, rather than request param. By then it's too late isn't it?

Related

how to give names to rails generated routes?

when using the following on routes.rb: resource :my_model
I get a few automatically generated routes. Some of them have a name (just like when manually defining them with 'as' keyword) but some of them don't.. so how can I give them names?
Or maybe it's a 'hint' given to me by rails that I'm not supposed to use these routes?
What do you refer to when you say "name", the Prefix when you run rake routes? Many of the HTTP requests (i.e. patch, put, delete) are handled by the controllers and are intended to then either redirect to another path or alter the DOM of the current page if you're using javascript, so they wouldn't have a prefix associated with them as those requests don't have an associated view.
When using a singular resource, all CRUD routes will be generated with the exception of an index route. You do not need names for these paths if you are looking to use them as intended. What is your intent for using these routes?
As per the docs:
A singular resourceful route generates these helpers:
new_resourceName_path returns /re/new
edit_geocoder_path returns /geocoder/edit
geocoder_path returns /geocoder
Please post your output via: bundle exec rake routes
You'll notice the show and create controller actions share the same path with the only difference being one expects a POST request and the other a GET request. This is some of the magic provided by Rails allowing you to use similarly named routes that map to different actions.
Try resources instead of resource. If you want a helper for PATCH, PUT or DELETE, just use the helper for the show action (that you'll get from resources) and specify the HTTP method with method:.
The second answer here has a decent explanation about your resource call.
These routes expect a different request method (this implies additional data in request), and do not need separate name, just use generic global_preferences_path and for example - set method for unobtrusive js in link:
<%= link_to 'Set preference', global_preferences_path(some_parameter:'foo'),
confirm:'Are you sure?', method: :put %>
or use html form or so

Accessing an arbitrary action in rails

I am somewhat confused as to how to properly access an action in a rails controller that is NOT associated with one particular model. The routing file, by default, seems to be routing the action name to "id". So if I type, say, /user/login, I end up with an error that says: "Couldn't find User with 'id'= login"
What is the proper way to access arbitrary action names in rails?
Make a route for it, obviously. The request goes this way:
first it hits a route
from there it hits a controllers' action
[an action may invoke a model] (optional, but common)
controller specified a view and fetches data to render
view is sent back in response to a request
resource and resources might not be obvious about what they do. But in fact, they are shorthands to corresponding collections of routes used quite often, like this is what resources adds. And they're not monoliths, they can be customised to fit your needs. Providing options is just a start, you can provide a block to define your custom action routes for this resource like so:
resources :users do
get :login
end
This will add a /users/login route that maps to UsersController#login, following Rails' conventions.
See this guide for more details and don't forget to run rake routes to see what you have at the moment.

index_ appended to path erroneously added to rails 4 route

I added a controller named "Triage" to my application, and added a PUT route as follows:
resources :triage do
collection do
put :process_multiple
end
end
Instead of the expected process_multiple_triage_path route, it seems it is processed as process_multiple_triage_index_path:
process_multiple_triage_index_path PUT /triage/process_multiple(.:format) triage#process_multiple
triage_index_path GET /triage(.:format) triage#index
POST /triage(.:format) triage#create
Answer: Turns out it is because triage is seen as a singular resource by Rails, thus by way of convention, you'd request the "index" of the resource.
This was because of the singular form of triage. Rails noticed that triage was used, instead of triages, and thus as a result of convention, the request would be of the index. I've linked below another StackOverflow that explains this well.
You can use resource :triage instead of resources (which also won't create an index route automatically either)
More info here
It's on the collecion, so Rails appends an _index. If you want to overwrite it, just change to:
resources :triage do
collection do
put :process_multiple, as: :proccess_multiple_triage
end
end
And now you'll be able to use process_multiple_triage_path

What is the logic behind Rails' default restful resource code?

I'm Learning Rails. Lots of the conventions make great sense. The convention for code that maps to controller actions is odd:
//code url controller action
tweets_path /tweets/ def index
tweet /tweet/ID def show
new_tweet_path /tweets/new def new
edit_tweet_path(tweet) /tweets/ID/edit def edit
Why aren't the automatically generated method helpers done in the same symmetrical way as the controller actions? eg:
//code
tweet_index
tweet_show(tweet)
tweet_new
tweet_edit(tweet)
I'm so new I'm sure there's a perfectly good reason, I just don't know it yet :)
There are two asymmetries here.
The first is plural vs. singular route helpers. Why are some helpers tweets_* helpers while others are tweet_* helpers?
The answer is that some resource routes are member routes and others are collection routes. Member routes have to do with an instance of a resource and collection routes have to do with all instances of a resource as a group (unless the resource is singular in which case there are no collection routes). The index action is a collection route and the show action is a member route.
You can declare your own member and collection routes like this:
# routes.rb
resources :tweets do
member do
get :duplicate
end
collection do
get :summarize
end
end
This will create two helpers in addition to the standard ones. Note that Rails will create route helpers that are appropriately singular or plural.
a summarize_tweets_path helper that does not take a parameter
a duplicate_tweet_path helper that does
Official docs are here.
The second asymmetry is that the action is left out of the helper for many of the built-in resource actions. I suppose this could have been for brevity, but I don't really know.
Edit
After thinking about it, the action name was dropped because there is path overloading in Rails and REST. The '/tweet/:id' path could be the show, update, or delete action depending on the HTTP verb. Basically, the path tells you what you are operating on but not what action to take.
The helper methods are generated in a way that makes them more readable by making them more like parts of sentences. Saying 'Create a link to a new tweet' sounds better than 'Create a link to a tweet new'. It helps to keep this in mind as well when naming any custom actions, using names that fit sentences makes it easier to comprehend and remember since this is how we learn to speak.
One reason for it not being symmetrical is that the mappings depends on the HTTP action. For example, a GET to /tweets map to the index action, but a POST to /tweets maps to the create action.

rails_3_question :as => why is my /posts/new routing to posts/show after setting up a slug

I'm using Rails 3 and after setting up slugs, I found that posts/new no longer works.
posts/:id, posts/:id/edit and all the other CRUD operations work.
However /posts/new gives me a routing error
No route matches {:action=>"show", :controller=>"posts"}
Now for some reason posts/new is routing to posts#show. In my routes, its just
resources :posts
My theory is that since /posts/:slug now matches against things other than numbers ids, the show verb is being routed to first. However it doesn't make sense since posts/grr a nonexistent entry gives a different error than posts/new and posts/first comes out just fine with all its associated paths working fine as well.
Anyone know what might be going on?
I've uploaded the repo to https://github.com/cultofmetatron/cassowary/tree/photogallary
I know my code sucks, I'm still learning the ins and outs of the system and I'd appreciate any insight into whats going on.
In your comment the first part seems fine: add a column to the Post column called slug and so on, and the contents of that will become some or all of the URL used to display a specific post. (I'll assume the other CRUD operations should work as normal)
To find the URL, the router has to know how to know which controller and action will handle this URL (as compared to others). A normal resources :posts route will match all of the RESTful methods, e.g. mapping a GET request onto a path starting with the controller name, and if an id is specified (/posts/1) map to the posts#show controller method, if not, it will map to posts#index method. If the request is a PUT, or DELETE or POST, different actions around a standardized URL format will occur.
Two changes are needed:
URL with the post slug format needs to map to the posts#show method (which is modified accordingly), and
Any links to the show page that are generated on your site need to use the post slug instead of the id
I'll assume you're OK with URLs start with /posts (if not, you'll need to identify some other unique pattern).
The first change requires that you override the specific case of the show method using route globbing, my adding something like match 'posts/*slug before the standard resource route. Here's a link to the guide on route globbing: http://guides.rubyonrails.org/routing.html#route-globbing
The next change, modify the existing posts#show method so that it looks for slug instead of id, e.g.
def show
#post = Post.where("slug = ?", params[:slug])
...
end
Finally, change the way Rails handles the URL helper posts_path. Do this by overriding to_param in your Post model, e.g.
def to_param
"/posts/#{slug}"
end
And then you're done. Maybe.
After that, see how the friendly_id gem does the same thing :-) https://github.com/norman/friendly_id

Resources