ActiveRecord and map in RoR - ruby-on-rails

I make select
m_repeats = Event.where(:repeat => 'monthly').where("schedule < ?", date.end_of_month)
Then I need change the shedule (it is date field) in each element.
I try to do:
m_repeats.map{ |elem| elem.schedule.year = date.today.year, elem.schedule.month = date.today.month }
But I get the errors:
Mysql2::Error: Unknown column 'schedule' in 'where clause': SELECT `events`.* FROM `events` WHERE `events`.`repeat` = 'monthly' AND (schedule < '2013-04-30')
or
undefined method `schedule' for #
What is correct way to do it?

Try to use only one where statement like
m_repeats = Event.where('events.repeat = ? AND events.schedule < ?', 'monthly', date.end_of_month)
or explicitly name the table of your query on the schedule column like
m_repeats = Event.where(:repeat => 'monthly').where("events.schedule < ?", date.end_of_month)
I don't think that your map method is causing the problem, because the select of the Events takes place at the call of the map method and there you get a clear problem in your select query.

it was really grammar error :) 'schedule' instead of 'shedule'

Related

Mysql2::Error: Unknown column in where clause Rails

I receive an error of
Mysql2::Error: Unknown column 'requests.access_level_id' in 'where clause':
SELECT `requests`.*
FROM `requests` LEFT OUTER JOIN `users` ON `users`.`id` = `requests`.`from_id`
WHERE `requests`.`access_level_id` = 1
ORDER BY id DESC
Model
class Request < ApplicationRecord
belongs_to :user, foreign_key: :from_id
end
Controller
#req = Request.left_outer_joins(:user).where(access_level_id: 1).order('id DESC')
How can I remove requests from the WHERE clause requests.access_level_id = 1? I just want access_level_id = 1 to be in the where statement.
As you requested, you can add where clause without requests as,
#req = Request.left_outer_joins(:user).where('access_level_id = ?', 1).order('id DESC')
But its good to keep relative aliasing for access_level_id. If its users then please use it like,
#req = Request.left_outer_joins(:user).where(users: { access_level_id: 1 }).order('id DESC')
Assuming that access_level_id is field for user, you can replace your query with following:
#req = Request.left_outer_joins(:user).where('users.access_level_id = ?', 1).order('id DESC')
By default the fields in where conditions are considered to be belonging to Request method in your query.
Hope this helps you.
Please let me know if you face any issue.

column is there, but I receive: SQLite3::SQLException: no such column: requestor.birthyear

I have a meetings table, which has a requestor (user) with an attribute birthyear.
In the terminal I can do Meeting.find(1).requestor.birthyear
But in the meeting controller, it says no such column: requestor.birthyear
I tried adding something like users_attributes: [:birthyear] in the meetings_params, but it didn't make any difference.
What am I missing?
Here are the full files:
meeting controller
def community
if current_user.birthyear != nil
#meeting_requests = Meeting.where('meeting_time >= ? AND requestee_id IS ? AND status = ? AND (requestor.birthyear <= ? AND requestor.birthyear >= ?)', Date.today, nil, "Active", current_user.birthyear + 10, current_user.birthyear - 10).order('meeting_time asc')
end
end
meeting model
class Meeting < ApplicationRecord
belongs_to :requestor, class_name: "User"
belongs_to :requestee, class_name: "User"
end
error:
SQLite3::SQLException: no such column: requestor.birthyear: SELECT "meetings".* FROM "meetings" WHERE (meeting_time >= '2017-03-06' AND requestee_id IS NULL AND status = 'Active' AND (requestor.birthyear <= 1944 AND requestor.birthyear >= 1924)) ORDER BY meeting_time asc
Let me know if you need anything further - thank in advance!
UPDATE
trying to join the tables in the query, but not too knowledgeable on that. I'm trying:
#meeting_requests = Meeting.where('meeting_time >= ? AND requestee_id IS ? AND status = ? ', Date.today, nil, "Active").order('meeting_time asc').joins("INNER JOIN users on requestor.birthyear >= current_user.birthyear + 10")
but get:
ActionView::Template::Error (SQLite3::SQLException: ambiguous column name: status: SELECT "meetings".* FROM "meetings" INNER JOIN users on requestor.birthyear >= current_user.birthyear + 10 WHERE (meeting_time >= '2017-03-07' AND requestee_id IS NULL AND status = 'Active' ) ORDER BY meeting_time asc):
*****UPDATE*****
I posted another question to get the syntax. If it helps anyone:
Rails: Two 'where' queries - each works individually, but not together
requestor and requestee are Rails associations. This means that Rails understands how to get to requestor from a Meeting...
However - your database does not know what a requestor is. So you can't put it into the string-part of a SQL-query like you have done here:
AND (requestor.birthyear <= ? AND requestor.birthyear >= ?)'
Instead you will need to use joins to add these to your query, then figure out how rails names them in order to access the columns from them.

Define left join conditions when using .includes in ActiveRecord

I am trying to find the best way to include a referenced model on what is essentially a compound key.
I have ChecklistItem (a list of things to do daily) and then ChecklistChecks (which ties the ChecklistItem together with a User for a particular day. These checklists can either be for all Stores (with a null store_id) or for a particular Store.
This pulls all of the ChecklistItems and their associated checks:
ChecklistItem.includes(:checklist_checks).where(store_id: [nil,#store.id], list_type: 'open')
The problem is that there would be checks from multiple days in there. What I need is to pull all of the ChecklistItems and any checks from a specific day.
I tried adding conditions like this:
ChecklistItem.includes(:checklist_checks).where(store_id: [nil,#store.id], list_type: 'open', checklist_checks: {store_id: #store.id, report_date: #today})
The problem is that will only pull ChecklistItems that have an associated ChecklistCheck.
It is generating SQL that is essentially:
SELECT
checklist_items.*,
checklist_checks.*
FROM
checklist_items
LEFT OUTER JOIN
checklist_checks
ON
checklist_checks.checklist_item_id = checklist_items.id
WHERE
checklist_items.list_type = 'open'
AND
checklist_checks.store_id = 1
AND
checklist_checks.report_date = '2015-05-03'
AND
(checklist_items.store_id = 1 OR checklist_items.store_id IS NULL)
I think the problem is that the conditions on checklist_checks is in the WHERE clause. If I could move them to the ON clause of the join, everything would work.
Is there a Rails way to end up with something like this?
SELECT
checklist_items.*,
checklist_checks.*
FROM
checklist_items
LEFT OUTER JOIN
checklist_checks
ON
checklist_checks.checklist_item_id = checklist_items.id
AND
checklist_checks.store_id = 1
AND
checklist_checks.report_date = '2015-05-03'
WHERE
checklist_items.list_type = 'open'
AND
(checklist_items.store_id = 1 OR checklist_items.store_id IS NULL)
UPDATE:
I found this: enter link description here
It suggests using find_by_sql and then passing the result array and model to be included to ActiveRecord::Associations::Preloader.new.preload
I tried that, and my find_by_sql pulls the right stuff, but the id column is nil in the resulting objects.
#store = Store.find(1)
#today = Date.today - 1.days
#open_items = ChecklistItem.find_by_sql(["SELECT checklist_items.*, checklist_checks.* FROM checklist_items LEFT OUTER JOIN checklist_checks ON checklist_checks.checklist_item_id = checklist_items.id AND checklist_checks.store_id = ? AND checklist_checks.report_date = ? WHERE checklist_items.list_type='open' AND (checklist_items.store_id=? OR checklist_items.store_ID IS NULL)", #store.id, #today, #store_id])
ActiveRecord::Associations::Preloader.new.preload(#open_items, :checklist_checks)
> #open_items.first.name
=> "Turn on the lights"
> #open_items.first.id
=> nil
A solution using Arel to generate a custom join clause:
class ChecklistItem < ActiveRecord::Base
has_many :checklist_checks
# ...
def self.superjoin(date, store_id)
# build the ON clause for the join
on = Arel::Nodes::On.new(
Arel::Nodes::Equality.new(ChecklistChecks.arel_table[:checklist_item_id], ChecklistItem.arel_table[:id]).\
and(ChecklistItem.arel_table[:store_id].eq(1)).\
and(ChecklistChecks.arel_table[:report_date].eq(date))
)
joins(Arel::Nodes::OuterJoin.new(ChecklistChecks.arel_table, on))
.where(store_id: [nil, store_id], list_type: 'open' )
end
end
I bundled it up into a model method to make it easier to test in the rails console.
irb(main):117:0> ChecklistItem.superjoin(1,2)
ChecklistItem Load (0.5ms) SELECT "checklist_items".* FROM "checklist_items" LEFT OUTER JOIN "checklist_checks" ON "checklist_checks"."checklist_item_id" = "checklist_items"."id" AND "checklist_items"."store_id" = 1 AND "checklist_checks"."report_date" = 1 WHERE (("checklist_items"."store_id" = 2 OR "checklist_items"."store_id" IS NULL)) AND "checklist_items"."list_type" = 'open'
=> #<ActiveRecord::Relation []>

Rails changes postgres SELECT * to SELECT COUNT

I am working with the RailsCast on token input and am trying to cleanup a query method for Postgres. I found this post for making my query DB-agnostic.
My method:
def self.tokens(query)
t = Language.arel_table
languages = Language.where(t[:name].matches("%#{query}%"))
if languages.empty?
[{id: "<<<#{query}>>>", name: "New: \"#{query}\""}]
end
end
Returns
:001 > Language.tokens('Ru')
(0.8ms) SELECT COUNT(*) FROM "languages" WHERE ("languages"."name" ILIKE '%Ru%')
But if I use return instead of language =, I get the correct query:
def self.tokens(query)
t = .arel_table
return Language.where(t[:name].matches("%#{query}%"))
end
:001 > Language.tokens('Ru')
Language Load (0.9ms) SELECT "languages".* FROM "languages" WHERE ("languages"."name" ILIKE '%Ru%')
It's probably something obvious, but I cannot figure out why the first method is selecting count instead of all of the rows in the `languages' table db. I would really like to store the result of that query in a variable.
It's because the where is resolved as lazily as it possibly can be (not until it is absolutely needed). In your case it needs it when you:
Explicitly return
Check empty?
The reason it is doing the count, is to determine via the count whether it is empty.

Rails 3 how to do a query with a habtm association

I need to dump a set of Awards into a instance variable:
#corp = Award.find(:all, :conditions => ["award.category_id = ?", "2" ])
Award <= => AwardsCategories <= => Categories
I am trying to find All the Awards that have a Category of X
The interesting piece I am noticing is that my Award.category_id is nil but the AwardsCategory.category_id and award_id are both set.
The error is returning is:
ActiveRecord::StatementInvalid in PagesController#award_cat
PGError: ERROR: missing FROM-clause entry for table "award"
LINE 1: SELECT "awards".* FROM "awards" WHERE (award.category_id = ...
^
: SELECT "awards".* FROM "awards" WHERE (award.category_id = '2')
Any ideas and merry christmas
With a habm award doesn't need a category_id (after all, if it was used, how could an award have multiple categories?)
You need to join the award_categories table and put conditions on award_categories.category_id. Obviously if you have an actual category handy, you can just do
category.awards

Resources