Bound Parameters in Ruby on Rails - ruby-on-rails

I’ve previously asked a question related to this topic as well and with the aid of that question I’ve found the name of exactly what I wanted: “bound parameters”.
I have managed to create a routing like "user/:id/dosomething" by adding a member to the routes.rb. However, this type of URL is not the solution I was looking for.
My question is, how do you provide the 'user/dosomething/:id' to match with action user's dosomething action with id sent as parameter?
Here is the section I’ve read in order to get the idea:
3.1 Bound Parameters
When you set up a regular route, you supply a series of symbols that
Rails maps to parts of an incoming HTTP request. Two of these symbols
are special: :controller maps to the name of a controller in your
application, and :action maps to the name of an action within that
controller. For example, consider this route:
get ':controller(/:action(/:id))'
If an incoming request of /photos/show/1 is processed by this route
(because it hasn’t matched any previous route in the file), then the
result will be to invoke the show action of the PhotosController, and
to make the final parameter "1" available as params[:id]. This route
will also route the incoming request of /photos to
PhotosController#index, since :action and :id are optional
parameters, denoted by parentheses.

You can add a custom route:
get 'user/doesomething/:id' => 'users#do_something', :as => 'do_something_user'
This will route HTTP GET requests that match the URL user/dosomething/:id to the UsersController's do_something action. The :as => 'do_something_user' part names the route, so that you can use do_something_user_path and do_something_user_url helpers to generate the URLs.
For more information on routing, see Rails Routing from the Outside In.

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

Form_tag 'create' vs '/create'

I'm exploring all options for form_tag and I noticed that if I use form_tag(action:'create') it would do post 'create'.
However, if I use form_tag('/create') or form_tag('create') I get this error in browser\
No route matches [POST] "/create"
I merely extrapolate from the example given in the Rails documentation on form_tag to use '/create' (http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-form_tag).
Does anyone know why I'm getting this error?
form_tag needs whatever is necessary to find a path for sending data.
action: 'create', which is resolved to {action: 'create'}, a Hash, invokes a routing system (with rules defined in routes.rb) to find a route in the same controller (the current view is in) for create action.
Otherwise, it's more commonly used with path helpers, returning paths as strings. When you specify a string manually, it's used as a path directly. Most of the time this is not what you want. All path helpers can be found by invoking rake routes. For a bare-bones app I threw together for a test this is what I get:
Prefix Verb URI Pattern Controller#Action
root GET / application#index
This means that you have methods root_path and root_url (Prefix hints) that routes path '/' into ApplicationController, action index. If I had something accepting a POST on the same path (the table above says I don't), I would have written this:
form_tag(root_path) # parentheses are optional, it's Ruby!
PS: routing anything to ApplicationController is bad practice. So yes, it's an impractical example, which nevertheless explains what's this all about.

Custom route mistaken for object id in Rails

I have the following route:
view_all_styles /styles/view_all(.:format) styles#view_all
When I point my broswer at xyz.com/styles/view_all I receive the error:
ActiveRecord::RecordNotFound at /styles/view_all
Couldn't find Style with id=view_all
I'm also routed to the show action??
Request parameters
{"action"=>"show", "controller"=>"styles", "id"=>"view_all"}
It sounds like you've got your routes defined in the wrong order - you'll want to define your custom route before the resource routes of styles. Otherwise, you'll run into exactly this problem.
Since your route, /styles/view_all also fits into the route for #show, /styles/:id ('view_all' being the :id), it will match and pass along the request to #show before it even tries to match your custom route.

Routing without the model name

Using this question and railscast 63 I've got my articles routed to articles/article_permalink.
I'd like them to be accessible without the model name in the url so my-domain.com/article_permalink routes directly to the article. I'd only want this to happen on the show action. Is this possible?
I think you need something like ...
(in routes.rb)
match '/:id' => 'articles#show', :via => 'get'
(needs to be last, or towards the end of the routes as it can match requests intended for other routes)
To change the article_path(...) helpers, "as" might help: http://guides.rubyonrails.org/routing.html#overriding-the-named-helpers
Or you can add a helper for that specific path.
If I understand your question, you want the model tied to the route "articles/article_permalink" to be dynamic based upon which is article is selected from a list?
Would you be open to appending a model ID to the end of the URL as a query string? A more complicated approach would be to have your links POST, with the model ID as a hidden input field. Your controller could determine if it was accessed via get/post, and handle it accordingly, but that doesn't feel right.
Regardless, when the controller action is fired up based upon a request to "articles/article_permalink", it has to know which model to fetch. With HTTP being stateless, something has to be passed in. You could get fancy and write JavaScript to fire one AJAX call, set a session var, and then fire the GET, but that's messy.
I hope I understood the question...

How to create custom routes for certain actions in a CakePHP controller?

Coming from Django, I'm used to be able to organize my URL routings any way I see fit. For example, user registration would exist under the /users/ url.
/users/
/users/registration/
/users/registration/optin/
/users/registration/thankyou/
However, I'm creating a user registration system in CakePHP and the default convention behaviour for url routings is /controller/action/. This yields:
/users/
/users/registration/
/users/optin/
/users/thankyou/
How can I achieve a /controller/action/custom/ style-url routing on some of my actions (where /custom/ is a sub-section, not a parameter)? Should I even be expecting to do this or am I just fighting the convention?
/controller/action/custom/ works fine by default.
It invokes ControllerController::action('custom').
If you're looking for something like invoking UsersController::thankyou() through the URL /users/registration/thankyou, you can make an appropriate route:
Router::connect('/users/registration/thankyou',
array('controller' => 'users', 'action' => 'thankyou'));
You can group routes in one rule like this:
// Routes /users/registration/optin and /users/registration/thankyou to
// UsersController::optin() and UsersController::thankyou() respectively
Router::connect('/users/registration/:action',
array('controller' => 'users'),
array('action' => '(optin|thankyou)'));
Routes are very powerful and completely flexible in Cake. As always, study the manual:
http://book.cakephp.org/view/945/Routes-Configuration
The basics are that the Router matches the route, e.g. '/users/registration/:action', against the current URL, including conditions specified in the third parameter, e.g. 'action' => '(optin|thankyou)' (the :action part has to match the RegEx /^(optin|thankyou)$/).
If it matches, it merges the defaults from the second parameter with any information extracted from the URL, so you get array('controller' => 'users', 'action' => 'thankyou') for example.
It then pushes it through CakeRoute::parse, which constructs the array you can see when doing debug($this->params) in a controller. This array is used to figure out which Controller to load and which action to invoke.
The basic RegEx and parameter matching is already very powerful, but you can go completely crazy by subclassing CakeRoute and providing a custom parse function, as briefly explained at the end of the manual. :)

Resources