I have two tables (A and B) and a relatively complicated Active::Record::Relation that selects from a join of these two tables. The query executes correctly with ActiveRecord::Base.connection.exec_query joined.to_sql, that is, it prints out the columns I want from each table (A.id, A.title, b.num).
I would like to then pass this "joined" table as an Arel::Table, to be used in the rest of the program. However, when I run at_j=joined.arel_table, the Arel table is created from the original database A, not from the one resulting from the "joined" query, i.e. I get all the columns from A (not only the selected ones), and none of the columns from B.
I realise that a first step would be to create an arel table from an already filtered table, i.e. if A has columns id, title, c1, c2, c3... I would like to be able to do:
filtered=A.select(:id,:title)
at_f=filtered.arel_table
and only get id and title in at_f, but that is not what happens, I also get c1, c2, c3....
I know I could do
at_f=A.arel_table.project(:id,:title)
but this outputs an Arel::SelectManager, and I need to pass an Arel::Table (that is out of my hands).
I also would rather not build the query in Arel, because I need to modify the table A that was given as an input, and I can do that using _selct! and joins!.
Is there a way to achieve this? I thought of using something like
at_f=Arel::Table.new(filtered.to_sql)
but that fails, unsurprisingly...
Thanks in advance for your help.
................................
In case this is useful, this is how I get the "joined" active record relation:
A._select!(:id,:title,'b.num')
bf=B.where(c1: 'x',c2: 'y')
num=bf.select('id_2 AS A_id, COUNT(id_2) AS num').group(:id_2)
A.joins!("LEFT OUTER JOIN (#{num.to_sql}) b ON A.id = b.A_id")
and this is the query it generates:
# A.to_sql:
SELECT `A`.`id`, `A`.`title`, `b`.`num`
FROM `A` LEFT OUTER JOIN
(SELECT id_2 AS A_id, COUNT(id_2) AS num
FROM `B` WHERE `B`.`c1` = 'x' AND `B`.`c2` = 'y'
GROUP BY `B`.`id_2`) b
ON A.id = b.A_id
Maybe I understand what you are trying for although I am not sure about the whole
Arel::Tablepart but we can get you that AR Relation fromAas follows:This will result in an ActiveRecord::Relation object and when executed will return
Aobjects with only the following attributes:id,title, andnum.The SQL will be:
Which is equivalent to what you have now.
If you truly want to build the query you have now we can certainly do that without issue but this is a bit cleaner.
If this is not your intended outcome please clarify and I will update accordingly.
Notes:
Arel::Tableis.Arel::Nodes::TableAliaswhich kind of duck types anArel::Tablefor most intents and purposes and will allow for a query (subquery).arelmethod. For Example:UPDATE with Additional Information:
Arel::Tableout of nothingt =Arel::Table.new('c')t[:id]will return anAttributeand will generate SQL ofc.idArel::Table#project- is theSELECTcommand and returnsSelectManager(this object is the primary means of interaction with the AST and the table).SelectManageralso hasprojectto add to the current projections.Tableor aTableAliasas a source for theSelectManagerusing#fromttable we created above or thebtable alias to add columns, sort, etc.SelectManagerusing thefromsmethod which will give you access to theTableAliasin this case which may be what you are looking for regarding the need for anArel::Table