Rails Route "as" - ruby-on-rails

I have this code snippet it has 3 types of "as"
Can anybody explain about 3 different "as"
as: 'drivers_confirmation'
:as -> 'user_registration'
as :user do
get 'drivers/confirmation' => "root#index", as: 'drivers_confirmation'
namespace :api do
get 'describe/models'
get 'status' => 'status#index'
as :user do
put 'v1/users' => 'v1/registrations#update', :as => 'user_registration'
# post "login" => "v1/sessions#create"
# get "currentUser" => "v1/sessions#current"
end
as :driver do
get "v1/drivers/session" => "v1/drivers/sessions#current"
end
end

as: 'drivers_confirmation' and :as => 'user_registration' are the same.
It's the old and new ruby hash syntax. They are there to be able to use url helpers in your views (drivers_confirmation_path and user_registration_path)
as :user do is probably from Devise, those routes are scoped to specific kinds of users.

Those methods expect a hash to be passed to it in that context. What you're describing are three ways to write a Ruby hash.
The form as: 'drivers_confirmation' is the "newer" and more preferred (from what I've seen) approach to creating hashes, so long as the key you're using can be directly converted to a symbol.
The form :as => 'user_registration' is the older style of writing a hash.
The form as :user is a method which is likely expecting a symbol to be passed to it as opposed to it being any form of hash.

Related

how to make dynamic nested routes on rails?

I'll explain when open www.domain.com/:id should be check the :id is a page then use
get ':id' => 'pages#show'
else if :id is a Category use
get ':category' => 'categories#show'
sorry for my english
get ':page' => 'pages#show'
resources :categories, :path => '/' do
resources :posts, :path => '/'
end
constraints for routes is way to go, but I would suggest a bit different solution for your problem.
Consider creating custom Constraint objects, which will query the database in order to check if Post or Category exists:
app/lib/post_constraint.rb
class PostConstraint
def matches?(request)
Post.exists?(request[:id])
end
end
app/lib/category_constraint.rb
class CategoryConstraint
def matches?(request)
Category.exists?(request[:id])
end
end
In your app/config/routes.rb
get ":id" => "posts#show", constraints: PostConstraint.new
get ":id" => "categories#show", constraints: CategoryConstraint.new
You have to be aware of the fact, that id is very poor candidate for such comparison, because the Post is checked in first place, and if there is record matching, the "posts#show" will be accessed, and CategoryConstraint wot be even bothered.
For more, check the documentation.
You should consider adding a slug for both models to easier serve exactly what user expects to see. For this purpose, try gem friendly_id.
Hope that helps! Good luck!
why dont you write something like this:
routes.rb
get '/:category_id/:post_id', to: 'categories#post'
and in your categories_controller.rb
def post
#params[:category_id] and params[:post_id] will contain the params from the url
end
Couple of solutions
If your post id and category id follow a pattern you can add constraints to your routes
1)
get ':post_id' => 'posts#show', :constraints => { :id => /[A-Z]\d{5}/}
get ':category_id' => 'categories#show', :constraints => { :id => /[1-9]\d{5}/ }
2)
Add a custom method where both post_id/category_id routes point, in that check if the id is a post id or category id and based on that render the page

Why resources on collection has different routing helper then regular post

In my routes.rb I had this resource
resources :home_screen_buttons do
post :update_multiple, :on => :collection
end
update_multiple helper is update_multiple_home_screen_buttons
Then I decided to remove resource because i need only update_multiple method in my controller, so I changed routes.rb to
post "home_screen_buttons/update_multiple"
It create helper home_screen_buttons_update_multiple instead of update_multiple_home_screen_buttons
Why it has different routing helper name?
It makes sense that :on => :collection has different helper then :on => :member, but is there any other way then adding :as => :update_multiple_home_screen_buttons to my post method for same behavior?
This is how Rails does this. When match is used, it maps the URI to the action and creates the corresponding helper path as controller_action_path
but when it is used as collection, that becomes RESTful action for that resource and Rails gives it a logical name relating to a collection. As quoted as an example here:
resources :photos do
collection do
get 'search'
end
end
generates search_photos_path.
You could have done this:
resources :home_screen_buttons, :only => [:update_multiple] do
post :update_multiple, :on => :collection
end

rails routing aliases

