active record query conflict between :joins and :includes - mysql

Can anyone suggest an easy fix for the query below?
Workout.all(:joins => [:person, :schedule],
:conditions => ["schedule.id = ? AND people.gym_id = ?", schedule.id, gym.id ],
:order => "time DESC",
:include => [:person]),
Error message says Mysql::Error: Not unique table/alias: 'people': and then a very long sql query
When I remove :person from the :include options, the code works fine. However, then I get the "n+1 queries" problem: when I display the workouts, it generates a separate query for each person.
I am assuming that the 'people' tables from the join and include options conflict in the generated SQL. Is there a way to alias tables with active record using the find options? Or do I need to use a sql fragment for the :joins option so that I can alias the tables with AS?
I have not upgraded this app to 3.0 yet, so I can't use the "Class.joins().where()" syntax.

You can remove :person from the joins and keep it in the include, you can add fields from the people table in the :select option e.g
Workout.all(:joins => [:schedule],
:conditions => ["schedule.id = ? AND people.gym_id = ?", schedule.id, gym.id ],
:order => "time DESC",
:select => "workouts.*,people.*"
:include => [:person])

Related

Wildcard search with Thinking Sphinx issue with indexes

define_index do
indexes :first_name, :prefixes => true
indexes :last_name, :prefixes => true
indexes :email, :prefixes => true
set_property :enable_star => 1
set_property :min_perfix_len => 1
end
In this case if i what to search for only email then it will search from all the indexes that are specified.
EG:
email ="*me*"
Contact.search email
Displayed from first_name,last_name and email.
But it should display from only email
What would be solution for searching only one index from the specified indexes.
Just a quick correction - you want to search on a specific field, not a specific index.
And Thinking Sphinx can do this by using the :conditions option - so give the following a try:
Contact.search :conditions => {:email => '*me*'}
Thinking Sphinx can also automatically add wildcards to both ends of each word you give it as well:
Contact.search :conditions => {:email => 'me'}, :star => true

Rails activerecord order by field in related table

I have a typical forum style app. There is a Topics model which has_many Posts.
What I want to do using Rails 2.3.x is query the topics table and sort by the most recent post in that topic.
#topics = Topic.paginate :page => params[:page], :per_page => 25,
:include => :posts, :order => 'HELP'
I'm sure this is a simple one but no joy with Google. Thanks.
Sorting on a joined column is probably a bad idea and will take an enormous amount of time to run in many situations. What would be better is to twiddle a special date field on the Topic model when a new Post is created:
class Post < ActiveRecord::Base
after_create :update_topic_activity_at
protected
def update_topic_activity_at
Topic.update_all({ :activity_at => Time.now }, { :id => self.topic_id})
end
end
Then you can easily sort on the activity_at column as required.
When adding this column you can always populate the initial activity_at with the highest posting time if you have existing data to migrate.

problem with ActiveRecord/Rails ordering of query data from MySQL -- no problem in SQLite

I have the following two ActiveRecord queries in an application_helper.rb file:
#left_menu = Page.select('id, menu_name').where(:published => true, :left_menu => true).order("sort")
Also can be written as:
#left_menu = Page.select('id, menu_name').where(:published => true, :left_menu => true).order("'sort' ASC")
and:
#left_menu = Page.find(:all, :conditions => {:published => true, :left_menu => true}, :order => :sort)
Why does the first one fail to sort on the 'sort' column, while the second one does not? Both work in SQLite, but only the second one works in MySQL.
Any ideas?
it's the quote in ther order params .
the query generated will be (similar to)
"SELECT id, title FROM `pages` WHERE (`pages`.`pub` = 1) ORDER BY 'sort' ASC"
its the char ' quote . It's wrong sql syntax , it's going to order by costant value not column value . sqlite allow it , mysql not.
try to simple use
Page.select('id, menu_name').where(:published => true, :left_menu => true).order("sort ASC")
without single quote in the order chain method parameters.
sorry for my english.
have a nice day

Sorting a Rails database table by a column in an associated model

