Rails3: Getting "no attribute named..." in simple join - ruby-on-rails-3

I'm trying join in Rails 3 for the first time, and can't get the most basic thing to work, so must be missing something major. Given
class Member < ActiveRecord::Base
belongs_to :status
...
end
class Status ActiveRecord::Base
has_many :members
...
end
when I try to use a join, testing in the console an example adapted from the Rails Guides
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
Status.joins(:members).where('member.created_at' => time_range)
I get an error message,
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'member.created_at' in
'where clause': SELECT `statuses`.* FROM `statuses` INNER JOIN `members` ON
`members`.`status_id` = `statuses`.`id` WHERE (`member`.`created_at` BETWEEN
'2011-03-26 23:00:00' AND '2011-03-27 23:00:00')
Both models do have created_at columns and this works: Member.where(:created_at => time_range). I've tried several permutations and used different columns but get the same Unknown column error every time I try the join.

It should be members.created_at :) When you explicitly use the db table name, remember that it's in plural by rails convention.

Related

Ransack / Rails 6 : PG::UndefinedTable for a query through a belongs_to

I can't chain a where and a Ransack query, I get a PG::UndefinedTable error. I'm using Rails 6.1.3 and Ransack 2.4.2.
I have seen this issue : https://github.com/activerecord-hackery/ransack/issues/1119 where everybody agrees that the problem has been fixed with the upgrade to rails 6.1. Sadly, not for my case.
My models looks like this :
class Appointment < ApplicationRecord
belongs_to :slot
end
class Slot < ApplicationRecord
belongs_to :place
end
This query
Appointment.joins(slot: [:place])
.where('slot.date' => Date.today)
.ransack(slot_place_id_eq: 2)
.result
returns this error :
ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR: invalid reference to FROM-clause entry for table "slots")
LINE 1: ...ointments"."slot_id" WHERE "slot"."date" = $1 AND "slots"."p...
^
HINT: Perhaps you meant to reference the table alias "slot".
The generated query is the following, and indeed, slots.place_id can't work for a belongs_to.
SELECT appointments.*
FROM appointments
INNER JOIN slots slot ON slot.id = appointments.slot_id
INNER JOIN places ON places.id = slot.place_id
WHERE slot.date = '2021-06-30' AND slots.place_id = 2
Any clue ?
I just solved this : it was a different issue, with the same error message than the other one.
This :
.where('slot.date' => Date.today)
is supposed to be this :
.where('slots.date' => Date.today)
Two hour of research, 10 minutes to write a SO question, finding the solution by yourself 30 seconds after clicking publish....

Create a scope in rails based on HABTM association count

I'm trying to create a rails scope based on the count of a model's HABTM assocation, but I'm struggling with the SQL.
I want Match.open to return matches with less than two users. I also have Match.upcoming, which returns matches with a 'future_date' in the future, which is working well.
My code:
class Match < ActiveRecord::Base
has_and_belongs_to_many :users
scope :open, joins('matches_users').
select('*').
group('matches.id').
having('count(matches_users.user_id) < 2')
scope :upcoming, lambda {
where("proposed_date between ? and ?", Date.today, Date.today.next_month.beginning_of_month)
}
I'm currently getting the error:
SQLite3::SQLException: no such column: matches_users.user_id: SELECT * FROM "matches" matches_users GROUP BY matches.id HAVING count(matches_users.user_id) < 2
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: matches_users.user_id: SELECT * FROM "matches" matches_users GROUP BY matches.id HAVING count(matches_users.user_id) < 2
I'm currently achieving this with a class method:
def self.open
self.select{|match| match.users.length < 2}
end
Which works, but I'd really like to move this into a scope for speed, and so that I can chain the scopes like Match.open.upcoming.
What am I doing wrong here? What's the correct way to do this? Any help would be appreciated.
Give this a shot - I've used something similar before and it seems to work for me:
class Match < ActiveRecord::Base
has_and_belongs_to_many :users
scope :open, joins(:matches_users)
.select('matches.*')
.group('matches.id')
.having('count(matches_users.id) < 2')
...
end

Active Record find using conditional based on multi level association's attribute

