What's wrong with rails activerecord? - ruby-on-rails

With this code:
candidates = Challenge.joins(:projectmilestone).where("challenges.id in (?) and projectmilestones.user_id = ?", c.subtree_ids, assignee.id)
logger.debug "candidates: #{candidates.count}"
I get this into my logs:
SELECT COUNT(*) FROM "challenges" INNER JOIN "projectmilestones" ON "projectmilestones"."id" = "challenges"."projectmilestone_id" WHERE (challenges.id in (1122) and projectmilestones.user_id = 123)
Candidate projectmilestones: 0
When I run the query straight in the database, the result is 1
Why does Activerecord tells me that the result = 0?
Please note that when I remove "and projectmilestones.user_id" from the code, then it performs right.
This has been driving me crazy for a couple of hours...

Wrong SQL statement: challenges.id in (1122)
If c.subtree_ids returns array, then:
c.subtree_ids.join(", ")

I've got it: I changed the user_id before triggering the above query but I saved it afterwards...
This is why, when running the code, it was incorrect but when cross-checking, it was ok...
Nothing was wrong with rails, it was with wrong with me... Sorry and thanks for your help!

Related

SQLite.swift joins missing information

I am trying to join a few tables in swift using the SQLite.swift library and I am having a few problems. The below code shows the issue:
I first join the tables:
let ext_tasks = tasks.join(tasktypes, on: tasktypes[tty_id] == tasks[task_type])
.join(preUsers, on: preUsers[Worker_ID] == task_ownerID)
.order(task_dueDate)
.filter(task_ownerID == iUserID)
At this point I have the tables joined and all the fields from tasks, task types and preUsers are there properly.
Following I run the second join statement:
let ext_equipment = equipment.join(equipment_type, on: equipment_type[eqt_id] == equipment[equ_type])
.join(facilities, on: facilities[fac_id] == equipment[equ_facid])
.join(eqowners, on: eqowners[Worker_ID] == equipment[equ_owner])
.order(equ_make)
.filter(equ_status >= 0)
Again, after running this statement I can access all the fields from the equipment, equipment_type, facilities and eqowners tables, up to here everything is working as expected...
However then I try to join the two above results using:
let comp_tasks = ext_tasks.join(ext_equipment, on: ext_equipment[equ_id] == ext_tasks[task_eqID])
.order(task_dueDate)
Here is where I run into a problem, it seems like the tables coming from the ext_tasks query are there but only the equipment table from the ext_equipment query is available.
Further when I try to access the "facilities"."facility_name" field, I get the following message saying that the field does not exist:
fatal error: no such column '"Facilities"."Facility_Name"' in columns:
["Equipment"."EquipmentType_ID", "Equipment"."Equipment_ID", "Equipment"."Equipment_Owner_ID", "Equipment"."Facility_ID", "Equipment"."Status", "PreUsers"."Client_ID", "PreUsers"."Date_LastLogin", "PreUsers"."First_Name", "TaskTypes"."TaskType_ID", "TaskTypes"."Type", "Tasks"."Equipment_ID", "Tasks"."Owner_ID", "Tasks"."Priority", "Tasks"."Time_Complete", "Tasks"."Time_Start"]:
(I removed some of the columns in there to shorten the answer, there are 53 fields in total shown) but as you can see only tables from the first join + the equipment table are shown, the joins from the second query (equipment_type, facilities and eqowners) are nowhere to be seen
I would appreciate if someone could let me know why this is happening, this has been killing my brain for hours and I just can't figure it out...
Thanks in advance!

Building an ActiveRecord relation without having it execute the query