I'm trying to implement Ryan Bates' sortable table columns code (Railscast #228) but I'd like to be able to sort on an associated column. In particular, I have the following models and associations:
class Project < ActiveRecord::Base
belongs_to :program_manager, :class_name => "User"
class User < ActiveRecord::Base
has_many :program_manager_projects, :class_name => "Project", :foreign_key => "program_manager_id"
The association between the Project model and the User model is mediated by the 'program_manager_id' foreign key, which the user sets in the new/edit views using a collection-select dropdown. Here's part of the annotation at the top of project.rb:
# Table name: projects
# program_manager_id :integer
I want to be able to sort my list of projects in the index view by the program manager's name, i.e., by project.program_manager.name.
Ideally, I'd be able to point :order to this name somehow, perhaps with something like this in the index method of my ProjectsController:
#projects = Project.find(:all, :order => project.program_manager.name)
But that obviously won't work (not to mention Ryan's routine implements this with a specific reference to table names from the model to be sorted.)
I've come across some intimidating approaches that use named_scope, such as:
named_scope :most_active, :select => "questions.*", :joins => "left join comments as comments_for_count on comments_for_count.question.id = questions.id", :group => "questions.id", :order => "count(questions.id) desc"
But given my lack of MySQL expertise, this is fairly impenetrable to me.
Can anyone help me either generalize the named_scope example above for my specific case, or point me to a more straightforward strategy?
Thanks very much,
Dean
Let's dissect that named scope you referenced above. Imagine a model Question which has many Comments.
named_scope :most_active, :select => "questions.*", :joins => "left join comments as comments_for_count on comments_for_count.question.id = questions.id", :group => "questions.id", :order => "count(questions.id) desc"
:most_active
the name of your scope. You would reference thusly: Question.find(:all).most_active
:select => "questions.*"
by default scopes selects all columns from your table anyway, so this limits the results to only the questions table, and not the comments table. This is optional.
:joins => "left join comments as comments_for_count on comments_for_count.question.id = questions.id"
this is saying for every question, I also want to get all comments associated with them. The comments table has a column 'question_id' which is what we'll be using to match them up to the appropriate question record. This is important. It allows us access to fields that are not on our model!
:group => "questions.id"
This is required for the count() function in the order clause to tell us that we want the count of comments based on question. We don't need the count function in our order clause, so we also don't need this group statement
:order => "count(questions.id) desc"
Return the results in order of number of comments, highest to lowest.
So for our example, discarding what we don't need, and applying to your needs, we end up with:
:named_scope :by_program_manager_name, :joins => "left join users on projects.program_manager_id = users.id", :order => "users.name"
This named_scope would be called thusly:
Project.find(:all).by_program_manager_name
Note this is basically equivalent to:
Project.find(:all, :joins => "left join users on projects.program_manager_id = users.id", :order => "users.name")
But, as cam referenced above, you should really know the underlying SQL. Your abilities will be severely hampered without this understanding

Use :include statement to find records

I'm working on Ruby On Rails 2.3.2 and I'm learning how to use the :include statement.
I'd like to get all the announcements order by their rate. I've got two models and tables for that: Announcement and Rate.
The models look like this:
class Announcement <
ActiveRecord::Base
belongs_to :rate
end
class Rate < ActiveRecord::Base
belongs_to :announcement
end
I'd like to do something like the following, but using :include statement.
Announcement.find_by_sql 'select * from announcements ann inner join rates r on ann.id = r.announcement_id order by r.average DESC'
I already tried this:
Announcement.paginate :page => params[:page], :per_page => 10, :include => [:rates], :order => 'rates.average DESC'
but it's trying to associate rates.id = announcements.id, instead of rates.announcement_id = announcement_id
How can I specify the correct relationship to make this work?
As Yuri points out in the comments, you have incorrectly defined your relationship.
Announcements should have_one :rate
As a named scope on announcment:
class Announcement < ActiveRecord::Base
has_one :rate
named_scope :order_by_rate, :include => :rate, :order => 'rates.average DESC'
end
Announcement.order_by_rate.paginate :per_page => 10, :page => params[:page]
Note the difference between :include and :joins as a find option. :joins will join the on the association(s) or SQL JOIN fragment given for purposes of complex WHERE/ORDER clauses. :include will only works on associations, it provides the same advantages of :joins, and also eager load the association.
Where eager loading makes a difference:
With include, #a.rate is populated in the same SQL statement that populates #a.
#a = Association.first :include => :rate
Without include #a.rate is not populated until required.
#a = Association.first
#a.rate #=> #a.rate is populated here, with a separate SQL statement.