How to specify conditions on joined tables in rails

SqlRuby on-RailsActiverecord

Sql Problem Overview


I am trying to do a query in in Rails with ActiveRecord that specifies some condition on a joined table. And i can't seem to get it to work, even though i follow the examples from here:

http://guides.rubyonrails.org/active_record_querying.html#specifying-conditions-on-the-joined-tables

From the guides:

> Client.joins(:orders).where(:orders => {:created_at => time_range})

My database schema looks like this, with tables scores, submissions and tasks:

  create_table "scores", :force => true do |t|
    t.integer  "value"
    t.integer  "user_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "scores", ["user_id"], :name => "index_scores_on_user_id"

  create_table "submissions", :force => true do |t|
    t.integer  "user_id"
    t.integer  "task_id"
    t.integer  "score_id"
    t.datetime "completed_at"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "submissions", ["score_id"], :name => "index_submissions_on_score_id"
  add_index "submissions", ["task_id"], :name => "index_submissions_on_task_id"
  add_index "submissions", ["user_id"], :name => "index_submissions_on_user_id"

  create_table "tasks", :force => true do |t|
    t.integer  "episode_id"
    t.integer  "score"
    t.string   "key"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

So i want to do a query where I can find all "scores" that have a relation to a spesific task. Submission belongs to tasks and scores.

My query now looks like this:

Score.joins(:submission).where(:submission => {:task_id => 1})

This generates the following syntax:

SELECT "scores".* FROM "scores" INNER JOIN "submissions" ON "submissions"."score_id" = "scores"."id" WHERE "submission"."task_id" = 1

Which generates the following error:

SQLite3::SQLException: no such column: submission.task_id

But there is a column submission.task_id, which you can see in the db schema. And i can do this successfully:

SELECT "submissions".* FROM "submissions" WHERE "submissions"."task_id" = 1

Sql Solutions


Solution 1 - Sql

The name in the clause should be plural to reference the table name:

Score.joins(:submission).where(:submissions => {:task_id => 1})

Solution 2 - Sql

I find this to be easier.

Score.joins(:submission).merge(Submission.where(task_id: 1))

Solution 3 - Sql

The clause name should be plural to reference the table name.

Score.joins(:submission).where(submissions: { task_id: 1 })

If score has many submissions, the joins symbol should also be plural to reference the relation between Score and Submission.

Score.joins(:submissions).where(submissions: { task_id: 1 })

Solution 4 - Sql

A caveat: if you're using non-standard table names the above will fail like so:

ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "submissions"

To fix this, put (joined-model-class).table_name as a key in the where hash:

Score.joins(:submission).where(
  Submission.table_name => {task_id: 1}
)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionespenhogbakkView Question on Stackoverflow
Solution 1 - SqlNickView Answer on Stackoverflow
Solution 2 - SqlthedanottoView Answer on Stackoverflow
Solution 3 - SqlimtkView Answer on Stackoverflow
Solution 4 - SqlMatt HuckeView Answer on Stackoverflow