Active Record select field on included sub query - ruby-on-rails

I have some sql that I am trying to convert to ActiveRecord
The sql looks like
select type.name, sum(order.sub_total)
from orders order
join order_types type on type.id = order_type_id
group by type.name
I have this mostly working except that I cannot figure out how to select type.name
Order.
select("sum(sub_total)").
joins(:order_type).
group("order_type_id`")
I'm thinking it should be something like:
Order.
select("order_type.name, sum(sub_total)").
joins(:order_type).
group("order_type_id`")
but it's not aware of what order_type.name is in this context so this fails.
Anyone know how I can do this in a way that still feels "railsy"

This worked for me:
Order.
select("order_types.name, sum(orders.sub_total).
joins(:order_type).
group("order_types.name")

You can do this:
grouped_orders = Order.select("order_types.name name, sum(orders.sub_total) sub_total")
.joins(:order_type)
.group("order_types.name")
And then, you can list the order names like this:
grouped_orders.map(&:name)

Related

Rails Query Unique Items

I have a search bar which works fine but it produces a duplicate every time it shows the correct result.
if params[:nav_search]
#art = Art.where(["style_number LIKE ? OR name LIKE ?", "%#{params[:nav_search]}%", "%#{params[:nav_search]}%"]).page(params[:page]).per_page(18)
end
Any clue where I'm going wrong?
Try to the following
#art = Art.where(["style_number LIKE ? OR name LIKE ?", "%#{params[:nav_search]}%", "%#{params[:nav_search]}%"]).distinct.page(params[:page]).per_page(18)
To retrieve objects from the database, Active Record provides several finder methods. Each finder method allows you to pass arguments into it to perform certain queries on your database without writing raw SQL.
You can see this Rails Guide for very well understand
include .uniq
try this,
if params[:nav_search]
#art = Art.where(["style_number LIKE ? OR name LIKE ?", "%#{params[:nav_search]}%", "%#{params[:nav_search]}%"]).uniq.page(params[:page]).per_page(18)
end
Use uniq or distinct to avoid duplicate records. In your case, you should use distinct:
if params[:nav_search]
#art = Art.where(["style_number LIKE ? OR name LIKE ?", "%#{params[:nav_search]}%", "%#{params[:nav_search]}%"]).distinct.page(params[:page]).per_page(18)
end

Rails: Search for substring without getting SQL Injected

I'm trying to implement auto complete for Rails. I have something like the following in my code -
Location.where("name like ?", "%#{params[:location]}%")
I'm afraid this would lead to SQL injection. Something like the following -
SELECT * FROM Locations WHERE (name LIKE '%green%') OR 1=1--%'
When params[:location] is something like this green%') OR 1=1--
Is there any way, I can avoid SQLi for substring based search in Rails?
Dave is right. Try it and see what it outputs. It wraps the whole thing up as part of the condition. In my Courses model.
> x = "'') OR SELECT * FROM Users"
=> "'') OR SELECT * FROM Users"
> Course.where(["name like ?", "%#{x}%"])
Course Load (38.7ms) SELECT "courses".* FROM "courses" WHERE
(name like '%'''') OR SELECT * FROM Users%')
=> []
If you're using Postgres, I would suggest using trigram support in Postgres to do this.
Throw this in a migration to get things set up:
CREATE EXTENSION pg_trgm;
then run your query like this:
Location.select('*', "similarity(search_term, #{ActiveRecord::Base.sanitize(search_term)}) AS similarity").order('similarity DESC, search_term')
or, just do what you're doing but wrap the param in #{ActiveRecord::Base.sanitize(search_term)}

Rails sort columns by column name in another table

I'm using handles_sortable_columns to sort my columns in Rails 3 and was wondering if there is a way to sort by a column in another table other than using a join.
I have a column that is a lookup of the name of a column in another table.
That is, I have cities.country_id as a column and in the View template I do:
#cities.each do |city|
city.country.name
to display the name.
I would like to be able to sort by this column, but the countries.name, not the cities.country_id.
Does anyone know if this possible with the gem or any other simple way? If so how?
The only thing I can think of is to do an IF statement in the controller and catch the sorting by country and then run a different query using a join for that, but that's ugly and error-prone, was hoping for something more elegant.
Thanks.
Can you override to the to_s on the country model to return the name, then sort by that in the controller?
In your country model override to_s by:
def to_s
country.name
end
Then in your controller
#sorted_cities = #cities.sort_by { |obj| obj.country.to_s }
in addition to Webjedi answer..
#sorted_cities = #cities.includes(:country).sort_by { |obj| obj.country.to_s } #for eager loading
In the end I decided to use a join to get the right data to begin with. While Webjedi's answer is quite intriguing I didn't want to override any built-in functions, but it's good to know I can do that.
The code looks like this:
#countries = Country.select('countries.*, continents.name AS continent_name').joins{continent}.search(params[:term]).order(order).page(params[:page])

Change default finder select statement in Rails 3.1

I'd like to change the default statement that ActiveRecord uses to query a model's table. By default, it queries a table "cables" for example by...
this_cable = Cable.first
results in
SELECT "cables".* FROM "cables" LIMIT 1
I would like to find a way for it to wind up with
SELECT *,askml(wkb_geometry) as kml FROM "cables" LIMIT 1
This way i can call a database function and have that behave like a field on the object.
this_cable.kml
=> "<LineString><coordinates>-73.976879999999994,40.674999999999997 -73.977029999999999,40.674779999999998 -73.977170000000001,40.674770000000002 -73.97775,40.67501</coordinates></LineString>"
This can be accomplished by adding a scope
scope :with_kml, "*,askml(wkb_geometry) as kml"
But I figure that's kind of messy. I would like this "kml" column to always be there, without having to call the "with_kml" scope.
Any ideas?
Have you tried using default_scope for this, or do you actually want this to be present on all your models?
Something like this might solve your problem:
default_scope select("*, askml(wkb_geometry) as kml")
You might want to change that to cables.* for it to work properly with joins and such, though.

How to get table column value?

I write follow code to get one record from the table webeehs:
webeehs_result = Webeeh.find(:all, :conditions=>["webeeh_project_id=#{project_id}"])
Then I want to get one column value from this record, how could I do?
For example, the column name is webeeh_date.
first of all, never EVER write code like that. Building your own conditions as pure strings can leave you vulnerable to SQL injection exploits. If you must do conditions, then do it like this:
:conditions => ["webeeh_project_id = ?", project_id]
if you have a Project model, you should rename the webeeh_project_id column from your Webeeh model into project_id and have an association in your Project model like has_many :webeehs
Then, you won't need to call that find anymore, just do a p = Project.find(id) and then p.webeehs will return the webeehs you need.
the result will be an array which you can iterate through. And to get your webeeh.webeeh_date member, just call it like this:
result.each do |webeeh|
date = webeeh.webeeh_date
end
webeehs_result = Webeeh.findwebeeh_dates
is enough to get all columnn values.
For a different method and performance issues check the following: http://www.stopdropandrew.com/2010/01/28/finding-ids-fast-with-active-record.html
webeeh_result will usually be an array of results for the database.
You can iterate throughit using
webeehs_result.each do |webeeh|
# use "webeeh.webeeh_date" to access the column_name or do whatever you want with it.
end

Resources