I am trying to build a query as follows:
rel = article.where(version: 'some_version')
.joins(:categories)
.merge(Category.where(:uuid => 'some_cat_uuid'))
articles = rel.where(published: true).limit(10)
# etc.
The problem is the first query seems to execute no matter what I do. Am I doing something wrong?
When you run commands in the console, it automatically adds something similar to .inspect at the end to display the results of the command. For instance (this is in my app that I'm working on right now):
irb(main):061:0> Job.where(id: 251000)
Job Load (3.8ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."deleted_at" IS NULL AND "jobs"."id" = 251000
=> [#<Job id: 251000, {...}>]
So, your first line of code is just fine and would not normally execute the query, but since you were running it in the console it executes immediately so that it can display the results for you.
One way to get around this is to add ; nil to the end of the command, that way the console won't attempt to display the results (it'll just display nil as the result of that line. IE:
irb(main):062:0> Job.where(id: 251000); nil
=> nil
Doing it this way you should be able to do what you were expecting (delay execution of the query until you actually need the results):
rel = article.where(version: 'some_version')
.joins(:categories)
.merge(Category.where(:uuid => 'some_cat_uuid')); nil
articles = rel.where(published: true).limit(10); nil
Then you can execute the query by using articles.all (in Rails 3) or articles.to_a (in Rails 4)
Of course if you then move this code to a rake task or model or something you can drop those ; nil bits because they look a little cluttered and would be useless at that point.
Another point of contention for the console might be that it'll see that .where() {NEWLINE} and execute the query at that point, I tend to put the dot on the previous line to remove any ambiguity of where my command is ending:
rel = article.where(version: 'some_version').
joins(:categories).
merge(Category.where(:uuid => 'some_cat_uuid')); nil

Selecting sum results from multiple tables in Rails

I am working in the Rails console. I would like to select the SUM of a same named column in two different tables.
Here is my ActiveRecord code:
Computer.joins(:services, :repairs)
.select("computers.id, SUM(services.cost) as SCOST, SUM(repairs.cost) as RCOST")
.group("computers.id")
This works well and returns the following correct SQL:
`SELECT computers.id, SUM(services.cost) as SCOST, SUM(repairs.cost) as RCOST
FROM "computers" INNER JOIN "services" ON "services"."computer_id" = "computers"."id"
INNER JOIN "repairs" ON "repairs"."computer_id" = "computers"."id"
GROUP BY computers.id `
But it gives the following result in the Rails console:
=> [#<Computer id: 36>, #<Computer id: 32>]
Shouldn't I be able to access my SUM values as well? I ran the above SQL query in postgres and it gave the desired output.
Any help would be appreciated.
Thanks.
The Rails console uses the inspect method to display the object content. This method doesn't display the values for the custom fields. You will be able to print the value of a custom attribute at the console by explicitly referring to it.
Computer.joins(:services, :repairs)
.select("computers.id, SUM(services.cost) as scost, SUM(repairs.cost) as rcost")
.group("computers.id").each do |c|
puts c.scost
puts c.rcost
end
Edit
Example based on comment:
Create a member variable in your controller:
#computers = Computer.joins(:services, :repairs)
.select("computers.id, SUM(services.cost) as scost, SUM(repairs.cost) as rcost")
.group("computers.id")
Iterate over the variable in your views
- #computers.each do |computer|
= computer.scost
= computer.rcost
Edit2
You need to use LEFT OUTER JOIN to get values for computers with missing repairs or services.
join_sql = "LEFT OUTER JOIN services ON services.computer_id = computers.id
LEFT OUTER JOIN repairs ON repairs.computer_id = computers.id"
sum_sql = "SUM(COALESCE(services.cost, 0)) as scost,
SUM(COALESCE(repairs.cost, 0)) as rcost"
#computers = Computer.joins(join_sql)
.select("computers.id, #{sum_sql}")
.group("computers.id")
try as follow,
#computer_list = Computer.joins(:services, :repairs).select("computers.id, SUM(services.cost) as SCOST, SUM(repairs.cost) as RCOST").group("computers.id")
#computer_list.last.SCOST

undefined method `gsub' for nil:NilClass

I'm newvbie in ruby on rails.. I'm having problem with gsub.. I everytime I go to the list of my store page it says "undefined method `gsub' for nil:NilClass"..
here is mycode :
def self.search(search_val, page = 1)
#search_val = search_val.gsub("'", "\\\\'")
search_query = "store_id LIKE '%#{ #search_val }%' OR english_name LIKE '%#{ #search_val }%' OR chinese_name LIKE '%#{ #search_val }%'"
select("jos_store.id, store_id, english_name, chinese_name, store_manager, delivery_area,year, week").joins("LEFT OUTER JOIN (SELECT id as store_replenishment, store, MAX(stock_movement) AS stock_movement FROM jos_store_replenishment GROUP BY store) AS replenishment ON replenishment.store = jos_store.id").joins("LEFT OUTER JOIN jos_stock_movement ON jos_stock_movement.id = replenishment.stock_movement").where(search_query).order("year DESC, week DESC").paginate :page => page, :per_page => 15
end
thanks in advance
A good practice is doing .to_s when you are using string methods.
You can use the & operator on search_val. It allows you to avoid null pointer exceptions without adding additional checks or using to_s to convert a string to a string.
So, you'll have something like this:
#search_val = search_val&.gsub("'", "\\\\'")
You can read more on the safe navigation operator here: http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/
This means that search_val is in fact nil. You can easily verify this by printing out the value of search_val.
I'm not sure if this is your case, but the same undefined method gsub for nil:NilClass error happened with me after a few rollbacks and migrations.
Then, I restarted the server and works. Maybe this could be the case for some people that reached this topic searching on Google.

How to make LIMIT work in Grails HQL executeUpdate()?

I'm running grails 1.3.6 and I have this code:
String hql = '''
UPDATE
ApiResponse a
SET
a.lockId = :lockId
WHERE
a.lockId = 0
ORDER BY
a.dateAdded asc
LIMIT 5
'''
ApiResponse.executeUpdate(hql, [lockId : workerId])
It seems that this code updates all rows in DB instead of the 5 oldest entries. Does this mean LIMIT is not working in HQL? Please help me how to achieve the same SQL logic in GORM or HQL. Basically, I need to do a bulk update using LIMIT.
what i do (grails 1.3.7):
ExAus.executeQuery( "select distinct <field> from <controller>", [max: 20, offset: 0] )
While waiting for someone to reply, I think I found a workaround. Here it is:
def c = ApiResponse.createCriteria()
def targetList = c.list {
eq('lockId', 0)
maxResults(5)
order("dateAdded", 'asc')
}
String hql = '''
UPDATE
ApiResponse
SET
lockId = :lockId
WHERE
id in (:ids)
'''
ApiResponse.executeUpdate(hql, [lockId : workerId, ids: targetList.collect {it.id}])
I believe this approach can still be considered same logic with the original. However, this has to make 2 queries.
Feel free to suggest other approaches. Thanks!
I know the post is quite old but the question is still relevant since I had the same problem.
I fell back to using Groovy sql (jdbc) instead.
You will need to inject the dataSource object within your service/controller first by using:
def dataSource
Then you may do this in your method:
String sqlQuery = '''
UPDATE
API_RESPONSE a
SET
a.LOCK_ID = :lockId
WHERE
a.LOCK_ID = 0
ORDER BY
a.DATE_ADDED asc
LIMIT 5
'''
def sql = new Sql(dataSource)
sql.executeUpdate(sqlQuery, [lockId : workerId])
Note that you will need to use the database native table and column names in the sql query.

Resources