Conflict routes and params name in Ruby on Rails - ruby-on-rails

In my website, users can visit category via example.com/category1, example.com/category2, etc. So I write the route rule as below:
match '/:category' => 'home#category', :constraints => ShowCategory.new
ShowCategory is a Class that make sure the category user visited is exist. At the same time, users can specify their personal domain name, then his/her profile page can be visited via url like example.com/peter. So There is another route rule:
match '/:user_domain' => 'Profiles#show'
Because I use the :constraints for category route, the routes didn't conflict. However, in the Profiles#show action I always get the parameters {'category' => 'peter'}, not {'user_domain' => 'peter'}.
How can I correct the parameter name? I don't want a parameter named category in the profiles controller.
Thanks.

Well, the way you're naming your routes doesn't make much sense; it's making the routing engine confused. It should be categories/1 rather than category1.
As for the profiles, I guess the first rule and the to_param method should be enough.
# routes.rb
profile '/:user_domain', controller: 'profiles', action: 'show'
resources :profiles
resources :categories
# profile.rb
def to_param
self.user_domain
end

Related

Rails wildcard route with database lookup & multiple controllers

I have a Rails application setup where, after all of the other site routes are defined, I have a catch-all wildcard for my Users to display their Profiles on selected root-level "vanity" URLs of non-reserved paths/keywords:
get '*path' => 'profiles#show'
The Profiles controller then checks to make sure the path defines a valid Profile, otherwise redirects to root. This works fine.
What I need to do now is create a mechanism where the catch-all path could define either a Profile or a Blog, based on the database lookup of the path for the proper controller to route to.
I do not want to do a redirect ... I want to load either the Profile or Blog content on the original wildcard URL.
What are my options to go from wildcard route -> db lookup -> proper controller?
In other words, where might this logic properly go?
Thanks.
It seem like you want a route constraint that will match some pattern (regex) that defines if a path matches a route or if it tries the subsequent routes. Maybe something like this.
get '*path', :to => 'profiles#show', :constraints => { path: /blog\/.+/ }
The idea is that you must know something at the routing level, if it can be path based then the above thing will work otherwise if it needs to be more complex you can use a custom constraints class.
# lib/blog_constraint.rb
class BlogConstraint
def initialize
#slugs = Blog.pluck(:slug)
end
def matches?(request)
request.url =~ /blog\/(.+)/
#slugs.include?($1)
end
end
# config/routes.rb
YourApp::Application.routes.draw do
get '*path', :to => 'blogs#show', :constraints => BlogConstraint.new
get '*path', :to => 'profiles#show'
end

Dynamic named routes in Rails

I have a simple problem where in a routes/url name is determined by a user role. Currently the route displayed is /new_admin/dispensaries. If the user has a role of either manager or executive then the named route should be '/dashboards/dispensaries'.
It's kind of simple but the hard part is that in my routes.rb:
namespace :new_admin do
resources :vendor_templates
resources :markdown_docs
resources :email_lists
namespace :moderation do
resources :reported_reviews
end
resources :users do
member do
get :user_bans
post :ban_unban, to: 'user_bans#create'
delete :ban_unban, to: 'user_bans#destroy'
end
end
# TODO - this should be written generically to support dispensary/doctors/whatever
get '/dispensaries/reviews', :to => "reviews#all", :as => :all_reviews
get '/dispensaries/pictures', :to => "pictures#all", :as => :all_pictures
get '/dispensaries/videos', :to => "videos#all", :as => :all_videos
get "/dispensaries/autocomplete", to: "dispensaries#autocomplete"
resources :vendors do
resources :ownership_transfers, only: [:new, :create]
end
...
I'm kind of stuck since if I change the new_admin routes, so many other routes will be affected. Any idea guys?
We've actually done something like this. It's not pretty, but this solution worked for us:
Slugs
You're basically alluding to a type of your routes called Slugs. This is where you use a name instead of an ID, allowing you to make a user-friendly route (such as /delivery/today). The problem is that in order to create these routes, you have to define them individually in the routes file
There are two Gems you can use to handle your slugged routes -- FriendlyID & Slugalicious. Both of these allow you to create slugged routes, but FriendlyID basically just changes the ID, whilst Slugalicious is a totally independent system
We used Slugalicious for the code below, however, you'll probably want FriendlyID (there's a RailsCast for it here):
Routing
The problem you have is that routes are outside the scope of the RESTful controller interface, which means you'll have to call all the routes exclusive of your resources references in the routes.rb file
If you use Slugalicious, it has its own Slugs database, which means we can use it to create the routes on the fly, like this:
#Slugs
begin
Slug.all.each do |s|
begin
get "#{s.slug}" => "#{s.sluggable_type.downcase.pluralize}#show", :id => s.slug
rescue
end
end
rescue
end
This is live code, and outputs all the slugs in the routes file dynamically. The way we managed to get this to update programmatically was to use an Observer Class like this:
class SlugObserver < ActiveRecord::Observer
def after_save(slug)
Rails.application.reload_routes!
end
def after_destroy(slug)
Rails.application.reload_routes!
end
end
I appreciate you may have your answer already, but as you're a beginner, I felt I could help out by explaining the slug stuff for you

