rails params[:month] stripping leading zeros causing incorrect match - sql

In my application when a user visits finances/trends/2014/03 a select query is executed in my trends_controller
#expenses = Expense.select("name, amount, id, created_at").where(:user_id => current_user.id).where(["strftime('%Y', created_at) = ? AND strftime('%m', created_at) = ?", params[:year], params[:month] ])
#expenses_by_month = #expenses.group_by { |expense| expense.created_at.beginning_of_month }
and if the query returns results, the page is rendered, otherwise a redirect occurs. This all seems to work fine.
The problem occurs when I attempt to pass the params[:month] into a link on my index page, and the leading zero in the :month seems to get stripped, so the link will return a path such as finances/trends/2014/3 instead of the required finances/trends/2014/03 for the select statement (because in the db, the created_at value is stored as 2014-03-day, of course).
routes:
get "finances/trends/:year/:month" => "trends#month", :as => :month_trends
index.html.erb:
<% #expenses_by_month.each do |month, expenses| %>
<%= link_to "#{month.strftime('%B')}", month_trends_path(:year => month.year, :month => month.month) %>
<% end %>
I understand that the %m in the select statement should return the month as a padded value, so I'm not sure at all what is causing this.

Try some direct ruby way, if that works. Here is how
"3".rjust(2,"0") #=> 03
"3".ljust(2,"0") #=> 30
month=3
month.to_s.rjust(2,"0") #=> 03

Related

How to get number of items in a grouped row in Ruby on Rails?

