Paginating with kaminari on a custom route - ruby-on-rails

I'm having a problem with kaminari, it doesn't seem to be able to paginate results when using a custom "unRestful" url.
resources :provinces, :path => '', :only => [ :show ] do
resources :sports, :only => [ :show ] do
match ':page', :controller => 'facilities', :action => 'index'
end
end
So, /:foo/sports/:bar points to a controller, /:foo/sports/:bar/1 points to another 1. It's a disgusting URL scheme but I don't have the leverage right now to change the specs.
If I call the page without Kaminari, everything works as expected, I see the first page. When I use Kaminari like:
<%= paginate #facilities, :params => { :controller => 'facilities', :action => 'index' } %>
Rails gives me a routing error on the following URL:
http://lvh.me:8080/milano/sports/palestra/1
No route matches {:controller=>"facilities", :province_id=>"milano", :sport_id=>"palestra", :page=>nil}
I honestly don't know what to do, everything seems right to me, and couldn't find a kaminari group or more documentation on my case.
The problem seems to be that the call to paginate somewhat generates a URL with page set to nil...
Any suggestion?
Using rails (3.2.8)
Using kaminari (0.14.0)

in controller
#facilities = kaminari.paginate_array(#facilities).page(params[:page]).per(params[:per_page])
and in your view <%= page_entries_info #facilities %> & <%= paginate #facilities %>

Related

Routing and form in Rails

