ui-router, devise and a user profile page - ruby-on-rails

I'm trying to create a user profile page but I'm having some problems. I've used Devise for user handling in my project and I'm using AngularJS and ui-router and obviously RoR.
What I'm trying to do is to show a profile page of a user when the following URL is visited http://localhost:3000/users/1
When I visit that URL now I see my frontpage (views/layout/application.html.haml) which is obviously wrong.
In my mainCtrl.js I have
$stateProvider
.state('home', {
url: '',
templateUrl: '../assets/angular-app/templates/_search.html',
controller: 'searchCtrl'
})
.state('users.profile', {
url: '/users/{id}',
templateUrl: '../assets/angular-app/templates/_profile.html'
})
The home state works when I go to localhost:3000
But like I said, when I go to http://localhost:3000/users/1 the template _profile.html doesn't get inserted, there's not even an error if I mistype the template file name. So it looks like the state action doesn't do anything.
My expectation is that the template _profile.html gets loaded into the
%div{"ui-view" => ""}
on my application.html.haml page. But it inserts the _search template.
And this is the routes.rb if it matters,
Rails.application.routes.draw do
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
get 'sessions/create'
get 'sessions/destroy'
devise_scope :user do
root to: 'application#angular'
match '/sessions/user', to: 'devise/sessions#create', via: :post
end
resources :users do
member do
get :following, :followers
end
end
resources :relationships, only: [:create, :destroy]
get 'login/show'
get 'auth/:provider/callback', to: 'sessions#create'
get 'auth/failure', to: redirect('/')
get 'signout', to: 'sessions#destroy', as: 'signout'
resources :sessions, only: [:create, :destroy]
resources :movies, only: [:create, :destroy, :index, :show]
end

Researching some examples I noticed the hashtag. When I added the # to my url the route states started working. Then I used html5mode enabled to remove the # and now it's working fine.

Related

When using the friendly_id gem - can you ignore certain routes like /about /contact?

I'm using the friendly_id gem in a Rails application, to be able to view organisations at site.com/organisation-name
The problem is that I have a few static pages like "About" and "Contact" at site.com/about and friendly_id assumes these pages should point to a record, hence I get this error.
ActiveRecord::RecordNotFound in OrganisationsController#show
can't find record with friendly id: "about"
routes.rb
resources :organisations, path: "", except: [:index, :new, :create] do
resources :posts
end
get '/organise', to: 'home#organise'
get '/privacy', to: 'home#privacy'
get '/about', to: 'home#about'
get '/terms', to: 'home#terms'
Is there a way to ignore these routes at all, or do I need to prefix them with something else?
The solution was to simply reorder my routes to put the static page routes above my organisations route definition:-
get '/organise', to: 'home#organise'
get '/privacy', to: 'home#privacy'
get '/about', to: 'home#about'
get '/terms', to: 'home#terms'
resources :organisations, path: "", except: [:index, :new, :create] do
resources :posts
end

One of my Rails routes requesting favicon.ico

I've just added resources: :favorites, nested inside resources: :deals, to my Rails app. All of a sudden, visiting the deals/deal_slug/favorites/new, after it renders, fires off a GET request to deals/favicon.ico which of course activates the show route, which fails to find anything with the slug of favicon.ico.
It appears to ONLY be the favorites/new route that causes this request, and I've tried commenting out all of favoritescontroller#new as well as the new view, with no change.
Commenting out link href="../../favicon.ico" rel="icon" in my layout fixes it of course, but I'd love to keep that in my layout and figure out why the heck this problem JUST started!
My routes file:
Rails.application.routes.draw do
# what are these??
get 'regions/index'
get 'regions/show'
root "deals#index"
resources :deals, param: :slug do
resources :favorites
end
resources :favorites
get 'my-deals', to: 'deals#my_deals', as: :my_deals_path
resources :regions, param: :slug, only: [:index, :show] do
resources :deals, only: [:index, :show], param: :slug
# resources :deals, only: [:index, :show, :edit, :destroy]
end
resource :preferences
ActiveSupport::Inflector.inflections {|inflect| inflect.irregular 'preferences', 'preferences'} # fix route helper paths so that form_for works
get '/preferences/delete_airport/:airport_id', to: 'preferences#destroy', as: 'delete_home_airport'
resources :vacations
get 'pry', to: 'application#pry'
# ------- DEVISE STUFF --------
devise_for :users, controllers: {
omniauth_callbacks: 'users/omniauth_callbacks',
preferences: 'users/preferences',
}
devise_scope :user do
get "/sign_out", to: 'devise/sessions#destroy', as: 'user_sign_out'
get "/sign_in", to: 'users/sessions#new', as: 'user_sign_in'
get "/sign_up", to: 'devise/registrations#new', as: 'user_sign_up'
get "/user/preferences", to: 'users/preferences#index', as: 'user_preferences'
get "/user/preferences/edit", to: 'users/preferences#edit', as: 'edit_user_preferences'
patch "/user/preferences/:id/edit", to: 'users/preferences#update'
end
devise_for :admins, path: 'admin', controllers: { sessions: 'admins/sessions' }
devise_scope :admin do
get "/admin", to: 'admins/sessions#portal', as: 'admin_root'
get "/admin/sign_out", to: 'devise/sessions#destroy', as: 'admin_sign_out'
end
end
FavoritesController:
class FavoritesController < ApplicationController
def new
prefs = current_user.preferences
#favorite = Favorite.new deal: Deal.find_by(slug: params[:deal_slug]), preference_id: prefs.id
end
def create
#favorite = Favorite.create(favorite_params)
redirect_to preferences_path
end
def favorite_params
params.require(:favorite).permit :preference_id, :deal_id, :comment
end
end
The request for the favicon icon is made by the browser, your code does not trigger that request.
The problem is your favicon href, you are making it relative to the current path: "../../favicon.ico" instead of absolute "/favicon.ico". You'll get the same problem if you have other routes with more than 2 levels since the route is relative.
You should add the favicon.icon somewhere on your public folder and point at it with an absolute path instead. If the icon is in /public/favicon.ico then configure the layout's favicon tag with href="/favicon.ico", if you put the icon somewhere else like /public/icons/favicon.ico then change the link tag to href="/icons/favicon.ico".

