简体   繁体   中英

how to select fields from joined table properly?

here is my simplified models, i have joined models,

model apartment

   has_many :towers

and

model tower

   belong_to :apartment

and then i tried to join both tables in controller also tried it in rails console like this:

Apartment.joins(:towers).select('apartments.id', 'apartments.name', 'towers.id', 'towers.name')

the problem is above query only returns

apartments.id and apartments.name

also tried to use alias like this, still no luck

Apartment.joins(:towers).select('apartments.id', 'apartments.name', 'towers.id as towerid', 'towers.name as towername')

i have confirmed that all towers have an apartment, i know i could do this to get 1 record

Apartment.joins(:towers).select('apartments.id', 'apartments.name', 'towers.id', 'towers.name').first.towers.id

and etc, but i need all records and all those fields, please advice.

here is the latest result i got in rails console:

 Apt Load (1.0ms)  SELECT apts.id, apts.apt_name, towers.id as towerid, towers.
    tower_name as towername FROM `apts` INNER JOIN `towers` ON `towers`.`apt_id` = `
    apts`.`id`
    => #<ActiveRecord::Relation [#<Apt id: 5, apt_name: "basura">, #<Apt id: 5, apt_
    name: "basura">, #<Apt id: 124, apt_name: "hydra">, #<Apt id: 124, apt_name: "hy
    dra">, #<Apt id: 126, apt_name: "mediterania">, #<Apt id: 126, apt_name: "mediterania">, #<Apt id: 142, apt_name: "apartement gajah mada">, #<Apt id: 142, apt_name: "apartement gajah mada">]>

as you can see, above query only return 2 fields, i need the result to be like this:

#<Apt id: 126, apt_name: "mediterania", tower_id: 12, tower_name: "tower A">, 
#<Apt id: 126, apt_name: "mediterania", tower_id: 15, tower_name: "tower F">

etcc...

The only way I see this is possible is using as

q = Apartment.joins(:towers).select('apartments.id, apartments.name, towers.id as t_id, towers.name as t_name')

q.first.t_id
q.first.t_name

Why first.towers.id will not work?

apartment.towers will return ActiveRecord::Associations::CollectionProxy . You can think of it as a collection of towers. In SQL query you are referring to towers table. But when you run apartment.towers.id you are calling id on CollectionProxy object which will not work. You can get first tower using towers.first .

Regarding,

Apt Load (1.0ms)  SELECT apts.id, apts.apt_name, towers.id as towerid, towers.
    tower_name as towername FROM `apts` INNER JOIN `towers` ON `towers`.`apt_id` = `
    apts`.`id`
    => #<ActiveRecord::Relation [#<Apt id: 5, apt_name: "basura">, #<Apt id: 5, apt_
    name: "basura">, #<Apt id: 124, apt_name: "hydra">, #<Apt id: 124, apt_name: "hy
    dra">, #<Apt id: 126, apt_name: "mediterania">, #<Apt id: 126, apt_name: "mediterania">, #<Apt id: 142, apt_name: "apartement gajah mada">, #<Apt id: 142, apt_name: "apartement gajah mada">]>

What you see in console is result returned by inspsect method. The inspect method is not designed to show non column attributes. Hence even if you have towername in memory it will only show attributes which are columns of Apartment model. More about inspect

I also recommend to try following:

Apartment.joins(:towers).pluck('apartments.id, apartments.name, towers.id as t_id, towers.name as t_name')

Above statement will get all data in array. The same result you get with select but select will not load all data in array.

You should use

Apartment.joins(:towers).select('apartments.id, apartments.name, towers.id , towers.name')

that is all column names inside a single string.

Refer this.

Rails 7 adds support for such queries, now select accepts hash

You can use aliases like this

Apartment
  .joins(:towers)
  .select(
    apartments: { id: :apartment_id, name: :apartment_name },
    towers: { id: :tower_id, name: :tower_name }
  )

It produces such query

SELECT apartments.id AS apartment_id, apartments.name AS apartments_name,
  towers.id AS tower_id, towers.name AS tower_name
FROM apartments
INNER JOIN towers ON towers.apartment_id = apartments.id

你可以试试像下面这样的别名

Apartment.joins(:towers).select('apartments.id as apartment_id, apartments.name as apartment_name, towers.id as tower_id , towers.name as tower_name)

You can try this

Apartment.joins(:towers).select('apartments.id as id, apartments.name as apartment_name, towers.id as tower_id , towers.name as tower_name)

you will get the response like this #ActiveRecord::Relation [#<Apt id: 126, apt_name: "mediterania", tower_id: 12, tower_name: "tower A">, #<Apt id: 126, apt_name: "mediterania", tower_id: 15, tower_name: "tower F">]>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM