Figuring out rails routes, getting undefined method for my detail_path - ruby

My data of a datatable:
def data
theusers.map do |usermap|
[
h(usersmap.spriden_last_name),
h(usermap.spriden_first_name),
h(usermap.spriden_id),
link_to(usermap.gobtpac_username, detail_path(usermap.spriden_id))
]
end
end
the above code resides in app\datatables\helpdesk_datatable.rb
The above works mostly I know it is getting the data, the error I get is with the detail_path
Error on "undefined method" for detail_path... This means it is not building the router dynamically right, correct?
Or I am passing in the wrong thing I tried to pass in usermap.spriden.id and just banner user, same issue. I am really not sure how routes work apparently. I have a details_controller.rb in controllers that has a show method in it and i have the views/details/show.html.erb which will show the data that was passed into the route, at least I thought. But is it just an ID or an object? so if it just an id i have to look it up again in
the show method right? How do routes like this look? I am using devise and cancan too here is my routes file:
NmsuMyaccount::Application.routes.draw do
authenticated :user do
root :to => 'home#index'
match 'home', :to => 'home#index', :via => :get
end
#get 'show-details' => "details#show", as: 'show_details'
resources :details
devise_for :users
resources :users
# In order for an unauthorized user access this controller#action, this needs to be in a scope, but I don't know why.
devise_scope :user do
match 'home', :to => 'home#index', :via => :get
end
end
Also hitting the end point localhost:3000 is an error, I have to goto /home, although devise does work just fine. So thought I was close but for the life of me cannot get the detail_path to work, and I thought it was a plural issue so tried details, and just detail no path etc. No dice.

I don't believe that you have access to the route helpers that Rails provides inside your custom class. So you have to manually include the module inside your class. Something like:
link_to(usermap.gobtpac_username, Rails.application.routes.url_helpers.detail_path(usermap.spriden_id))
Or:
include Rails.application.routes.url_helpers
# Use it like you are using.
See here for more information about the subject:
Can Rails Routing Helpers (i.e. mymodel_path(model)) be Used in Models?

Related

How to fix FriendlyID duplicate content for :id and :slug

