rails routes access by resource name using friendly_id gem - ruby-on-rails

I have a list of cities stored in City table. Let's say I want to generate dynamic routes to be accessible through resource.name, city.name in this example.
I want to be able to visit /amsterdam or /berlin. How?
For info I'm using friendly_id gem so already have slug column if that makes more sense.

Assuming you have friendly_id set up correctly:
match '/cities/:name' => 'cities#show'
or
resources :cities
From the Quick Start for the friendly_id gem:
class City < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
end
Also:
# If you're adding FriendlyId to an existing app and need
# to generate slugs for an existing model, do this from the
# console, runner, or add a Rake task:
City.find_each(&:save)
Here is a RailsCast on it: http://railscasts.com/episodes/314-pretty-urls-with-friendlyid?view=asciicast

At the end of your routes file, add this:
match '*id' => 'cities#show
Then in your CitiesController:
def show
#city = City.find(params[:id])
# ...
end

Don't know if this helps .. but I have put together a gist on what I use in my projects.
https://gist.github.com/1908782
It mostly works for what I do as my routes file is generally quite concise.
The beauty of it is, that if you attempt to visit a path that doesn't exist, it won't hit any routes!
Just a side note, this is broken in the 4.0 release. At the time of writing this, you will need to put the following in your gemfile.
gem 'friendly_id', :git => 'git://github.com/norman/friendly_id.git'
or
gem 'friendly_id', :git => 'https://github.com/norman/friendly_id.git'
Hope this helps.

Related

Display user#show url as www.fb.com/usrname and www.usrname.fb.com instead of showing www.fb.com/123, in rails 4.2.6

I am trying to show username instead of user_id i.e., (users/4).
i have tried with changing routes file, model file as:
class User < ActiveRecord::Base
def to_param
username
end
end
and routes file as:
get '/:username' => 'users#show'
on show action it must show as fb.com/username url.
thanks in advance.
You may use friendly_id gem for this. Here is Rails cast : Pretty URLs with friendly_id On how to use it. You can use the attribute/column you want in the URL.
With FriendlyId, it's easy to make your application use URLs like:
http://example.com/states/washington
instead of:
http://example.com/states/4323454

Generate slug when using ancestry gem

I'd like to create a slug based on the ancestors of the record. If I already have a slug created. The best solution I have come up with is:
def pretty_url
path.select(:slug).map(&:slug).join("-")
end
Is there a more precise way to do this using the ancestry gem?
Also, I am using friendly id to generate the slug, so maybe there is a better way using friendly id?
This is what I figured out, using friendly id and ancestry gem together.
friendly_id :slug_candidates, use: :slugged
def slug_candidates
[
[parent.try(:slug), :title]
]
end

friendly_id and routes.rb - rails

I'm currently using friendly_id gem in rails and noticed that if someone names a post "About" that it overwrites the /about path that I have assigned to a static page in my routes.rb file.
This is my current code:
extend FriendlyId
friendly_id :title, use: :history
If there are prior posts with the same name...it adds a --2. But friendly_id seems to ignore static routes in my routes.rb.
Is there a way to make friendly_id recognize and not overwrite these routes?
Thank you
FriendlyID includes a Reserved module which prevents a list of provided words from being used as friendly slugs. You could add your static routes to the reserved words array which would prevent someone from overwriting your routes.
From the FriendlyId RDocs
FriendlyId.defaults do |config|
config.use :reserved
# Reserve words for English and Spanish URLs
config.reserved_words = %w(new edit nueva nuevo editar)
end
If you still want to allow for a title that is reserved you can make a new method that FriendlyId would use for the slug. This piece from the RDocs explains that
Column or Method?
FriendlyId always uses a method as the basis of the slug text - not a column. It first glance, this may sound confusing, but remember that Active Record provides methods for each column in a model's associated table, and that's what FriendlyId uses.
Here's an example of a class that uses a custom method to generate the slug:
class Person < ActiveRecord::Base
friendly_id :name_and_location
def name_and_location
"#{name} from #{location}"
end
end
bob = Person.create! :name => "Bob Smith", :location => "New York City"
bob.friendly_id #=> "bob-smith-from-new-york-city"
You could create a method like :title_with_id or :title_with_rand. it's up to you and how you'd like the slugs to look.
You would also want to make sure your routes.rb has your static routes listed prior to the routes for with the friendly id. The first route dispatcher matches is where the request will be processed.