Rails - Deploying to Heroku with duplicate routes

I'm deploying my Rails app that uses the clearance gem to Heroku. Everything works fine in development but I'm running into trouble with the gem generated routes I get.
When attempting to deploy to Heroku, I get the error...
ArgumentError: Invalid route name, already in use: 'sign_in'
You may have defined two routes with the same name using the `:as` option, or you may be overriding a route already defined by a resource with the same naming. For the latter, you can restrict the routes created with `resources` as explained here:
remote: http://guides.rubyonrails.org/routing.html#restricting-the-routes-created
I'm not seeing where to restrict the duplicates or where they would be generated with any of my resources:
Please see routes.rb file below
Routes.rb
Rails.application.routes.draw do
resources :passwords, controller: "clearance/passwords", only: [:create, :new]
resource :session, controller: "clearance/sessions", only: [:create]
resources :users, controller: "clearance/users", only: [:create] do
resource :password,
controller: "clearance/passwords",
only: [:create, :edit, :update]
end
get "/sign_in" => "clearance/sessions#new", as: "sign_in"
delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
get "/sign_up" => "clearance/users#new", as: "sign_up"
get 'newSignUp', to: 'signups#new'
post 'newSignUp', to: 'signups#create'
get 'newTrip', to: 'trips#new'
post 'newTrip', to: 'trips#create'
get 'trips/:id/send_itinerary' => 'trips#send_itinerary', as: :trips_send_itinerary
root 'static_pages#home'
get 'static_pages/home'
get 'static_pages/help'
get 'static_pages/about'
get 'static_pages/contact'
resources :signups
resources :tripitems
resources :trips
end
This issue has to do with the clearance gem.
I am not totally familiar with the gem, so as per usual, I checked out the github and found the following:
# config/routes.rb
if Clearance.configuration.routes_enabled?
Rails.application.routes.draw do
resources :passwords,
controller: 'clearance/passwords',
only: [:create, :new]
resource :session,
controller: 'clearance/sessions',
only: [:create]
resources :users,
controller: 'clearance/users',
only: Clearance.configuration.user_actions do
resource :password,
controller: 'clearance/passwords',
only: [:create, :edit, :update]
end
get '/sign_in' => 'clearance/sessions#new', as: 'sign_in'
delete '/sign_out' => 'clearance/sessions#destroy', as: 'sign_out'
if Clearance.configuration.allow_sign_up?
get '/sign_up' => 'clearance/users#new', as: 'sign_up'
end
end
end
This is basically creating the same routes for you, only if the config routes_enabled? is true.
You need to configure clearance as follows to handle the routes yourself:
config.routes = false
After looking at the gems GitHub, it looks like I raked the routes earlier and even though config.routes was set to false in the initializer, there was a conflict generate in the generated resources in production.
I wound up deleting the raked routes and making config.routes=true.

Does the order of the routes effect which controller is accessed?