I am getting missing FROM clause error (shown below)
I want to find the entries whose associated reports' city is the same as the users' city, thus only showing relavant entries to users. So, if a user belongs to a city that a report does, the user should be shown the entries from that report.
I tried a few things, one being this scope in the Entry model:
scope :report_in_city, lambda { |user| joins(:report).where("report.city_id = ?", user.city_id) }
And if I call Entry.report_in_city(user)
I get this error:
SELECT "entries".* FROM "entries" INNER JOIN "reports" ON "reports"."id" = "entries"."report_id" WHERE (report.city_id = 1)
ActiveRecord::StatementInvalid: PG::Error: ERROR: missing FROM-clause entry for table "report"
LINE 1: ... ON "reports"."id" = "entries"."report_id" WHERE (report.cit...
^
: SELECT "entries".* FROM "entries" INNER JOIN "reports" ON "reports"."id" = "entries"."report_id" WHERE (report.city_id = 1)
I have a few models set up like this:
class Report
belongs_to user
belongs_to city
has_many entries
class Entry
belongs_to report
class User
has_many reports
belongs_to city
class City
has_many users
has_many reports
I am new to sql and would appreciate any advice on this query!
Since that string condition "report.city_id = ?" goes into the SQL, you have to use the table names. Rails is cute about going back and forth between plural and singular, but SQL only knows the table name reports. You can see that in the generated SQL like ON "reports"."id" = "entries"."report_id". The table name is plural.
Try this:
"reports.city_id = ?"
or the Rails way:
joins(:report).where(:report => { :city_id => user.city_id })

Rails 3 Order Records By Grand-child Count

I'm trying to do some fairly complicated record sorting that I was having a bit of trouble with. I have three models:
class User < ActiveRecord::Base
has_many :registers
has_many :results, :through => :registers
#Find all the Users that exist as registrants for a tournament
scope :with_tournament_entrees, :include => :registers, :conditions => "registers.id IS NOT NULL"
end
Register
class Register < ActiveRecord::Base
belongs_to :user
has_many :results
end
Result
class Result < ActiveRecord::Base
belongs_to :register
end
Now on a Tournament result page I list all users by their total wins (wins is calculated through the results table). First thing first I find all users who have entered a tournament with the query:
User.with_tournament_entrees
With this I can simply loop through the returned users and query each individual record with the following to retrieve each users "Total Wins":
user.results.where("win = true").count()
However I would also like to take this a step further and order all of the users by their "Total Wins", and this is the best I could come up with:
User.with_tournament_entrees.select('SELECT *,
(SELECT count(*)
FROM results
INNER JOIN "registers"
ON "results"."register_id" = "registers"."id"
WHERE "registers"."user_id" = "users.id"
AND (win = true)
) AS total_wins
FROM users ORDER BY total_wins DESC')
I think it's close, but it doesn't actually order by the total_wins in descending order as I instruct it to. I'm using a PostgreSQL database.
Edit:
There's actually three selects taking place, the first occurs on User.with_tournament_entries which just performs a quick filter on the User table. If I ignore that and try
SELECT *, (SELECT count(*) FROM results INNER JOIN "registers" ON "results"."register_id" = "registers"."id" WHERE "registers"."user_id" = "users.id" AND (win = true)) AS total_wins FROM users ORDER BY total_wins DESC;
it fails in both PSQL and the ERB console. I get the error message:
PGError: ERROR: column "users.id" does not exist
I think this happens because the inner-select occurs before the outer-select so it doesn't have access to the user id before hand. Not sure how to give it access to all user ids before than inner select occurs but this isn't an issue when I do User.with_tournament_entires followed by the query.
In your SQL, "users.id" is quoted wrong -- it's telling Postgres to look for a column named, literally, "users.id".
It should be "users"."id", or, just users.id (you only need to quote it if you have a table/column name that conflicts with a postgres keyword, or have punctuation or something else unusual).

Complex Query with Has many and belongs to for RAILS 3

I am trying to do a QUERY in my controller to get a list of suppliers with a category ID.
I have my models set up like this.
class Supplier < ActiveRecord::Base
has_and_belongs_to_many :sub_categories
end
class Category < ActiveRecord::Base
has_many :sub_categories
end
class SubCategory < ActiveRecord::Base
belongs_to :category
has_and_belongs_to_many :suppliers
end
A supplier can have Many sub_categories that are under one single category. So i can grab the category of a supplier by doing this.
#supplier.sub_categories.first.category.name
This returns the category that the supplier comes under because they have to have at least 1 sub category which is then linked to a category.
What i am trying to do is by passing a category_id i wish to return all suppliers that come under that category.
I had it written like this but it doesnt seem to be working.
#category = Category.find(params[:category_id])
#suppliers = Supplier.where('sub_category.first.category.id = ?', #category.id)
i get the following sql error
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.id = 20)' at line 1: SELECT `suppliers`.* FROM `suppliers` WHERE (sub_category.first.category.id = 20)
Well, that's certainly an sql error. The stuff inside the where() call gets translated directly to SQL, and that's not sq;l. :)
You need to join tables together. I'm assuming there's a sub_category_suppliers table that completes the habtm association. (BTW, I much prefer to use has_many :through exclusively)
I think it would be something like this:
Supplier.joins(:sub_category_suppliers => :sub_categories).
where('sub_categories.category_id =?', #category.id).
group('suppliers.id')
As Caley Woods suggested, this should be placed in the Supplier model as a scope:
scope :by_category, lambda { |category_id|
joins(:sub_category_suppliers => :sub_categories).
where('sub_categories.category_id =?', category_id).
group('suppliers.id')
}
and then called as Supplier.by_category(#category.id)