I'd like to use something like domain.com/users/foo instead of the routes looking like /users/user_id/
Fair enough you could do get "/users/:name/..... but I am using nested resource:
devise_for :users, :controllers => { omniauth_callbacks: 'omniauth_callbacks' }
resources :users do
resource :profile
resources :supports do
post :interest
end
end
Is there a way to change the resource users/user_id to users/firstname?
for this you can use friendly_id gem or you can define to_param method in your user model.
def to_param
"#{name}"
end
Related
I'm looking for some feedback on both the philosophy of good practice and technical practice of using a top level route that routes to multiple Models based on conditions.
I need to have a top level route domain.com/:id that either routes to a: Company or User.
The condition/identifier being that a User has an # in the url, e.g. domain.com/#theminijohn
My routes for the moment look like this:
devise_for :users, path: '',
path_names: {
sign_up: '',
registration: 'signup',
sign_in: 'login',
password: 'password',
confirmation: 'verification'
},
controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations',
omniauth_callbacks: 'users/omniauth_callbacks',
passwords: 'users/passwords'
}
resources :users, path: '', only: [:show] do
member do
get 'reviews', to: 'users#reviews', as: :reviews
get :following, :followers
post :follow, to: 'users#follow_user'
post :unfollow, to: 'users#unfollow_user'
end
end
resources :companies, path: '', only: [:show], as: :company do
resources :products, path: '', only: [:show], as: :product
end
Furthermore the # sign will only be used in the url, aka it is not present in the attribute.
How do I go about this ?
Edit: Here's where I am:
the constraint that gets called from the route for the :users resource
module Constraints
class UserProfile
def matches?(request)
if request.path.include?('#')
slug = request.path.delete('/#')
User.where(slug: slug).exists?
end
end
end
end
and in the controller I patched the find method to:
def set_user
#user = User.includes(:reviews).find(params[:id].delete('#'))
end
How I ended up solving this:
1) Include the # in the friendly_id slug
To do this I had to patch the normalize function which strips it out when calling .parameterize
# overwrite normalize function because it's stripping
# out '#' when calling .parameterize
def normalize_friendly_id(value)
"#" + value.to_s.parameterize
end
2) Regenerate all slugs
There are various methods, I went with deleting the slug and generating it again.
User.each do |u|
u.update_attribute(:slug, nil)
end
User.find_each(&:save)
Have in mind should_generate_new_friendly_id? & if you overwrote it.
3) Routing Constraint
I wrapped my User routes in a constraint:
constraints(Constraints::UserProfile.new) do
resources :users,
....
end
which looks like this:
module Constraints
class UserProfile
def matches?(request)
if request.path.match? /\/#(.*)/
slug = request.path.split('/')[1]
User.where(slug: slug).exists?
end
end
end
end
VoilĂ .
In Ruby on Rails, is there a way to add another RESTful action to the base URL of a plural resource? I'm looking for something like this:
resources :groups do
resources :users do
put on: :base, to: 'users#update_all'
end
end
Which would generate the route: [PUT] groups/:group_id/users => users#update_all
I've already tried doing this:
resources :groups do
resources :users
put 'users', on: :member, to: 'users#update_all'
end
But that doesn't preserve the value of params[:group_id] in the controller.
resources :users do
collection do
put '' => 'users#update_all' ## PUT /users
end
end
UPDATE
It would be recommended to do this though:
resources :users do
collection do
put 'update_all' ## PUT /users/update_all
end
end
Both route to the update_all action of the users controller.
RESOURCES
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
I am trying to get custom routes based on the username rather than the ID. I have it working to get to the show page of the user but I am also trying to nest the resources so that I can see his posts and comments using the same syntax.
Example:
Works... "mysite.com/users/username/"
Does not work... "mysite.com/users/username/posts/"
routes.rb
...
# Users with the Username...
match 'users/:username' => "users#show" do
get :posts
get :comments
end
# Users with the ID...
resources :users do
get :posts
get :comments
end
...
Perhaps you can use the to_param method and update your nested routes/resources:
routes.rb:
resources :users do
resources :posts
resources :comments
end
user.rb
class User < ActiveRecord::Base
def to_param
username
end
end
..for finds in the UserController:
#user = User.find_by_username(params[:id])
(or any variation of finding by the username criteria)
Right now I have an admin.domain.com subdomain for which there is a module scope:
constraints(AdminDomain) do
scope :module => "admin" do
resources :visitors
end
end
This makes all requests on the admin subdomain hit controllers in app/controllers/admin/.
What I'd like to do now is something like:
constraints(AdminDomain) do
scope :module => "admin" do
resources :visitors
scope "history", :as => "history" do
resources :visitors
end
end
end
Where the end goal is to make admin.domain.com/history/visitors hit controller: app/controllers/admin/history/visitors_controller.rb.
This path however still looks for app/controllers/admin/visitors_controller.rb.
Any ideas?
namespace is what I was looking for:
constraints(AdminDomain) do
scope :module => "admin" do
resources :visitors
namespace :history do
resources :visitors
end
end
end
And I had to define Admin::History::VisitorsController in app/controllers/admin/history/visitors_controller.rb
easy way to define specific controller is just like:
:controller => admin/history/visitors
This is an excerpt from my config/routes.rb file:
resources :accounts do |account|
account.resource :profile, :except => [:new, :create, :destroy]
account.resources :posts,
:collection => { :fragment => :get },
:has_many => [:comments, :likes]
# even more code
end
I would like that each nested resource to be loaded from from the account namespace such as Account::PostsController instead of PostsController.
Using resources :accounts, :namespace => 'account' tries to load AccountPostsController.
Trying to nest the structure doesn't really work all that well:
map.namespace :account do |account|
..
end
The previous code will load the files from the locations I want, however it does add the namespace to the url and the generated paths so I'll have methods such as account_account_posts_url and similar paths.
Another alternative is to use something like:
account.resource :profile, :controller => 'account/profile'
I really don't like this as it involves both code duplication and forces me to remove some of the rails magic helpers.
Any thoughts and suggestions?
Changing my routes.rb and running rake routes I came up with the following:
map.resources :accounts do |accounts|
accounts.namespace :account do |account|
account.resource :profile, :except => [:new, :create, :destroy]
end
end
This gets you what you want. The correct url and pointing to account/... controller.
See Rails Routing for more detailed info and options on what can be done with Rails Routes.
So what's specifically wrong with namespacing? I think this is what you're trying to do:
map.namespace :account do |account|
account.resource :profile
end
This will try to load the controller at app/controllers/account/profiles_controller.rb and will generate routes such as account_profile_path.
Updated based on comment:
map.resources :accounts do |account|
account.resource :profile
end
Will give you /accounts/22/profile.