FriendlyID is consistently showing duplicate content for both /slug and /1. In other words, the correct page is loading for the friendly slug (/new-york), but it's loading the same content for the old, unfriendly slug (/11).
Here's my current configuration:
#config/routes.rb
resources :groups, path: ''
get 'groups/:id' => redirect("/%{id}")
#app/models/group.rb
class Group < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: [:slugged, :finders]
end
#app/controllers/groups_controller.rb
def show
#group = Group.friendly.find(params[:id])
end
As a potential workaround, I've found putting this in my controller does redirect the bad slugs (/11) to the good slugs (/new-york), but it feels wrong for many reasons (routing outside routes.rb, likely unintended consequences, complex solution for a common problem = probably not the right one).
if request.path != group_path(#group)
return redirect_to #group, :status => :moved_permanently
end
What is the right way to make FriendlyID either (1) redirect :id calls to :slug or (2) simply 404 them?
Thanks to this fantastic comment on Medium, I now have a fully functional and very elegant solution which solves my initial problem (duplicate pages with /new-york and /11) as well as allowing two root-level slug structures to coexist.
get '/:id', to: 'groups#show', constraints: proc {|req| FriendlyId::Slug.where(sluggable_type: 'Group').pluck(:slug).include?(req.params[:id])}, as: :group
get '/:id', to: 'custom_pages#show', constraints: proc {|req| FriendlyId::Slug.where(sluggable_type: 'CustomPage').pluck(:slug).include?(req.params[:id])}, as: :custom_page

Detect which method called the routing condition in Sinatra

I'm using Sinatra with namespace.
When I tried to use condition, I met a problem.
Here's the snippet of code
class MainApp < Sinatra::Base
register Sinatra::Namespace
set(:role) do |role|
condition{
### DETECT WHERE THIS IS CALLED
p role
true
}
end
namespace '/api', :role => :admin do
before do
p "before"
end
get '/hoo' do
p "hoo"
end
end
namespace '/api' do
get '/bar' do
p "bar"
end
end
end
The above code outputs following message to console when accessing /api/hoo
:admin
:admin
"before"
:admin
"hoo"
I could not understand why :admin is displayed three times. However, maybe one is from namespace, and other twos are from before and get '/hoo'.
On the other hand, accessing /api/bar shows :admin two times.
I just want to do the filtering only before get '/hoo'. Is there any idea?
NOTE: I don't wan't to change URL from /api/hoo to something like /api/baz/hoo
You can debug the steps using the caller:
http://ruby-doc.org/core-2.0/Kernel.html#method-i-caller
(Note: I wouldn't recommend to leave caller in production code unless you absolutely need it for introspection, because it's quite slow.)
Re the Sinatra filters in particular, note that you can at the very least qualify the route and conditions they apply to:
http://www.sinatrarb.com/intro#Filters
before '/protected/*' do
authenticate!
end
before :agent => /Songbird/ do
# ...
end
I can't recollect how to get the http method, but if you look at the sinatra source code you'll likely find it -- last I looked, I recollect each of get, post, etc. to forward their call to the same function, with a method parameter.

Devise : /login with param giving `undefined method stringify_keys`

For /login my application is working fine, but for /login?user="something" giving 500
I am using devise gem
routes.rb
devise_for :users, :controllers => { :sessions => 'devise/sessions'}, :skip => [:sessions] do
get '/login' => "devise/sessions#new", :as => :new_user_session
end
error :
Completed 500 Internal Server Error in 263ms
NoMethodError (undefined method `stringify_keys' for "\"something\"":String):
Rendered /usr/local/rvm/gems/ruby-1.9.2-head/gems/actionpack-3.1.0/lib/action_dispatch/middleware/templates/rescues/_trace.erb (2.6ms)
Rendered /usr/local/rvm/gems/ruby-1.9.2-head/gems/actionpack-3.1.0/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.7ms)
Rendered /usr/local/rvm/gems/ruby-1.9.2-head/gems/actionpack-3.1.0/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (7.9ms)
stringify_keys is a method that Rails mixes into the Ruby Hash class, so the problem here is that devise is expecting a hash of attribute-value pairs in the user param instead of a plain string. In other words its expecting a User model object rather than just a user name.
The convention that Rails uses for packing nested attribute value pairs into URL query string or HTML form params uses square brackets, so you probably need something like this:
/login?user[name]=someone&user[password]=secret

Rails current_path Helper?

I'm working on a Rails 3.2 application with the following routing conditions:
scope "(:locale)", locale: /de|en/ do
resources :categories, only: [:index, :show]
get "newest/index", as: :newest
end
I've a controller with the following:
class LocaleController < ApplicationController
def set
session[:locale_override] = params[:locale]
redirect_to params[:return_to]
end
end
I'm using this with something like this in the templates:
= link_to set_locale_path(locale: :de, return_to: current_path(locale: :de)) do
= image_tag 'de.png', style: 'vertical-align: middle'
= t('.languages.german')
I'm wondering why there doesn't exist a helper in Rails such as current_path, something which is able to infer what route we are currently using, and re-route to it include new options.
The problem I have is using something like redirect_to :back, one pushes the user back to /en/........ (or /de/...) which makes for a crappy experience.
Until now I was storing the locale in the session, but this won't work for Google, and other indexing services.
I'm sure if I invested enough time I could some up with something that was smart enough to detect which route matched, and swap out the locale part, but I feel like this would be a hack.
I'm open to all thoughts, but this SO question suggests just using sub(); unfortunately with such short and frequently occurring strings as locale short codes, probably isn't too wise.
If you are using the :locale scope, you can use url_for as current_path:
# Given your page is /en/category/newest with :locale set to 'en' by scope
url_for(:locale => :en) # => /en/category/newest
url_for(:locale => :de) # => /de/kategorie/neueste
In case somebody looks here, you can use request.fullpath which should give you all after domain name and therefore, will include locale.

Rails 3: Remap user_path route with match rule

I have got this in my routes file:
resources :users
match '/#:id' => 'users#show'
When I go to /#radeks then it would be the same as if I would go to /users/radeks. However, I use user_path in my views, but this points to /users/radeks which I don't want.
How can I make user_path always point to /#:id?
Edit
I also have got this in my User model:
def to_param
name
end
match '/#:id' => 'users#show', :as => 'user'
The :as argument makes this a "named route". See http://guides.rubyonrails.org/routing.html#naming-routes for more info.
NB that you're overriding the default 'user' named route you get automagically from 'resources :users'

Resources