For some reason it seems like .each block iterate only once, when I write lets say 3 or 4 comments, #total_comments displays only 1, instead of 3 or 4.
The relationships are:
user has many posts
post has many comments
Can anybody help please?
controller
#total_comments = 0
#posts = current_user.posts
#posts.each do |post|
#comments = post.comments
#new_comments = #comments.count -#comments.where("created_at < ?",1.day.ago).count
#total_comments += #new_comments
end
view
<%= #total_comments %>
To get the count of all comments you want something like this
#total_comments = Comment.count(
:conditions => ["post.user_id = ? and comment.created_at >= ?",
current_user.id, 1.day.ago],
:include => :post
)
Although without knowing your data model it's difficult to say exactly.
As discussed with #m_x, a neater and more rails-3/ruby 1.9 esque version of above
#total_comments = Comment
.joins( post: :user )
.where( users: {id: current_user.id} )
.where( "created_at < ?", 1.day.ago )
.count
use this instead :
#total_comments = Comment
.joins( post: :user )
.where( users: {id: current_user.id} )
.where( "comments.created_at < ?", 1.day.ago )
.count
EDIT
i definitely need some sleep. as #Ryan pointed out this is much simpler :
#total_comments = current_user.comments.where( "created_at < ?", 1.day.ago ).count
... but the OP has to add this to his User model :
has_many :comments, through: :posts
It looks like you forget to save you comments - some comments are not saved to database that's why you're loosing some of comments.
Also you could use autosave option to automatically save your variables every time when you're changing them.
Related
class Author
has_many :post
end
class Post
belong_to :author
has_many :content
end
class Content
belong_to :post
(column: section)
end
c = Content.select("post_id").where("section like ?", 'foo%')
p = ActiveRecord::Base.connection.select_all(Post.select("title, post_id ").joins(:author).where(:id => c.map(&:post_id)).to_sql)
how to join c and p to become a table-like structure by post_id column ?
just like in SQL:
select * from c,p where c.post_id = q.post_id ;
Thanks a lot.
This code
#posts = Content.find(:all, :include => :post)
will generate SQL as you wish. You can access separately content for each post in each cycle or generate plane table like DB returns performing something like this:
#posts = Content.find(:all, :include => :post).map{|c| c.merge(c.post)}
I have 2 models:
class Mission < ActiveRecord::Base
belongs_to :category
end
class Category < ActiveRecord::Base
has_many :missions
end
And I have a complex Mission find statement:
#missions = Mission.send(#view, level).send(#show).search(#search).paginate :page => params[:page], :order => actual_sort, :per_page => 50
I'd like to add to my query the possibility to search for a specific category too.
I tried this but it does not work:
#missions = Mission.send(#view, level).send(#show).send(:category, #category).search(#search).paginate :page => params[:page], :order => actual_sort, :per_page => 50
Rails says that Mission has not a .category method. How would you solve this?
Thanks,
Augusto
OH ... MY ... GOD
Are you sure this is the best way to be doing this?
I don't think people will be able to help you if you don't explain a bit more, but I highly doubt that you couldn't write your statement like so:
#missions = Mission.select("missions.level ...,category.attr ...").where(["missions.level = ? ...", level ...]).includes(:category).where(["categories.field = ?", ...]).paginate(...)
Obviously the elipses (...) mean generally etc.
This is a working example on one of my projects in testing:
i = Item.where("items.name like '%Coupon%'").includes(:category).where(["categories.name = ? ",'Category 2'])
try performing the where selection on category_id
I am working on a Rails 2.3.9 app and my question involves both a self referencial relationship and a named_scope. This application allows users to log and share workouts. A workout can be public or private and that is designated by #workout.public == 1.
I allow users to 'follow' people. So on a current_user's dashboard I display all public workouts from users that current_user follows with the following code:
/dashboard/index.html.erb
<% current_user.friends_workouts.each do |workout| %>
<%= link_to (workout.title), workout %> <br/>
by <%= link_to (workout.user.username), workout.user %> - <%= time_ago_in_words(workout.created_at)%> ago</p>
<% end %>
user.rb
def friends_workouts
#friends_workouts ||= Workout.current.public_workouts.find_all_by_user_id(self.friends.map(&:id), :order => "created_at DESC", :limit => 3)
end
workout.rb
named_scope :public_workouts, :conditions => {:public => 1 }, :order => "created_at DESC"
I now want to add a condition to this scope as I am adding another level of sharing. Users can associate to a "box" (a gym really) through a "membership" model. So if the current_user belongs_to the same "box" as a user they follow, they should not only see the workouts marked public but also workouts where #workout.box_only == 1.
How can I affect the above to include all public workouts from followed users AND workouts from followed users where #workout.box_only == 1 and #workout.user.membership.box_id == current_user.membership.box_id. I know that syntax is incorrect but you get my point (hopefully).
UPDATE:
It also needs to be considered that :public_workouts is being called from pages that don't require a logged_in? user so in that case if the scope is trying to reference current_user it will throw an error.
UPDATE 2:
:user has_many :memberships
I believe something like the following should do it for you:
named_scope :public_workouts,
:joins => ", user, membership"
:conditions =>
"workouts.public = 1 or
membership.box_id = #{current_user.membership.box_id}",
:group => "workouts.id",
:order => "workouts.created_at DESC"
You would have to play around with this for a bit. The hard part every time I try something like this is to get the OR conditions correct. You want to get all public and those where the joined membership.box_id matches regardless of public being 1.
Edit: Admittedly this is perhaps not the most ruby way of building a query and I haven't tested it properly but something like below could also be made to work.
def self.public_workouts
query = Workout.joins(:user => { :membership })
if current_user
query.where('memberships.box_id = ? or workouts.public = 1', current_user.membership.box_id) unless current_user.membership.box_id.nil?
else
query.where('workouts.public = 1')
end
query.group('workouts.id')
query.order("workouts.created_at DESC")
return query
end
Edit2
Another alternative could be to create two separate scopes and create a class method that combines the two scopes. This class method would then be used in the view.
named_scope :box_workouts,
:joins => ", user, membership"
:conditions => "memberships.box_id = #{current_user.membership.box_id}"
:group => "workouts.id",
:order => "workouts.created_at DESC",
:select "workouts"
named_scope :public_workouts,
:conditions => :public => 1
:order => "workouts.created_at DESC"
def self.public_box_workouts
return box_workouts.merge(public_workouts).limit(3) if current_user
return public_workouts.limit(3)
end
Edit3 Not so hard, I believe something like below will work.
def self.box_and_public_workouts(user)
return public_workouts if user.nil? or user.memberships.blank?
return public_workouts + box_workouts(user.memberships.map(&:box_id))
end
named_scope :box_workouts, lambda { |box_ids| { :conditions => ['box_id IN (?)', box_ids], :order => 'created_at DESC' } }
Apologies for taking so long. I was missing confused with how the "old" way of querying the database. I went right for Rails3 :)
Anyway, I didn't want to commit anything so I tried to fork it to send a pull request but github is being rude to me tonight. Might just copy from here then.
I have read the following rails guide : http://guides.rails.info/active_record_querying.html
in there exemple a client has many orders and orders belong to clients.
They explain how to find a lot of stuff from client. But if i want all orders from yesterday, with the corresponding client name, how do i retrieve the client from an order?
# controller
#orders = Order.all(:include => :client,
:conditions => ["created_at = ?", Date.today-1])
# view
<% #orders.each do |order| %>
<%= order.client.name %>
<% end %>
Edit:
If you have an specific order id, you can do your search like
#order = Order.first(id, :include => :client)
and access the client the same way
#order.client.name
today = Date.today
yesterday = today - 1.days
orders = Order.find(:all, :include => :client, :conditions => ["created_at >= :yesterday AND created_at <= :today", {:yesterday => yesterday, :today => today}])
You can now iterate orders and do order.client to retrieve the Client object. The :include => :client will make RoR automatically include the it in the query (rather than lazy loading).
You can do something like this:
orders = Order.all(:conditions => ["DATE(created_at) = DATE(?)",
:include => :client,
Time.now - 1.day])
client = orders.first.client
In a typical User - Post - Comment model in Rails, every user can create a Post and also can create Comment, question is how to grab every user latest comment on specific post.
Example:
Post A have 3 user making comment
User 1 have comment 1, 2, 3, 4, 5, 6
User 2 have comment 1, 2, 3, 4
User 3 have comment 1, 2
So the view I want is just the latest comment for every user:
Post A have 3 user making comment
User 1 latest comment that is 6
User 2 latest comment that is 4
user 3 latest comment that is 2
How to do it ?
thanks
Something like this:
post.comments.for_user(current_user).last
add a named_scope in your model
class Comment
named_scope :for_user, lambda{ |user| {:conditions=>{:user_id => user.id}}
end
That should do the trick.
If you rather do it in rails,
messages_by_users = post.messages.group_by(&:user)
messages_by_users.each do |key, value|
messages_by_users[key] = value.last
end
I have had to get this kind of data and usually I end up doing two queries. In my case I have Blogs and their Posts and I wanted a list of the 3 most recent blog posts with the restriction that the blogs are unique, I dont want 2 posts from the same blog. I ended up doing something like this (MySQL):
q = <<-EOQ
SELECT id,pub_date FROM
(
SELECT id,blog_id,pub_date
FROM posts
ORDER BY pub_date DESC
LIMIT 40
)
t
GROUP BY blog_id
ORDER BY pub_date DESC
LIMIT #{num_posts}
EOQ
post_ids = Post.connection.select_values(q)
Post.find(:all, :include => [:blog], :conditions => ["id IN (?)", post_ids], :order => "posts.pub_date DESC")
So in your case you might have something like:
q = <<-EOQ
SELECT id FROM
(
SELECT id,post_id
FROM comments
ORDER BY id DESC
LIMIT 40
)
t
GROUP BY post_id
ORDER BY id DESC
LIMIT 10
EOQ
post_ids = Post.connection.select_values(q)
Post.find(:all, :include => [:blog], :conditions => ["id IN (?)", post_ids], :order => "posts.id DESC")
Assuming that your database is assigning sequential IDs to the comments, you can do this:
class Comment
named_scope :most_recent, lambda {
lastest_comments = Comment.maximum :id, :group => "user_id, post_id"
{ :conditions => [ "comment_id in ?", lastest_comments.map(&:last) ] }
}
end
This gives you a two-query method that you can use in a variety of ways. The named_scope above pulls back the most recent comments for all users on all posts. This might be a problem if your database is gigantic, but you can certainly add conditions to make it more specific.
As it stands, it is a flexible method that allows you to do the following:
Comment.most_recent.find_by_user #user #-> the most recent comments on all posts by a user
#user.comments.most_recent #-> same as above
Comment.most_recent.find_by_post #post #-> the most recent comments on a single post by all users
#post.comments.most_recent #-> same as above
Comment.most_recent.find_by_user_and_post #user, #post #-> the specific most recent comment by a certain user on a certain post
#post.comments.most_recent.find_by_user #user #-> you get the idea