I have a controller for a resource, BuddiesController. My routes config file up until now has been
resources :buddies
match ':controller(/:action(/:id))', :via => [:get, :post]
I didn't realize what the ' resources :buddies ' line was doing until I read up on routing in Rails just now, because the behavior has been identical with what I expected until now. The problem was that I wanted to add a non-CRUD action to the controller: 'search'. Every time I used link_to(:action => 'search'), I would get an exception saying that action 'show' could not be found despite the url being ' localhost:3000/buddies/search ' as expected. I have several questions arising from this:
Firstly, the form I used in 'new' stopped working:
%= form_for(#buddy, {:action => :create, :method => :post, :html => {:role => "form"}}) do |f| %>
because buddies_path couldn't be found. How could I manually add a buddies_path to my routes?
Secondly, I revised the form to use:
<%= form_for(#buddy, :url => {:action => :create, :id => #buddy.id}, :html => {:role => "form", :id => #buddy.id}) do |f| %>
but this has caused the form to give me password and email confirmation not matching errors even if they match. What's going on here?
Lastly, what is the best way to add a search action to my resource?
#routes.rb
resources :buddies
collection do
get :search
end
end
now when you run rake routes | grep 'buddies' you will get output something like this :
now you need to define this search action in your buddies controller .
#buddies_controller.rb
Class BuddiesController < ApplicationController
def search
end
end
Have your search form in app/views/buddies/search.html.erb
Now in order to open your search form / to hit your search action you need to use
<%= link_to 'Search XYZ', search_buddies_path %>
against buddies#search you can see search_buddies
In routes.rb:
resources :buddies do
collection do
post :search
end
end
This might make your routing works.

Defining pretty urls for Rails 4 and will_paginate

I'm using will_paginate for my home page of the application which is the home action of the static_pages controller.
root 'static_pages#home'
The will_paginate URLs are as follows
http://localhost:3000/static_pages/home?page=3
I would prefer to take out the controller name in there and have it look like
http://localhost:3000/home?page=3
Or even something prettier like
http://localhost:3000/home/3
My pagination looks like this
will_paginate #product_feed_items, :page_links => false, :previous_label => "Newer", :next_label => "Older"
and I have tried a couple things like this with no luck
will_paginate(#product_feed_items, :params => { :controller => "static_pages", :action => "home" }, :page_links => false, :previous_label => "Newer", :next_label => "Older")
Does anything have a good solution for this??
If you are looking to do this only for few actions try this:
get "home(/:page)" => "static_pages#home"
You will need to do this via the routes.rb file. Have a look at the routing guide here: http://guides.rubyonrails.org/routing.html
Specifically section 3 on non-resourceful routes.

Rails 3 Routing: non-CRUD controller

I need a bit of help with converting routing from Rails 2 to Rails 3.
In app/views/layouts/application.html.erb, I have:
<%= link_to "Reports", reports_path %><br>
There is a ReportsController, and in app/views/reports/index.html.erb, I have this:
<%= link_to "Clients With Animals", :action => "getAnimals", :controller => "clients" %>
Then, in config/routes.rb, I have this (Rails 3)
match '/reports' => "reports#index"
match '/clients/getAnimals', to: "clients#getAnimals"
I get this error when I click on the "getAnimals" link on the reports page:
ActiveRecord::RecordNotFound in ClientsController#show
Couldn't find Client with id=getAnimals
I don't want "getAnimals" to be the ID - I want it to be the action, instead.
How do I do that?
Assuming you also have a resources :clients entry, you want to make sure match '/clients/getAnimals', to: "clients#getAnimals" is above it (Rails will match whatever it hits first).
However, the better way may be to put it in the resource:
resources :clients do
get 'getAnimals', :on => :collection
end

will_paginate with resources route collection

Can't quite figure out what's going on here. So in my routes I have
sso.namespace(:admin) do |admin|
admin.resources :locations, :collection => {:search => :post}
Generating the pagination just fine on the view. Here's my view code:
<%= will_paginate #search_locations, :class => "loc_pagination", :params => {:controller => 'sso/admin/locations', :action => 'search'}, :style => "text-align: center;" if #search_locations %>
Problem is that when I click on the links, it fires a GET request and sticks search in the params. Here is the parameters in the server log.
Parameters: {"action"=>"show", "id"=>"search", "page"=>"2", "controller"=>"sso/admin/locations"}
The generated html code looks sound, but I can't figure out what it's doing wrong.
You've configured the search action to only respond to post requests. When you attempt to visit the second page of the search results (via a get request) the show route picks up the response. Try changing the :collection => { :search => :any } and append the search term to the params passed to will_paginate.

How can I change the link format in will_paginate for page_cache in Ruby on Rails?

I want to use page_cache with will_paginate.
There are good information on this page below.
http://railsenvy.com/2007/2/28/rails-caching-tutorial#pagination
http://railslab.newrelic.com/2009/02/05/episode-5-advanced-page-caching
I wrote routes.rb looks like:
map.connect '/products/page/:page', :controller => 'products', :action => 'index'
But, links of url are not changed to '/products/page/:page' which are in will_paginate helper.
They are still 'products?page=2'
How can i change url format is in will_paginate?
Is that route declared above any RESTful resources routes? That is, your route file should look like the following:
map.connnect '/products/page/:page', :controller => 'products', :action => 'index'
map.resources :products, :except => [:index]
If your routes look correct, you could try monkey-patching the way will_paginate generates the page links. It does so in WillPaginate::ViewHelpers#url_for(page). It's some fairly complex logic in order to handle some tricky edge cases, but you could write a new version that tried the simple version for your products first:
# in lib/cache_paginated_projects.rb
WillPaginate::ViewHelpers.class_eval do
old_url_for = method(:url_for)
define_method(:url_for) do |page|
if #template.params[:controller].to_s == 'products' && #template.params[:action].to_s == 'index'
#template.url_for :page => page
else
old_url_for.bind(self).call(page)
end
end
end
this works for me
app/helpers/custom_link_renderer.rb
class CustomLinkRenderer < WillPaginate::LinkRenderer
def page_link(page, text, attributes = {})
#template.link_to text, "#{#template.url_for(#url_params)}/page/#{page}", attributes
end
end
add this line to config/environment.rb file
WillPaginate::ViewHelpers.pagination_options[:renderer] = 'CustomLinkRenderer'
A little addition to the current answers, I had to spend hours to figure it out.
If you have some more complex routes, like for example including filtering in my case, make sure that the "higher level" routes come first (and not just that they are above the RESTful one), otherwise will_paginate picks up the first usable one and sticks the extra params at the end of the URL in a non-pretty way.
So in my case I ended up with this:
map.connect "wallpapers/:filter/page/:page", :controller => "wallpapers", :action => "index", :requirements => {:page => /\d+/, :filter => /(popular|featured)/ }
map.connect "wallpapers/page/:page", :controller => "wallpapers", :action => "index", :requirements => {:page => /\d+/ }
map.resources :wallpapers
So now I get pretty URLs like: wallpapers/popular/page/2 instead of wallpapers/page/2?filter=popular
Do this:
map.products_with_pages "/products/page/:page", :controller => "products", :action => "index"
You can even do it with a has_many ie: products has_many :items
map.resources :products do |product|
map.items_with_pages "/products/:id/page/:page", :controller => "products", :action => "show"
end
Then your controller could look like
def show
product = Product.find(params[:id])
#items = product.items.paginate :per_page => 5, :page => params[:page]
end
Which would give you a url like: http://domain.com/products/123/page/3 where 123 is the product id and 3 is the page id. You could also use permalinks and have the 123 id changed to a more seo friendly word.

Resources