I have a model called Spaces which has different types of places... such as Bars, Restaurants, etc. It has the same columns, same, model, controller, etc. no fancy STI, I just have one field called Space_type which I would like to determine an aliased route.
Instead of domain.com/spaces/12345 it would be /bars/12345 or /clubs/12345
Currently I have:
resources :spaces do
collection do
get :update_availables
get :update_search
get :autocomplete
end
member do
post :publish
post :scrape
end
resources :photos do
collection do
put :sort
end
end
resources :reviews
end
Also, Is there a way I can do this so that anytime I use the space_url it can figure out which one to use?
The routes are not a way to interact with your model directly. So, as long as you write a standard route, you can make things work. For instance, to make /bars/12345 and /clubs/12345 for your spaces_controller (or whatever the name of the controller is) , you can create routes like :
scope :path => '/bars', :controller => :spaces do
get '/:id' => :show_bars, :as => 'bar'
end
scope :path => '/clubs', :controller => :spaces do
get '/:id' => :show_clubs, :as => 'clubs'
end
# routes.rb
match "/:space_type/:id", :to => "spaces#show", :as => :space_type
# linking
link_to "My space", space_type_path(#space.space_type, #space.id)
which will generate this urls: /bars/123, /clubs/1 ... any space_type you have
And it looks like STI wold do this job little cleaner ;)
UPD
Also you can add constraints to prevent some collisions:
match "/:space_type/:id", :to => "spaces#show", :as => :space_type, :constraints => { :space_type => /bars|clubs|hotels/ }
And yes - it is good idea to put this rout in the bottom of all other routes
You can also wrap it as a helper (and rewrite your default space_url):
module SpacesHelper
def mod_space_url(space, *attrs)
# I don't know if you need to pluralize your space_type: space.space_type.pluralize
space_type_url(space.space_type, space.id, attrs)
end
end

Rails 3 routing - what's best practice?

I'm trying out Rails, and I've stumbled across an issue with my routing.
I have a controller named "Account" (singular), which should handle various settings for the currently logged in user.
class AccountController < ApplicationController
def index
end
def settings
end
def email_settings
end
end
How would I set-up the routes for this in a proper manner? At the moment I have:
match 'account(/:action)', :to => 'account', :as => 'account'
This however does not automagically produce methods like account_settings_path but only account_path
Is there any better practice of doing this? Remember the Account controller doesn't represent a controller for an ActiveModel.
If this is in fact the best practice, how would I generate links in my views for the actions? url_to :controller => :account, :action => :email_settings ?
Thanks!
To get named URLs to use in your views, you need to specify each route to be named in routes.rb.
match 'account', :to => 'account#index'
match 'account/settings', :to => 'account#settings'
match 'account/email_settings', :to => 'account#email_settings'
Or
scope :account, :path => 'account', :name_prefix => :account do
match '', :to => :index, :as => :index
match 'settings', :to => :settings
match 'email_settings', :to => :email_settings
end
Either works the same, it's just a matter of choice. But I do think the first method is the cleanest even if it isn't as DRY.
You could also define it as a collection on the resource:
resources :login do
collection { get :reminder, :test }
end
Of course, this also defines the default CRUD actions as well. I'm currently only using two of those for my not-an-actual-model controller, but I don't think/expect there will be any problem with the extra routes.

Passing variables to Controller via RESTful routing in Rails

The following question is related to passing a variable from routes to the controller. I have a Ruby on Rails (v 2.3.3) app with one model, which is delivered to the user with multiple views. The current solution involves using multiple controllers which are triggered by multiple routes. For example:
ActionController::Routing::Routes.draw do |map| # defines map
map.resource :simpsons, :only => [] do |b|
b.resources :episodes, :controller => "SimpsonsEpisodes"
end
map.resource :flintstones, :only => [] do |b|
b.resources :episodes, :controller => "FlintstonesEpisodes"
end
However, for the sake of DRYness I would like these routes to operate with the same controller. In order for the controller to distinct between the routes I would like to pass along a variable via the route. For example:
map.resource :simpsons, :only => [] do |b|
b.resources :episodes, :controller => "Episodes", :type => "simpsons"
end
map.resource :flintstones, :only => [] do |b|
b.resources :episodes, :controller => "Episodes", :type => "flintstones"
end
So in the controller I could do this:
case(type)
when "simpsons" then ... do something for the Simpsons ...
when "flintstones" then ... do something for the Simpsons ...
else .... do something for all episodes ....
end
I found a way to do this with non-RESTful routing (map.with_options etc.), but I'd prefer to use RESTful routes with map.resource(s). One ugly solution might be to parse the request URI in the controller, which I'd not prefer.
Since there are no replies and I found a solution, I am going to answer this question myself. If you also have a situation, where you might have a model or a table, which has multiple entries, but for some of them you might need separate views, this might benefit you a bit.
Most likely you would like to have different indexes and for that simply use collection get:
map.resources :episodes, :collection => {:simpsons=> :get, :flintstones=> :get} do |episode|
....and so on
Simply add the methods named "simpsons" and "flintstones" in your controller. And, for the edit, view and delete methods you can use a bit of extra logic, if necessary, by determening the ID of the entry at hand. Something like #episode = Episode.find(params[:id]), if #episode.criteria == ...something... then render this or the other view.

Resources