how to using twice id inside route in rails - ruby-on-rails

i have routes like this :
get "/:article_id" => "categories#show", as: :articles_category
get '/:account_id' => "accounts#show", as: :show_account
but why when i access show_account_url, i always entry to articles_category_url ??
why?
how to make my routes have twice "/:id" in url with different action?

But why when i access show_account_url, i always entry to
articles_category_url ??
The problem you have is you're trying to access the same URL -- domain.com/______. Because Rails cannot process the difference, it uses the first route - your category_url.
There are two ways to deal with this:
Have a "Routing" controller / use slugs
Split your routes up conventionally
Everyone wants app-wide slugs, but you can't do it unless you have a mechanism to calculate which URL is correct. The methods you have to achieve this are either to create a routing controller, or use slugs.
Using a routing controller is actually quite simple:
#config/routes.rb
get "/:id" => "router#direct", as: :slug
#app/controllers/routers_controller.rb
def direct
#routing code (lots of ifs etc)
end
A better way is to use a slug system, which allows you to route to your slugs directly. We use this with http://firststopcosmeticshop.co.uk & the slugalicious gem:
#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 allows you to send specific slugs to specific controllers / actions. The reason? It creates /[slug] routes, which you can access across the site
Further to this, you could look at the friendly_id gem -- which helps you create resourceful routes using slugs. Highly recommended

Related

Rails routes, constraints and variable scope

I have the following wildcard routes & constraints setup ...
get '*path' => 'profiles#show', constraints: SlugConstraint.new
get '*path' => 'blogs#show', constraints: SlugConstraint.new
and
class SlugConstraint
def initialize
#slugs = Slug.all.map(&:name)
end
def matches?(request)
request.url =~ /\/(.+)/
#slugs.include?($1)
end
end
... a variation based on the issue I described here:
Rails wildcard route with database lookup & multiple controllers
My issue now is that if the first call to SlugConstraint.new returns false (so that the 2nd routes.rb SlugConstraint.new now gets called) I don't want to have to redo the call to:
Slug.all.map(&:name)
How do I properly save (or scope) the #slugs data from the first constraint call that failed, so that I can access it if needed in the next constraint call?
Thanks.
Routing
You're not going to be able to use 2 routing patterns for the same path
When you send a request to Rails (or any other MVC application), Rails will take the path you've sent & consequently try to assign the right route (controller#action) for it.
This happens sequentially - IE Rails will look through your routes from top -> bottom until it finds one which corresponds. As you have two routes to match the same path, you're not going to be able to use the set up you have
--
App-Wide Slugs
What you're looking for is something called app-wide slugs - which essentially means you're able to manage a single slug path, and have a system in the back-end to accommodate it.
You're on the brink of being able to achieve this, and whilst I don't have any code to help, I do have an idea, which I found here:
#config/routes.rb
get '*path' => MyRouter.new, constraints: SlugConstraint.new
#lib/my_router.rb
class MyRouter
def call(env)
# Matched from routes, you can access all matched parameters
view_name= env['action_dispatch.request.path_parameters'][:view_name]
# Compute these the way you like, possibly using view_name
controller= 'post'
my_action= 'show'
controller_class= (controller + '_controller').camelize.constantize
controller_class.action(my_action.to_sym).call(env)
end
end
This will allow you to pick up the slugged paths, whilst routing to the correct controller. This is TOTALLY untested & just a stab in the dark - if you want to go over it with me, comment & we can have a look

change routing name dynamically

I have to modify the routes file in order to have SEO improvement.
This is my context, a rails backend generate a JSON feed with the route's name in, I have to read it and change the default name.
For example, I have this:
get '/people' => 'people#show', as: :people
and I'd like to change /people in some value read from my JSON feed.
I created a class to get the JSON object in my app
class JSONDatabase
def initialize(kind_of_site)
#kind_of_site = kind_of_site
end
def fetch_database_remote(url)
JSON.parse(open(url).read)
end
end
but how can i access it in routes file?
Thank you
You don't necessarily need to modify your application's routes. What you can do is define a wild card route that leads to a unique controller where you read the updated route. This approach is kind of hackish but gives you the unlimited routes you need without modifying the routes.
Your config/routes.rb file would look something like this:
resources :defined_models
root to: 'controller#action'
# At last we define the wildcard route
get '/:route' => 'routing_controller#routing_action'
Then, at this routing action we can do the job of seeing if this route (now defined in the params[:route] variable) corresponds to the modified one. Just remember to redirect to a 404 if the route given is not defined, since with this approach you loose the Rails default way of dealing with undefined routes.

