Grouping Activerecord query by a child attribute - ruby-on-rails

Is it possible to use an attribute of a child to group a query?
Post.find(:all, :include => [ :authors, :comments ], :group=>'authors.city')
does not work.
However, I am able to use author.city as part of the conditions.

The solution is to force the necessary join so that ActiveRecord can resolve "authors.city":
Post.find(:all, :include => [ :author, :comments ], :joins=>"INNER JOIN authors ON posts.author_id=authors.id", :group=>'authors.city')

If that's what you're using, then the syntax is wrong for the :group argument, it should be:
Post.find(:all, :include => [ :author, :comments ], :group=>'authors.city')
Make sure your :author and :comments associations are correct. If 'authors' is the actual table name, then you'll need a 'has_one :author' association in you Post model, and an Author model.
Associations need to be correct, too:
class Post < AR:Base
belongs_to :author
has_many :comments
end
class Author < AR:Base
has_many :posts
end
class Comment < AR:Base
belongs_to :post
end
And the db schema:
posts
id
author_id
authors
id
comments
id
post_id
This will let the query run correctly, however, now I'm getting an error with the results... the :group clause doesn't seem to be applied when :include is used.

Have a look at the query that is generated in your log file - you can often paste the query into your favourite MySQL tool to get a more detailed error.
You might actually need to provide an aggregate function to get the database to group correctly (this happens in MySQL rather than a syntax error sometimes).

Should the author include be pluralized?
Post.find(:all, :include => [ :authors, :comments ], :group=>'authors.city')

Related

N+1 queries in ModelSerializer

Comment.includes(:replies).without_replies
This way I get all the comments. I write API. And I use ActiveModelSerializer`
Comment have a relationship with the user. belongs_to :user
class CommentSerializer < ActiveModel::Serializer
has_many :replies, class_name: 'Comment'
attributes :id,
:user_image_url
def user_image_url
object.user.image_url
end
end
I need to get a picture of the user who left a comment.
Method user_image_url.
It's all good.
But the bullet displays a message.
GET /api/v1/comments?page=1&per_page=20
USE eager loading detected
Comment => [:user]
Add to your finder: :includes => [:user]
Call stack
/app/serializers/comment_serializer.rb:27:in `user_image_url'
I did this. Comment.includes(:replies, :user).without_replies But nothing, why?
Have you tried Comment.includes(:replies, :user).without_replies ?

How to return associated model objects in Rails with ActiveRecord

Let's assume I have the following three objects:
class Filing < ActiveRecord::Base
belongs_to :company
has_many :people , :dependent => :destroy
end
class Company < ActiveRecord::Base
has_many :filings
end
class Person < ActiveRecord::Base
belongs_to :filing
end
I'm attempting to make a single request that returns the filing with it's associated company and an array containing it's associated people. This is being used for an API request of GET filing/:id
I saw the documentation on joining tables with ActiveRecord, however when I run the following query:
Filing.joins(:people,:company)
It doesn't appear to include the associated people or company in the result set. I'm kind of confused about why I would do a join if the associated data won't be returned. What am I missing here? What query should I be running?
Update
As mentioned in the comments. I want to be able to generate the following output:
{ "filing" => { "filing_id" => 123, "company" => { ... }, "people" => [{"person_id" => 1}, {"person_id" => 2}] } }
With the help of commenters I ended up finding the answer. All that needs to be called is:
Filing.find( id , :include => [:company,:people] )
I think what you want is the following:
Filing.includes([:company, :people]).where(:filing => [:id => 756])

Thinking-Sphinx Grouping Error

I have have the meeting model which belongs to the project:
class Project < ActiveRecord::Base
has_many :meetings
end
class Meeting < ActiveRecord::Base
belongs_to :project
define_index do
join project
indexes agenda
indexes project.name. :as => :project_name
end
end
I attempt to search with grouping:
Meeting.search("stuff", :group_by => 'project_id', :group_function => :attr)
I get the following error:
group-by attribute 'project_id' not found
Any suggestions?
Many Thanks.
This is just a wild guess based on the examples in the ThinkingSphinx docs (http://freelancing-god.github.com/ts/en/searching.html#grouping), but perhaps you need to include the attribute to be grouped by in the indexing.
Try adding has project_id to your define_index.

activerecord find through association

I am trying to retrieve an activerecord object from my db. My models are
class User < ActiveRecord::Base
belongs_to :account
has_many :domains, :through => :account
end
And
class Account < ActiveRecord::Base
has_many :domains
has_many :users
end
And
class Domain < ActiveRecord::Base
belongs_to :account
end
Now I would like to retrieve a user based on the username and a domain name (lets assume that these are attributes of the User and the Domain classes respectively). i.e. something along the lines of
User.find(:first, :conditions =>{:username => "Paul", :domains => { :name => "pauls-domain"}})
I know that the above piece of code will not work since I do have to mention something about the domains table. Also, the association between users and domains is a one-to-many (which probably further complicates things).
Any ideas on how should this query be formed?
If you're using Rails 3.x, the following code would get the query result:
User.where(:username => "Paul").includes(:domains).where("domains.name" => "paul-domain").limit(1)
To inspect what happen, you can append .to_sql to above code.
If you're using Rails 2.x, you'd better write the raw sql query.
The following piece of code did the trick:
User.joins(:account).joins('INNER JOIN "domains" ON "accounts"."id" = \
"domains"."account_id"').where(:users => {"username" => "Paul"}).
where(:domains => {"name" => "paul-domain"})
Sorry about the formatting of this long line of code

Rails: Query to get recent items based on the timestamp of a polymorphic association

I have the usual polymorphic associations for comments:
class Book < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class Article < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
I'd like to be able to define Book.recently_commented, and Article.recently_commented based on the created_at timestamp on the comments. Right now I'm looking at a pretty ugly find_by_SQL query to do this with nested selects. It seems as though there must be a better way to do it in Rails without resorting to SQL.
Any ideas? Thanks.
For what it's worth, here's the SQL:
select * from
(select books.*,comments.created_at as comment_date
from books inner join comments on books.id = comments.commentable_id
where comments.commentable_type='Book' order by comment_date desc) as p
group by id order by null;
Sometimes it's just best to add a field to the object of which you are commenting. Like maybe a commented_at field of datetime type. When a comment is made on an object, simply update that value.
While it is possible to use SQL to do it, The commented_at method may prove to be much more scalable.
Not sure what your method has looked like previously but I'd start with:
class Book < ActiveRecord::Base
def self.recently_commented
self.find(:all,
:include => :comments,
:conditions => ['comments.created_at > ?', 5.minutes.ago])
end
end
This should find all the books that have had a comment created on them in the last 5 minutes. (You might want to add a limit too).
I'd also be tempted to create a base class for this functionality to avoid repeating the code:
class Commentable < ActiveRecord::Base
self.abstract_class = true
has_many :comments, :as => :commentable
def self.recently_commented
self.find(:all,
:include => :comments,
:conditions => ['comments.created_at > ?', Time.now - 5.minutes])
end
end
class Book < Commentable
end
class Article < Commentable
end
Also, you might want to look at using a plugin to achieve this. E.g. acts_as_commentable.

Resources