routing urls and paths in rails - ruby-on-rails

I have a controller which has a method called history
class UsersController < ApplicationController
def history
User.return_history(params[:id])
end
end
I have the following in my routes.rb file
map.resources :users, :shallow => true do |user|
user.resources :friends, :shallow => false
user.resources :posts, :collection=>{:no_access => :get}
user.resources :photos
end
How do I try to Ajax call the history method of the users_controller.rb? Using link_to_remote in the following way
link_to_remote 'History', :url=>history_user_path(#user), :update=>"history", :method=>'get'
throws me an error saying history_user_path() not found. How can this be? edit_user_path() shows no error and edit is not even explicitly defined in the User.rb file. Thanks.

mapresources :users creates a bunch of url/path helper methods, including edit_users_path. If you need others. you've got to add it as either a :member, or :collection option for map.resources.
This will let you do what you want:
map.resources :users, :shallow => true, :member => {:history => :get} do |user|
user.resources :friends, :shallow => false
user.resources :posts, :collection=>{:no_access => :get}
user.resources :photos
end

Related

paginate 'nested' rails routes for seo

I need to figure out how to properly use routes to create a url structure like so:
items/page/2
items/expired/page/2
I have items/page/2 working and then I have this which I want to to correct:
items/expired?page=2
I am using Kaminari to provide pretty url structure for rails 4.2 with a concern.
https://github.com/amatsuda/kaminari/#creating-friendly-urls-and-caching
My controller has two actions: index and expired
My views under items are index.html.haml and expired.html.haml
routes.rb
concern :paginatable do
get '(page/:page)', :action => :index, :on => :collection, :as => ''
end
concern :expired_paginatable do
get '(page/:page)', :action => :expired, :on => :collection, :as => ''
end
get 'items/expired', to: "items#expired", :concerns => :expired_paginatable
resources :items, :concerns => :paginatable
my views both have:
= paginate #items
I know I do not need two concerns but thought I would try it.
I ended up changing my resources block to this:
resources :items do
collection do
get 'expired/page/:page', :action => :expired
get :expired
end
concerns :paginatable
end
dropping:
concern :expired_paginatable do
get '(page/:page)', :action => :expired, :on => :collection, :as => ''
end
get 'items/expired', to: "items#expired", :concerns => :expired_paginatable
resources :items, :concerns => :paginatable

Namespaced controller redirect urls

i have probably a simple question. I have created a namespace panel with categories controller.
After creating or editing a category, rails redirects me to website.com/categories/:id instead of website.com/panel/categories/:id.
I've noticed that in the _form view, the #panel_categories argument of form_for() function points to /categories nor /panel/categories and that's causing this behaviour. Offcourse i can add a :url => '/panel/categories' param but i feel that it's not the best solution...
Can you provide me any better solution?
Thanks in advance
Files:
routes.rb:
Photowall::Application.routes.draw do
resources :photos
resources :categories
resources :fields
resources :users, :user_sessions
match 'login' => 'user_sessions#new', :as => :login
match 'logout' => 'user_sessions#destroy', :as => :logout
namespace :panel do
root :to => "photos#index"
resources :users, :photos, :categories, :fields
end
namespace :admin do
root :to => "users#index"
resources :users, :photos, :categories, :fields
end
end
categories_controller.rb:
http://pastebin.com/rWJykCCF
model is the default one
form:
http://pastebin.com/HGmkZZHM
form_for [:panel, #panel_category]
You can set the url to a route such as:
:url => panel_categories_path
I'm not sure what your route is, but this should work with your application.

How to specify a route member inside a block in Rails?

The following code:
map.resources :users, :has_many => :items
Could be written like this in a block:
map.resources :users do |user|
user.resources :items
end
How could I write the following code in a block?
map.resources :users, :member => { :start => :post }
Also, where could I find documentation on writing routes in blocks?
The Routes Documentation does not seem to show it.
Thank you!
Rails 2.x doesn't allow you to use blocks for member definition.
With Rails 3.x you can write
resources :users do
member do
post :start
end
end
You can do it like so in Rails 2 (2.3.5 is the version I tested it on):
map.resources :users, :member => { :start => :post } do |user|
user.resources :items
end
From here: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/

Rails functional tests, routing error

I'm new to testing, and I'm having some difficulties trying to run a functional test.
I've a messages_controller, and a user_controller here.
in the routes, I've defined that the users resources has_many message resources.
Now I'm trying to run a simple test in the messages controller:
def test_index
get :index, { :user_id => 1 }
assert_template 'index'
end
But get a routing error from rails, that he cant find a route to messages. I don't want to include a route to messages only because of the tests. How can I tell the test that he must access from the /users/messages url?
the full routes.rb:
ActionController::Routing::Routes.draw do |map|
map.login 'login', :controller => :user_sessions, :action => :new
map.logout 'logout', :controller => :user_sessions, :action => :destroy
map.signin 'signin', :controller => :users, :action => :new
map.connect 'search/:action/:word', :controller => :search
map.connect 'search/:word', :controller => :search, :action => :index
map.resources :forums do |forums|
forums.resources :forum_posts, :collection => {:preview => :post }, :as => :posts do |post|
post.resources :forum_posts, :as => :reply
post.resources :reports
end
end
map.resources :newsitems, :as => :news do |news|
news.resources :comments do |comment|
comment.resources :reports
end
end
map.resource :user_sessions
map.resources :users,
:as => :profiles,
:controller => :profiles,
:has_many => [ :messages ]
map.resource :profiles
map.resource :me,
:controller => :me,
:has_many => [ :messages ]
map.resources :comments, :has_many => [ :reports ]
map.resources :forum_posts, :has_many => [ :reports ]
map.resources :reports
map.home '/', :controller => :home
map.root :controller => :home
map.namespace :admin do |admin|
admin.namespace :forum do |forum|
forum.resources :categories
forum.resources :posts
forum.resources :forums
forum.root :controller => :home
end
admin.resources :notices
admin.resources :users
admin.workflow 'workflow/:action', :controller => :workflow
admin.resources :newsitems
admin.resources :reports
admin.resources :comments
admin.root :controller => :home
end
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
UPDATE
I've noticed that every functional test get a routing error. Even the simpliests ones like newsitem. I've no idea why.
I recreated your scenario in a blank rails app with the routing code and and test you specified, and it worked without a problem, as it should. I'll paste my controller code here since that's the only part you left out:
class MessagesController < ApplicationController
def index
#messages = User.find(params[:user_id]).messages
end
end
If yours is doing basically the same thing, then a routing issue could be caused by a conflict in your routing file, which is what I suspect might be the case. Can you post it? FYI, I wrote an article on testing your routes, and that would be a very good idea because it would catch routing errors early, before they interfere with controllers.
Anyway, if you can post your routes I can take a look.
UPDATE: After looking at your routes, there are a couple conflicts. You can have messages as a sub-resource of more than one other resource, but in your messages controller you're going to have to account for the possibility of either a params[:me_id] or params[:profile_id]. It looks like they're both really the user model underneath, so it can be as simple as:
#user = User.find(params[:me_id] || params[:profile_id])
and you'll probably want to abstract that out into a method you call with before_filter.
The other issue is that you have two overlapping profiles routes, and I'm not sure why. I don't think it's a routing error in the test, because tests bypass the routing engine anyway. I think it's an error in the index view, because it probably contains links to messages with improperly formatted urls. If you have a link to a message, for instance, and you have a #profile object, then you'll need to call them like this:
<%= link_to message.name, profile_message_path(#profile, #message) %>
However, if you're using non-nested paths like message_path(#message), it will fail because there are no non-nested message routes.
It was a problem in my "journey" gem. They made routes more stricter in journey 1.0.4 which only show up on "test" environment. It is good for "developement" and "production".
** Ensure you are using exactly the same parameters as declared in routes **
Either add:
get :index, :locale => "en"
or in your Gemfile update:
gem 'journey', '1.0.3'
The second solution is a workaround for time being. Ideally you should be testing your routes will all exact params. Journey 1.0.4 is a lot stricter

Multiple Nested Routes, is there a better way to do this?

So In my rails app I have two resources (rentals, and reservations) which belong to a user. This is the code in my routes.rb to set up the nested routes.
map.resources :users, :has_many => :reservations, :shallow => true
map.resources :users, :has_many => :rentals, :shallow => true
map.resources :rentals, :only => [:index]
map.resources :reservations, :only => [:index]
Is there a more perferred way to do this. I've done some googling but I can't find a clear answer.
Thanks in advance.
-ray
Your method duplicates the routes for users, as you can see by running rake routes. You can fix that by passing a block to map.resources:
map.resources :users, :shallow => true do |user|
user.resources :reservations
user.resources :rentals
end
The nested routes created will assume that you always want to access those resources in a nested fashion.
If you really need all the routes you've defined (including the non-nested rentals and reservations index) then you will need to add:
map.resources :rentals, :only => [:index]
map.resources :reservations, :only => [:index]
And I don't know of a DRYer way to do that.
Nests the two resources under users:
map.resources :users, :shallow => true do |users|
users.resources :reservations, :only => :index
users.resources :rentals, :only => :index
end
Edit: Sorry, forgot the :shallow option.
You can define nested routes with blocks
map.resources :users, :shallow => true do |user|
user.resources :reservations, :only => [:index]
user.resources :rentals, :only => [:index]
end
I feel that this way is a bit more clear and can more easily be adjusted later when you need additional options on one of the nested resources.
The different options and the details are at the ActionController Resources API page

Resources