Rails routing confusion due to :id

I am using devise for authentication. When signing up users create a profile name that I would like to use as their profile route. So, it might look like this: www.myapp.com/profile-name. The problem I'm running into is with the routes not going to the right place.
routes.rb
resources :majors do
resources :reviews
end
devise_for :users
...
match '/:id' => 'users#show', as: :user_profile
I've placed the :user_profile route at the bottom of my routes file. Part of my rake routes looks like this:
major GET /majors/:id(.:format) majors#show
user_profile GET /:id(.:format) users#show
On the profile page (myapp.com/my-custom-profile-name) there are no problems. But on the majors show page I use the user_profile_path to link to a user's profile and the url is www.myapp.com/:id - with the :id being the major :id. So, the :id of the major is getting mixed in with the user_profile :id.
My users controller looks like this:
def show
#user = User.find_by_profile_name(params[:id])
#reviews = #user.reviews
end
I have changed the url around, tested it on different areas, changed the order of my routes file, searched and tested this all day long. I cannot figure out what I'm missing. I think it's really simple but it's eluding me. Any ideas?
SOLUTION:
The solution was first get the routes correct. Since I've created a custom, dynamic url (myapp.com/user-profile-name) I needed to call the id in the route:
get '/:id' => 'users#show', as: :id
That changed my routes to look like this:
id GET /:id(.:format) users#show
Users share reviews and their name is posted next to their review. I was having trouble linking to their profile from their name on their review. I was able to do that on the view like this:
<%= link_to review.user.profile_name, id_path(review.user.profile_name) %>
To get to a specific user profile, you need to pass the user profile ID into the user_profile named route:
user_profile_path(#user)

setting up named routes for resouce routes in rails

I have what I think should be a simple task - but it's causing me a real headache.
I've added a resource route to my app using -
resources :cars
I want the user to be able to edit a car by going to
mydomain.com/CARNAME
In the edit action of the controller -
#donor = Donor.find_by_name(params[:car])
This page shows by setting up a named route -
match "/:car" =>"cars#edit", :as => :car
However when I try and submit the form on that page I get an error?
How can I set up the show action to have a named route to correspond with the edit route?
My desired show url would be something like
mydomain.com/CARNAME/savecomplete
In routes.rb
match "/:car" =>"cars#edit", :as => :edit_car
match "/:car/savecomplete" =>"cars#show", :as => :savecomplete
In cars_controller.rb update action
format.html { redirect_to(savecomplete_path(#car) }

How to change URL in Rails

I have a resource called Book, then I have domains like:
domain.com/books/272
But I want to change it to
domain.com/stories/272
Only for the URL, don't need to change controller, classes etc.
In the routes I have
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
map.root :controller => 'static'
How can I do it? Thanks
In rails 3, I believe you would do the following:
resources :books, :path => 'stories'
Depends really on what you have already.
Use this code to your routes file: (in the case of the original URL of books replaced by stories)
#resource routes
map.resources :books, :as => :stories
#named routes
map.books 'stories/:id'
Without defining routes the only option I can think of - which seems terribly wrong - is to add a new controller which inherits from your books controller. You'd need to go through your application and change the controller name used to generate paths or URLs as seen in the following example:
class BooksController < ApplicationController
class StoriesController < BooksController
Personally, I would recommend you take the time to define your routes but I guess this depends on how large an application you're working with.
This guide will help you understand routing in RoR: http://guides.rubyonrails.org/routing.html
Its called named routes and is done in your config/routes.rb
In your routes file:
map.stories 'stories/:id', :controller => 'books', :action => 'show'
Then in your view you can access this route with:
<%= link_to book.name, stories_path(book) %>
Make sure you change book.name to whatever name you want. also make sure you passing book as a local variable to the routes path.
You can also change the :id to be more SEO friendly with to_param in the respective model.
In your model:
def to_param
"#{id}-#{name.gsub(/\s/, '_').gsub(/[^\w-]/, '').downcase}"
end
Also make sure you replace name with an attribute that the book model actually has.

Resources