Rails basic search and PostgreSQL - ruby-on-rails

I'm trying to create basic search in my web app. Here's code of search function.
def self.search(title, category_id, city_id)
if title || category_id || city_id
joins(:category).where('title LIKE (?) AND category.category_id IN (?) AND city.city_id IN (?)', "%#{title}%", "%#{category_id}%", "%#{city_id}%")
else
scoped
end
end
I have these associations in my model:
has_one :category
has_one :city
And I get this error
ActionView::Template::Error (PG::Error: ERROR: missing FROM-clause entry for ta
ble "category"
LINE 1: ..._id" = "events"."id" WHERE (title LIKE ('%%') AND category.c...
I'm using PostgreSQL. What I can do to remove this error?

The form of joins that you're using wants the association name, the SQL wants the table name. The table should be called categories.
A few other things:
I don't see you joining :city anywhere so your next error will be "Missing FROM-clause entry for table "city". The solution will be to .joins(:city) and use cities in the where. But keep reading anyway.
You don't need the parentheses around the value for LIKE, just title LIKE ? is fine.
You're using IN expressions for the category and city but you're giving them LIKE patterns and that won't work: the IDs will be numbers and you can use LIKE with numbers. If you're using IN then you'll usually want to supply a list of possible values, if you only want to match one value then just use = and a single value for the placeholder.
The categories table probably doesn't have a category_id column, similarly for the cities table and city_id column. Those two columns should be in your model's table.
Searching for a title when you don't have a title doesn't make much sense. Similarly for country and city.
That looks like a lot of problems but they can be fixed without too much effort:
def self.search(title, category_id, city_id)
rel = scoped
rel = rel.where('title like ?', "%#{title}%") if(title)
rel = rel.where('category_id = ?', category_id) if(category_id)
rel = rel.where('city_id = ?', city_id) if(city_id)
rel
end
and you don't even need joins or explicit table names at all.

Related

How to have search functionality on association models as well

By using a railscast video i create a simple search that works on same model. But now i have a model that shows associated model data as well and i would like to search on them as well.
Right now i managed to make it semi work, but i assume i have conflict if i add the field "name" into the joins as i have two models that have a column named "name"
def self.search(search)
if search
key = "'%#{search}%'"
columns = %w{ city station venue area country plate_number }
joins(:services).joins(:washer).joins(:location).where(columns.map {|c| "#{c} ILIKE #{key}" }.join(' OR '))
else
where(nil)
end
end
What do i need to change to be sure i can search across all columns?
I think when you have ambiguous field name after join then you can mention table_name.field_name so it remove the ambiguity and works. something like.
joins(:services).joins(:washer).where("services.name = ? or washer.name = ?", "test", "test")

rails 3 order by another models column

I have 2 models in my Rails 3 app which I use to describe people and where they live
Unfortunately I set these up without using associations
The 2 tables are setup like this
People
id
name
location_id
Locations
id
name
what I want to do is list all entries in the Peoples table ordered by Locations.name alphabetically and People.name alphabetically
I can do a simple sort using this code which groups each person by a location but I need to drill into the Locations table as well
#people = People.all(:order => '"location_id" ASC, "name" ASC')
Anyone have any idea?
Also is it a good idea to set up an association in the People class to say location_id is Locations.id
Add
belongs_to :location
To the People class
Then you can query the following way:
#people = People.joins(:location).order("locations.name ASC, people.name ASC")

Rails- Merge a find with 2 models

I want to build a rails request with 2 models.
I think it's quite simple, but I don't want to do a loop myself.
I'm in my country model:
def self.find_for_user(user_id)
wines = Wine.where("user_id = ?", user_id).group(:country_id)
where("countries.id IN ?", wines.map())
end
I want to get all countries depending the first request (the wines grouped by countries, I just need the countries)
I think I can do this in a single line where I put map() or another instruction. I just need to get all country_id fields for wines.
Thanks.
Assuming that you've got an association set up between wines and country (ie. has_many :wines in country.rb), I think this is what you're looking for:
def self.find_for_user(user_id)
joins(:wines).where('wines.user_id = ?', user_id).uniq
end
If all you want is all countries that have wine for a specific user, you can do that in SQL:
where("countries.id in (select country_id from wines where wines.user_id = ?)", user_id)

IF/CASE statement OR MySQL OR array for get category name

On my site I got entries which have category. Site have only 5 categories, so I have dilemma:
Make relationship between category table and entries (category_id) table
OR
Make method which return category name via IF/CASE statement? Like:
case #entry.category.id
when 1
"Games"
when 2
"Movies"
when 3
"Fun"
[...]
end
(I remind that I must get 10 category name per page)
OR
Use array:
cat[1] = "Games"
cat[2] = "Movies"
cat[3] = "Fun"
[...]
<%= cat[#entry.category.id] %>
I think this relation definitely belongs into the database. (adding a category table)
it is the most sane and most scalable option.
It is also the cleanest, because you break the seperation of data, display and logic (MVC: model, view, controller) when hardcoding the categories in your application.
you can easily select the item AND its category with a single query:
SELECT item.*, category.name
FROM item
LEFT JOIN category ON category.id = item.category_id
WHERE some=condition
there are similar queries for INSERTs and UPDATEs (at least in MySQL), so you never need a second query.
If the only thing you care about category is "name", then you should just store the category_name in the entries table.
OR
Make a constant CATEGORY_NAME and wrapper method to get the name with id in the entries table (without using Category table/model at all). eg.,
class Entry
CATEGORY_NAME = [ "Games", "Movies", "Fun"]
def category_name
CATEGORY_NAME[cat_id] #cat_id being just 0,1,2 .. depends how you want to store
end
...
I am sure there are many ways to achieve this anyway.
Hope it helps.

Rails ActiveRecord Join

I'm using rails and am trying to figure out how to use ActiveRecord within the method to combine the following into one query:
def children_active(segment)
parent_id = Category.select('id').where('segment' => segment)
Category.where('parent_id'=>parent_id, 'active' => true)
end
Basically, I'm trying to get sub categories of a category that is designated by a unique column called segment. Right now, I'm getting the id of the category in the first query, and then using that value for the parent_id in the second query. I've been trying to figure out how to use AR to do a join so that it can be accomplished in just one query.
You can use self join with a alias table name:
Category.joins("LEFT OUTER JOIN categories AS segment_categories on segment_categories.id = categories.parent_id").where("segment_categories.segment = ?", segment).where("categories.active = ?", true)
This may looks not so cool, but it can implement the query in one line, and there will be much less performance loss than your solution when data collection is big, because "INCLUDE IN" is much more slower than "JOIN".

Resources