In my app I have grants and I want the url to be root/grant_id instead of root/grants/grant_id. I have this in my routes
Rails.application.routes.draw do
...
root 'static_pages#welcome'
# get 'home' => 'static_pages#home'
get 'about' => 'static_pages#about'
get 'faq' => 'static_pages#faq'
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
get 'dashboard' => 'dashboard#index'
resources :users do
resources :projects
member do
get 'access_granted'
put 'access_granted'
get 'remove_access'
put 'remove_access'
end
end
resources :profiles
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resource :request_access, only: [:show, :new, :create]
resources :grants, :path => '' do
resources :app_types do
resources :submissions
end
end
get 'grants' => 'grants#index'
resources :matches
end
When I put resources :matches below the resources :grants, :path => '' do line I get the error "Couldn't find Grant" and I see that request parameters are
{"controller"=>"grants", "action"=>"show", "id"=>"matches"}. When I put resources :matches above the the grant line everything works fine. Its almost like something in the grant route isn't closing and is forcing any lines below it to look for the grant controller. A simple solution is just keeping everything above that line but I'm trying to understand why this is happening.
I also noticed that even though I define the grant#index as grants, when I rake routes I see:
grants GET / grants#index
GET /grants(.:format) grants#index
So two questions
1. Is :path => '' the correct way to remove the grants/ part of the url.
2. Why is everything below the grants route getting sent to the grants controller?
From the documentation :
Rails routes are matched in the order they are specified, so if you have a resources :photos above a get 'photos/poll' the show action's route for the resources line will be matched before the get line. To fix this, move the get line above the resources line so that it is matched first.
So, the problem you're having is that matching grants to "" means your grants INDEX route is /, and your grants SHOW route is /:grant_id, which will match any route. If you want to have this kind of route (which I would advise against), it has got to be at the bottom of the routes file.
You can read more about routing here: http://guides.rubyonrails.org/routing.html

Why rails app is redirecting unexpectedly instead of matching the route?

I asked this question earlier and thought it was fixed, but it's not. Previous question here
My problem is I am trying to set my routes so that when I type in
localhost:3000/sites/admin
It should redirect to
localhost:3000/en/sites/admin
here is my routes.rb file
scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do
get "log_out" => "sessions#destroy", as: "log_out"
get "log_in" => "sessions#new", as: "log_in"
resources :sites, except: [:new, :edit, :index, :show, :update, :destroy, :create] do
collection do
get :home
get :about_us
get :faq
get :discounts
get :services
get :contact_us
get :admin
get :posts
end
end
resources :users
resources :abouts
resources :sessions
resources :coupons
resources :monthly_posts
resources :reviews
resources :categories do
collection { post :sort }
resources :children, :controller => :categories, :only => [:index, :new, :create, :new_subcategory]
end
resources :products do
member do
put :move_up
put :move_down
end
end
resources :faqs do
collection { post :sort }
end
root :to => 'sites#home'
match "/savesort" => 'sites#savesort'
end
match '', to: redirect("/#{I18n.default_locale}")
match '*path', to: redirect("/#{I18n.default_locale}/%{path}")
But as of right now, it redirects to /en/en/en/en/en/en/en/en/en/en/sites/admin (adds en until browser complains).
Any thoughts why it keeps adding /en?
Edit:
The answer is great, thanks. Can you help me diagnose the root route?
root to: redirect("#{/#{I18n.default_locale}") # handles /
I know redirects is looking for something like
redirect("www.example.com")
So that leaves this part
#{/#{I18n.default_locale}
The #{ is using rubys string interpolation, right? i'm not sure what that { is doing though.
So then we have
/#{I18n.default_locale}
Which is also using string interpolation and to print out the value of I18n.default_locale?
Hopefully that makes sense, I really really appreciate the help, I am learning a lot.
Edit 2:
I changed the line from
root to: redirect("#{/#{I18n.default_locale}") # handles /
to
root to: redirect("/#{I18n.default_locale}") # handles /
But i'm not sure if thats right. Now i'm getting the error
uninitialized constant LocaleController
I know it's getting the error from the root to: "locale#root", but i thought the locale# would come from the scope.
I'll continue playing with it and let you know any progress.
Here is a new link to my routes file https://gist.github.com/2332198
We meet again, ruevaughn. :)
I created a test rails app and the following minimal example works for me:
scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do
resources :sites do
collection do
get :admin
end
end
root to: "locale#root" # handles /en/
match "*path", to: "locale#not_found" # handles /en/fake/path/whatever
end
root to: redirect("/#{I18n.default_locale}") # handles /
match '*path', to: redirect("/#{I18n.default_locale}/%{path}") # handles /not-a-locale/anything
When using Rails 4.0.x that %{path} in the redirect will escape slashes in the path, so you will get an infinite loop redirecting to /en/en%2Fen%2Fen%2Fen...
Just in case someone, like me, is looking for a Rails-4-suitable solution, this is what I found to be working without problems, even with more complex paths to be redirected:
# Redirect root to /:locale if needed
root to: redirect("/#{I18n.locale}", status: 301)
# Match missing locale paths to /:locale/path
# handling additional formats and/or get params
match '*path', to: (redirect(status: 307) do |params,request|
sub_params = request.params.except :path
if sub_params.size > 0
format = sub_params[:format]
sub_params.except! :format
if format.present?
"/#{I18n.locale}/#{params[:path]}.#{format}?#{sub_params.to_query}"
else
"/#{I18n.locale}/#{params[:path]}?#{sub_params.to_query}"
end
else
"/#{I18n.locale}/#{params[:path]}"
end
end), via: :all
# Redirect to custom root if all previous matches fail
match '', to: redirect("/#{I18n.locale}", status: 301), via: :all

Resources