How to use will_paginate with a nested resource in Rails? - ruby-on-rails

I'm new to Rails, and I'm having major trouble getting will_paginate to work with a nested resource.
I have two models, Statement and Invoice. will_paginate is working on Statement, but I can't get it to work on Invoice. I know I'd doing something silly, but I can't figure it out and the examples I've found on google won't work for me.
statement.rb
class Statement < ActiveRecord::Base
has_many :invoices
def self.search(search, page)
paginate :per_page => 19, :page => page,
:conditions => ['company like ?', "%#{search}%"],
:order => 'date_due DESC, company, supplier'
end
end
statements_controller.rb <irrelevant code clipped for readability>
def index #taken from the RAILSCAST 51, will_paginate podcast
#statements = Statement.search(params[:search], params[:page])
end
I call this in the view like so, and it works:
<%= will_paginate #statements %>
But I can't figure out how to get it to work for Invoices:
invoice.rb
class Invoice < ActiveRecord::Base
belongs_to :statement
def self.search(search, page)
paginate :per_page => 19, :page => page,
:conditions => ['company like ?', "%#{search}%"],
:order => 'employee'
end
end
invoices_controller.rb
class InvoicesController < ApplicationController
before_filter :find_statement
#TODO I can't get will_paginate to work w a nested resource
def index #taken from the RAILSCAST 51, will_paginate podcast
#invoices = Invoice.search(params[:search], params[:page])
end
def find_statement
#statement_id = params[:statement_id]
return(redirect_to(statements_url)) unless #statement_id
#statement = Statement.find(#statement_id)
end
end
And I try to call it like this:
<%= will_paginate (#invoices) %>
The most common error message, as I play with this, is:
"The #statements variable appears to be empty. Did you forget to pass the collection object for will_paginate?"
I don't have a clue what the problem is, or how to fix it. Thanks for any help and guidance!

Solved -
I moved the invoices pagination into Statement's controller, like this:
def show
#statement = Statement.find(params[:id])
#TODO move the :per_page stuff out to a constant
#invoices = #statement.invoices.paginate :per_page => 10,
:page => params[:page],
:order => 'created_at DESC'
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #statement }
end
end
and call it in the view like this (code trimmed for readability>
<div id="pagination">
<%= will_paginate #invoices %>
</div>
<table>
<%# #statement.invoices.each do |invoice| -
shows all invoices with no pagination,
use #invoices instead%>
<%
#invoices.each do |invoice|
%>

Related

Limit total messages displayed in the inbox

I can't seem to find the correct way to set a maximum number of messages to display in a users inbox without it disfiguring the pagination. I'm trying to make it so only the last 100 inbox messages are displayed from newest to oldest.
messages_controller.rb
class MessagesController < ApplicationController
def index
#messages = current_user.received_messages.paginate(:page => params[:page], :per_page => 15, :order => 'created_at DESC', )
end
using the will_paginate gem
<%= will_paginate #messages %>
def index
#messages = current_user.received_messages.paginate(:page => params[:page], :per_page => 15).order('created_at DESC').limit(100)
end
or try with
def index
#records = current_user.received_messages.order('created_at DESC').limit(100)
#messages = #records.paginate(:page => params[:page], :per_page => 15)
end
Hope this will work
But it is a good practice to first implement the active_records conditions, than the pagination's.
def index
#messages = current_user.received_messages.order(:created_at).reverse_order.limit(100).paginate(:page => params[:page], :per_page => 15)
end
Hope it will help.
I have this problem before, My fix was:
require 'will_paginate/array' # To paginate an array instead of ActiveRecord
class MessagesController < ApplicationController
def index
#messages = current_user.received_messages.limit(100).all.paginate(:page => params[:page], :per_page => 15, :order => 'created_at DESC') # I transform the resultset to an array using .all before the paginate
end

Issue With Will Paginate and Index Action

In my controller for the index action, I have;
def index
#documents = current_user.documents.all if current_user
end
Anything I add on the end of current_user I get an error. For example, I tried to add will_paginate which is simply adding .paginate(:per_page => 5, :page => params[:page]) to the end of the index action and adding <%= will_paginate #documents %> to the views.
Once I add the .paginate(:per_page => 5, :page => params[:page]) to the end of the index method, like this;
def index
#documents = current_user.documents.all if current_user.paginate(:per_page => 5, :page => params[:page])
end
I get a NoMethodError. Anybody know how to fix this?
Try
def index
#documents = current_user.documents.paginate(:per_page => 5, :page => params[:page]) if current_user
end
You're calling the method on the wrong object, here is the correct one:
#documents = current_user.documents.paginate(:per_page => 5, :page => params[:page]) if current_user

How to get acts on taggable working

I am new to ruby on rails (and programming) and this is probably a really stupid question. I am using Rails 3.2 and trying to use acts_as_taggable_on to generate tags on articles and to have those tags show on article index and show pages as a clickable links.
I have tags clickable on both the article show and index pages, but the links just go back to the index page and don't sort according to the tag name. I have scoured the Internet and pieced together the code below from various sources, but I am clearly missing something.
Any help is greatly appreciated, as I have exhausted my seemingly limited knowledge! Thanks.
Here is what I have:
class ArticlesController < ApplicationController
def tagged
#articles = Article.all(:order => 'created_at DESC')
#tags = Article.tag_counts_on(:tags)
#tagged_articles = Article.tagged_with(params[:tags])
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #articles }
end
end
def index
#articles = Article.paginate :page => params[:page], :per_page => 3
#tags = Article.tag_counts_on(:tags)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #articles }
end
end
module ArticlesHelper
include ActsAsTaggableOn::TagsHelper
end
class Article < ActiveRecord::Base
acts_as_ordered_taggable
acts_as_ordered_taggable_on :tags, :location, :about
attr_accessible :tag_list
scope :by_join_date, order("created_at DESC")
end
article/index.html.erb
<% tag_cloud(#tags, %w(tag1 tag2 tag3 tag4)) do |tag| %>
<%= link_to tag.name, articles_path(:id => tag.name) %>
<% end %>
article/show.html.erb
<%= raw #article.tags.map { |tag| link_to tag.name, articles_path(:tag_id => tag) }.join(" | ") %>
routes.rb file snippet
authenticated :user do
root :to => 'home#index'
end
devise_for :users
resources :users, :only => [:show, :index]
resources :images
resources :articles
You can run 'rake routes' from the terminal to see all your paths. Here your tags are pointing at articles_path, which you will see routes to the index action in the articles controller ("articles#index")
You could create another route in your routes.rb file, something like:
match 'articles/tags' => 'articles#tagged', :as => :tagged
Place it above others in the routes file if you want it to take precedence, and remember you can always run 'rake routes' in the terminal to see how the routes are interpreted.
see http://guides.rubyonrails.org/routing.html#naming-routes for more info (maybe read the whole thing)
Another (probably better) option would be to combine your desired functionality into the index action using params, e.g. .../articles?tagged=true. Then you could use logic to define the #articles variable in the index controller based on params[:tagged]. A simple example might be
def index
if params[:tagged]
#articles = Article.all(:order => 'created_at DESC')
else
Article.paginate :page => params[:page], :per_page => 3
end
#tags = Article.tag_counts_on(:tags)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #articles }
end
end
This is called DRYing up your code (for Don't Repeat Yourself); it would save you the need for code duplication in the articles#tagged action, which would make it easier to understand and maintain your code base.
Hope that helps.

No field configured for Model with name 'image_filename'

I have a Model with 2 atrributes:
:image_filename
:yt_video_id
I have this code in my controller:
def index
#search = Model.solr_search do |s|
s.fulltext params[:search]
s.paginate :page => params[:page], :per_page => 2
s.with(:image_filename || :yt_video_id)
end
#model = #search.results
respond_to do |format|
format.html # index.html.erb
end
end
in my model.rb Model I have this in searchable:
searchable do
string :image_filename, :yt_video_id
end
I want filter :image_filename OR :yt_video_id any are not "nil". I mean, both attributes must have a mandatory value.
but I get the error:
Sunspot::UnrecognizedFieldError in ModelsController#index
No field configured for Model with name 'image_filename'
The problem was fixed with the following steps:
(This solution works fine for me. I hope this solution can help you too.)
In model.rb you can not write this syntax:
searchable do
string :image_filename, :yt_video_id
end
You must write this syntax:
searchable do
string :image_filename
string :yt_video_id
end
In your models_controller.rb in index action:
def index
#search = Model.solr_search do |s|
s.fulltext params[:search]
s.paginate :page => params[:page], :per_page => 2
s.any_of do
without(:image_filename, nil)
without(:yt_video_id, nil)
end
end
#model = #search.results
respond_to do |format|
format.html # index.html.erb
end
end
I have used the any_of method.
To combine scopes using OR semantics, use the any_of method to group restrictions into a disjunction:
Sunspot.search(Post) do
any_of do
with(:expired_at).greater_than(Time.now)
with(:expired_at, nil)
end
end
You can see in https://github.com/sunspot/sunspot/wiki/Scoping-by-attribute-fields

Ordering by Sum from a separate controller part 2

Ok, so I had this working just fine before making a few controller additions and the relocation of some code. I feel like I am missing something really simple here but have spent hours trying to figure out what is going on. Here is the situation.
class Question < ActiveRecord::Base
has_many :sites
end
and
class Sites < ActiveRecord::Base
belongs_to :questions
end
I am trying to display my Sites in order of the sum of the 'like' column in the Sites Table. From my previous StackOverflow question I had this working when the partial was being called in the /views/sites/index.html.erb file. I then moved the partial to being called in the /views/questions/show.html.erb file and it successfully displays the Sites but fails to order them as it did when being called from the Sites view.
I am calling the partial from the /views/questions/show.html.erb file as follows:
<%= render :partial => #question.sites %>
and here is the SitesController#index code
class SitesController < ApplicationController
def index
#sites = #question.sites.all(:select => "sites.*, SUM(likes.like) as like_total",
:joins => "LEFT JOIN likes AS likes ON likes.site_id = sites.id",
:group => "sites.id",
:order => "like_total DESC")
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #sites }
end
end
I think it should be
#sites = #question.sites.all(:select => "sites.*, SUM(likes.like) as like_total",
:joins => "LEFT JOIN likes AS likes ON likes.site_id = sites.id",
:group => "sites.id",
:order => "SUM(likes.like) DESC")
Ah...turns out that I had move the #sites controller code from the SitesController to the QuestionsController Show action. I then had to change my partial in the /views/questions/show.html.erb page from
<%= render :partial => #question.sites %>
to
<%= render :partial => #sites %>

Resources