Confused about routes setup -- Rails 3.1

I think I'm running across a conflict due to names:
Two models: store coupon
Url needed that will display coupons: http://localhost/coupons/:store_name ('coupons' is written in the url, not replaced with anything)
Controller name: coupons_controller
Here is what I have in my routes right now:
match '/coupons/:store_name' => 'coupons#index', :as => :stores
When I try to do redirect stores_path(store) in another controller, I get this error:
No route matches {:controller=>"coupons"}
Any clues? I'm new to rails so I bet it's a silly mistake.
UPDATE
Is there a central place to tell the dynamic _path() functions to use a specific url structure? i.e. Instead of having to do the following everywhere:
redirect_to stores_path(:store_name => store.store_name)
Instead using just:
redirect_to stores_path(store)
yes you can, redefine to_param in your model:
class Store < ...
def to_param
store_name
end
end
redirect_to stores_path(:store_name => store)
should work if it doesn't (cannot confirm right now), you should be able to do the (little hacky)
redirect_to stores_path+"?store_name=yourstorename"
Doing it the restful way, you should probably have something like this (in your routes):
resources :stores do
resources :coupons # this will give you e.g. /stores/:store_id/coupons for the coupons#index action
end
If you want to use the store name instead of the ID, just search SO for using "slug" or have a look here: getting a 'name' based URL in RESTful routes instead of an id based url or ID + Slug name in URL in Rails (like in StackOverflow)

How can I bind a Rails 3 route parameter to a nested value in the params hash?

I would like to have a route like this
get "users/sms_confirmation/:sms_confirmation_code" => "users#sms_confirmation"
bind the :sms_confirmation_code param like the following example:
A request to users/sms_confirmation/ABC123 results in the params hash containing
{:user => {:sms_confirmation_code => "ABC123"}} # This is what I want
Currently the route gives me:
{:sms_confirmation_code => "ABC123"} # This is what I've got.
As of yet I cannot find a way to do this with Rails 3 routing. Is there a way to accomplish this?
Working around this problem is easy, but I don't want to do it if it's unnecessary.
UPDATE: sms_confirmation_code is a fields in the users table. My goal is to use pretty URLs such as the one in the example above rather than a query string appended to the URL. I also want to avoid extra code in the controller to structure a hash like described above.
sms_confirmation is nested under users right?
shouldn't it be something likeusers/123/sms_confirmation/ABC123 ?
resources :users do
  resources :sms_confirmation do
    get "users/:user_id/sms_confirmation/:sms_confirmation_code" => "users#sms_confirmation"
  end
end
if you don't have a users controller you could use a namespace such as
namespace "users" do
resources :sms_confirmation do
get "sms_confirmation" => "users#sms_confirmation"
end
end
Tell me if it worked!

Get resource name from URL when using a custom controller in Rails

I have a set of routes that are generated dynamically at runtime, but that all point to the same controller i.e.
map.resources :authors, :controller => 'main'
map.resources :books, :controller => 'main'
These all work fine, producing routes like /authors/1, /books, /books/55, etc and then all end up being processed by the 'main' controller.
However, I can't seem to find how to get the name of the resource in the controller i.e. in the index action when the URL is /authors or /books I'd like to be able to determine which resource it is, i.e. Author or Book
I cannot use separate controllers for this.
Is this at all possible ?
EDIT: complete change of answer because it was waaay off.
So because it changes the params that you see in your action you'll have to get at the actual uri. It is really just as simple as what Terry suggested.
def index
if request.request_uri =~ /books/
#...
else
# if it is a author
end
end
This compares the request uri (the part that would be after localhost:3000) to books and so you can see what the user has requested.
I don't think there's anything like a .resource method, but you could look at request.request_uri, which in your case would return things like /authors or /books, and could act accordingly.
See the "Defaults routes and default parameters" section of the ActionController::Routing documentation. You can program into your routes arbitrary extra parameters you would like sent to your controller.
Looking at the request URI will force you to keep routes and controllers in sync, which will make your code more fragile and less easily re-used. Avoid if you possibly can.

Resources