I am finishing up my first RoR project, and am working on a leaderboard system that shows the number of points users have accrued for correctly answering quiz questions.
I am getting all of the users that have answered at least one question correct, grouping them by user_id, and displaying them in descending order by most correct using this:
#users = Point.find(:all,
:group => 'user_id',
:order => 'correct DESC', :conditions => { :correct => "yes"})
In my view, I am using this to iterate through the results:
<% #users.each_with_index do |user, index| %>
However, I am not able to get the number of correct answers per user. I tried:
user.count
but that doesn't work. How do I get the number of items per group?
You're on the right track. Seems like you would be better off using the all command with the count condition within it as opposed to the count command. Something like this:
Point.all(:select => 'user_id, count(id) as point_count', :group => :user_id, :conditions => { :correct => 'yes' }, :order => 'point_count desc', :limit => 10)
This will return 10 limited Point objects with a user_id attribute (so you can still access the user relationship), and a point_count attribute with the number of correct points said user has obtained.
Note: you could change the limit to be however many users you wanted to display in your leaderboard. This example would return 10.
It might make more sense to have your code look like this:
#points = Point.all(:select => 'user_id, count(id) as point_count', :group => :user_id, :conditions => { :correct => 'yes' }, :order => 'point_count desc', :limit => 10)
And as I said in a comment below, you could iterate through them by doing something like this (this would assume that your User model has a name attribute):
<table>
<% #points.each do |point| %>
<tr>
<td><%= point.user.name %></td>
<td><%= point.point_count %></td>
</tr>
<% end %>
</table>
I think the problem may be that you think you're getting an Array back, but you actually get a Hash back.
Try doing:
p #users
(which is equivalent to puts #users.inspect). You'll probably see it's more so something like:
{ "1" => [UserObject, UserObject], "2" => `[UserObject] }
You can even do p #users.class and you'll see it's not an array.
When you loop with a .each_with_index on a Hash, you need to do:
#users.each_with_index do |(key, value), index|
Then you can do #users[key].count or value.count.
Figured out how to get the correct count:
#users = Point.count(:group => :user_id, :conditions => { :correct => "yes"})
The most simple way should be:
#user.points.where(:correct => "yes").count
Though this will only work if have defined your associations in the user and point model like
class User < ActiveRecord::Base
has_many :points
class Point < ActiveRecord::Base
belongs_to :user
(personally I would have used a bool flag (smallint) instead of string for the "correct" column.

calendar_helper cannot be used with raw()

I'm using calendar_helper with success using this code:
<%=
calendar({:year => Date.today.year, :month => Date.today.month}) do |d|
cell_text = "#{d.mday}"
cell_attrs = {:class => 'day'}
#events.each do |e|
if e.start_at.mday == d.mday
cell_text << link_to( e.name, :action => 'show', :id => e ) << "<br />"
cell_attrs[:class] = 'specialDay'
end
end
[cell_text, cell_attrs]
end
%>
This gives me the correct html, with events falling on this month's days being outputed correctly. However, this gives me the escaped code, so i need to pass it trough raw.
As soon as i pass it trough raw though, i lose the details on the calendar (events) and get only the calendar itself.
Any idea why this is happening or how to circumvent it?
I put the work I needed to do in a helper method and passed day and my collection (like your #events) to the helper method. It worked fine without a call to raw and left the view code much cleaner.

Rails filtering with acts_as_taggable gem

I am working the acts-as-taggable-on gem and have a question about how to filter down search results based on tags users select. Here's an abridged look at my controller:
class PhotosController < ApplicationController
def index
#photos = Photo.where(["created_at > ? AND is_approved = ?", 1.months.ago, true])
#tags = ["Animals", "Architecture", "Cars", "Flowers", "Food/Drink", "General", "Landscape", "Mountains", "Nature"]
end
def search_by_tag(tag)
#photos = Photo.where('tagged_with LIKE ?', tag)
end
end
Photos/index
<% #tags.each do |tag| %>
<%= link_to tag, {:search_by_tag => tag}, :class => "tag" %>
<% end %>
This lists out all of the tags from the hash #tags defined in index, but clicking them doesn't actually filter anything down. Here's a look at what clicking one of those links produces in the log:
Started GET "/photos?search_by_tag=Animals" for 127.0.0.1 at Sun Oct 09 17:11:09 -0400 2011
Processing by PhotosController#index as HTML
Parameters: {"search_by_tag"=>"Animals"}
SQL (0.5ms) SELECT name FROM sqlite_master WHERE type = 'table' AND NOT name = 'sqlite_sequence'
The result I want is for the page to display only Photos that are tagged_with whichever tag was clicked on. I can't quite figure out how to accomplish this.
(Side-question: I can't seem to find a way to list out all of the tags from the tags table that acts-as-taggable-on generated. Doing something like Photo.tagged_with or Photo.tags doesn't work. I am able to see the "tags" table the gem created, and the entries inside of it; I'm just not really clear how to handle that using this gem)
Any thoughts greatly appreciated.
UPDATE
I've updated my code and am a bit closer.
class PhotosController < ApplicationController
def search_by_tag
#photos = Photo.tagged_with(params[:tag_name])
end
photos/index
<% Photo.tag_counts_on(:tags).map(&:name).each do |tag| %>
<%= link_to tag, {:action => 'search_by_tag', :tag_name => tag}, :class => "tag" %>
<% end %>
I believe this is closer, but still working through this...
You have a number of errors in your code:
Your link_to call is actually calling the index action.
Your search_by_tag method is expecting an argument, where it should be using the params hash to access the parameters passed to it in the web request.
tagged_with is a class method added by acts_as_taggable_on, not a field in your table - therefore you can't use it in the where method like you have done.
Finally, to get all the tag names: Photo.tag_counts_on(:tags_or_whatever_you_tagged_on).map(&:name)
Take a look at the acts_as_taggable_on documentation and you'll see examples of how to use tag_counts_on and tagged_with.
As for the Rails things: http://guides.rubyonrails.org/ http://railsforzombies.org/ and/or http://railscasts.com/

Month pagination with kaminari

I want to paginate posts by month so I added following scope in Post model
class Post
include Mongoid::Document
include Mongoid::Timestamps
scope :by_month, lambda {|end_date| Post.order_by(:created_at => :asc).where(:created_at.gte => (end_date.to_date.beginning_of_month), :created_at.lte => (end_date.to_date))}
end
In my controller I put
def show
#posts = Post.by_month(Time.now).page(params[:page]).per(20)
end
In view
<%= paginate #posts, :theme => 'month_theme' %>
<%= render #posts %>
Problems:
pagination is not working by month, I want to show all result of a month in a page, replacing params[:page] by params[:month]=2 or params[:month]=Feb
How do I view 'August 2011' instead of 1,2
Loop month and year like when you goto previous while in 'Jan 2011' it will goto 'Dec 2010'
I suppose this is not really a matter of pagination. Dealing with the params[:month] value for the query is something different from the page offset switching. You might not need a pagination library for that.
How about simply creating those links like this?
controller:
#posts = Post.by_month(Time.parse(params[:month]) || Time.now)
view:
<% Post.only(:created_at).map {|p| p.created_at.to_date.beginning_of_month}.uniq.sort.each do |m| -%>
<%= link_to_unless_current m, :month => m %>
<% end -%>
Of course you can combine this query with normal pagination if needed. But the pagination links should not be mixed with the month links in that case.

Group by Distance in Rails/SQL?

Is it possible to group by distance using the geokit-rails gem for ActiveRecord?
Say I have 10,000 users and I want to know how many are 1 mile, 2 miles... 100 miles from a point. How can I do that in as few queries as possible?
Doing something like this kills performance obviously:
(1..100).map { |i| User.count(:within => i, :origin => location) }
Is there someway to do:
User.count(:within => 100, :origin => location, :group => "distance / 100") # some sort of math perhaps
Any point in the right direction would be awesome! Some sort of way to chunk the records in one db call by a range.
I think the following db call will do what you ask for:
result = User.all(:select => "ROUND(distance / 100) AS distance, COUNT(*) AS user_count",
:group => "ROUND(id / 100)")
Since this will not load an actual user instance, you have to specify in the select what data you want to access. Then you can loop through the result like this:
<% result.each do |group| %>
<p>Distance: <%= group.distance %>, Number of users: <%= group.user_count %></p>
<% end %>