Ordering by Sum from a separate controller part 2 - ruby-on-rails

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 %>

Related

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.

Thinking Sphinx: search across multiple models: best practices?

I want to add a jquery autocomplete with categories.
The request will search across multiples models (Forum topics, news, users...) with Thinking Sphinx
So in controller, I think it will look like that
def autocomplete
#news = Actu.search(params[:term]).map {|g| {:label => g.title, :category => "Actualités", :id => g.id}}
#topics = Topic.search(params[:term]).map {|g| {:label => g.title, :category => "Topics", :id => g.id}}
#anotherModel = ...
respond_to do |format|
format.js { render :json => #news+#topics+#anotherModel }
end
end
That working, but what do you think about these practice ?
You can try this awesome syntax
ThinkingSphinx.search 'pancakes', :classes => [Article, Comment]
Read more at http://freelancing-god.github.com/ts/en/searching.html
You can search across all indexed models in your application:
ThinkingSphinx.search(params[:term])
Then you can define for each model method, say autocomplete_json, that returns hash.
So, your action
def autocomplete
render :json => ThinkingSphinx.search(params[:term]).map(&:autocomplete_json)
end

Messaging in Rails 3

I've been setting up a user to user messaging system using this rails tutorial http://www.novawave.net/public/rails_messaging_tutorial.html
I know its pretty old but I haven't really had a problem tweaking it to work now. My only problem is that the inbox is not displaying and the error that appears is "Couldn't find Folder without an ID" I'm not sure what I should do. My code is pretty much the same, besides some tweaks, with the code in that link until right before reply. Thats where I stopped.
My Folder Model looks like
class Folder < ActiveRecord::Base
acts_as_tree
belongs_to :user
has_many :messages, :class_name => "MessageCopy"
end
My Mailbox controller looks like
class MailboxController < ApplicationController
def index
redirect_to new_session_path and return unless signed_in?
#folder = current_user.inbox
show
render :action => "show"
end
def show
#folder ||= current_user.folders.find(params[:id])
#messages = #folder.messages.paginate :per_page => 10, :page => params[:page], :include => :message, :order => "messages.created_at DESC"
end
end
If any other code needs to be included let me know.
It looks like when you call show from within the index action that #folder is not set and so it calls current_user.folders.find(params[:id]) but because of the way you have called it params[:id] is nil.
This would cause an exception.
I suggest instead to change your index action to look like this:
def index
redirect_to new_session_path and return unless signed_in?
#folder = current_user.inbox
redirect_to :action => :show, :id => #folder.id
end
Instead of rendering the show action from within the index action, just redirect to the show method with the correct id parameter.

How to KISS and smart this method

I have an action in my RoR application, and it calls a different script depending on the user running it.
def index
#user = User.find(session[:user_id], :include => [ :balances, :links, :comments ])
render :file => "#{RAILS_ROOT}/app/views/user/index_#{#user.class.to_s.downcase}.html.erb"
end
How to make the call to render a more elegant and simple?
Try:
render :template => "user/index_%s" % #user.class.to_s.downcase
You can make it a partial (index_whatever.html.erb --> _index_whatever.html.erb) and it would look like this:
def index
#user = User.find(session[:user_id], :include => [ :balances, :links, :comments ])
render :partial => "index_#{#user.class.to_s.downcase}"
end
Also, what I would do is add a method in the user model, like this:
def view
"index_#{class.to_s.downcase}"
end
So your index action would be:
def index
#user = User.find(session[:user_id], :include => [ :balances, :links, :comments ])
render :partial => #user.view
end

How to use will_paginate with a nested resource in 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|
%>

Resources