modify friendly_id gem

I want to be able in browsing bar see full path to some product. The path would look like this
www.mysite.com/categories/category_name/subcategory_name/product_name
At this moment I have just
www.mysite.com/categories/category_name
It just provides with one level path, that I don't need.
To build these friendly links I used friendly_id. And full categorization function I created using gem called Ancestry.
How can I modify friendly_id slug so that I can show the full path? I know how the friendly_id works, but I don't know how to change the way how slug is generated.
Some guys could just give me link or tip to search for. I can work it out, I just need idea.
I would be very greatfull :) :)
You can pass a method for the gem to use, as in:
extend FriendlyId
friendly_id :method_name, use: :slugged
def method_name
end
You're probably looking for nested resouces.
If both models (category, subcategory) have slugs, nesting them in your routes.rb file should do the trick:
resources :categories do
resources :subcategories
end

Custom parameter name in RESTful routing, Rails 3 [duplicate]

I looked around on how to change the dynamic params slot and found this post that does the exact thing.
The post is https://thoughtbot.com/blog/rails-patch-change-the-name-of-the-id-parameter-in
Basically what it does is, if following is the routes:
map.resources :clients, :key => :client_name do |client|
client.resources :sites, :key => :name do |site|
site.resources :articles, :key => :title
end
end
These routes create the following paths:
/clients/:client_name
/clients/:client_name/sites/:name
/clients/:client_name/sites/:site_name/articles/:title
One solution is to override the def to_param method in the model, but I want this without touching the model itself.
But since its for Rails 2.x, how can I achieve the same for Rails 3?
Update
This app is using Mongoid. Not AR.
So, the gem friendly cannot be used afaik.
Rails 4 & 5
In Rails 4, the :param option was added, which seems to do exactly what you're looking for. You can take a look at the Rails 3 code compared to the Rails 4 code.
Details
You can easily implement this in your routes.rb file:
# config/routes.rb
resources :posts, param: :slug
# app/controllers/posts_controller.rb
# ...
#post = Post.find_by(slug: params[:slug])
# ...
As of the release of Rails 4, this functionality is documented in the Rails Guides.
Rails 3
Unfortunately, in Rails 3, the :key option for resources was removed, so you can no longer easily change the name for routes created in this way by just passing in an extra option.
Details
I assume you've already somehow gotten the application working the way you want in the past year, but I will go into a way to get the effect you describe in Rails 3 in routes.rb. It will just involve a bit more work than the to_param method. You can still define custom parameters in routes defined using scope and match (or it's cousins get, put, post, and delete). You simply write in the parameter name you want in the matcher:
get 'clients/:client_name', :to => 'clients#show', :as => client
scope 'clients/:client_name' do
get 'sites/:name', :to => 'sites#show', :as => site
end
You would have to manually add all the routes that resources automatically creates for you, but it would achieve what you're looking for. You could also effectively use the :controller option with scope and additional scope blocks to take out some of the repetition.
EDIT (May 8, 2014): Make it more obvious the answer contains information for both Rails 3 & 4. Update the links to the code to go to exact line numbers and commits so that they should work for a longer period of time.
EDIT (Nov 16, 2014): Rails 4 should be at the top now and include relevant information as it's been the current version of Rails for quite some time now.
EDIT (Aug 9, 2016): Reflect that the solution still works in Rails 5, and update outdated links.
in Rails 4, pass param option to change the :id params. For example
resources :photos, param: :photo_name will generate /photos/:photo_name
In Rails 3 you can rename the id keys by using a combination of namespaces and scopes like this (not very nice though):
namespace :clients do
scope "/:client_name" do
namespace :sites do
scope "/:name" do
post "/:title" => "articles#create"
...
end
end
end
end
If I understand you correctly, what you want is to have the client_name instead of id in your url, right?
You can do that by overriding the to_param method in your model. You can get more information here.
There's a gem for that, just like there's a gem for everything ;)
I've been using FriendlyId for this kind of behaviour in rails 3.
It will require you to add some code to your model though, like this:
class Client < ActiveRecord::Base
has_friendly_id :name
end
...and if your clients don't have URI compatible names, you might want to use a slug for that, which you can do with has_friendly_id :name, :use_slug => true. When using slugs you'll obviously need to persist them to the database as well though.
And as already mentioned, you can still use the to_param trick with rails 3, as documented here. I find FriendlyId a bit more versatile though.

Resources