QA@IT
«質問へ戻る

70
本文
 @deals = @deals.joins(%(INNER JOIN "users" as "sales" ON "users"."id" = "deals"."sales_id" AND "sales"."type" IN ('Sales'))).where("lower(sales.name) LIKE ?", "%#{params[:sales_name].downcase}%") if params[:sales_name].present?
 ```
 
-幾ら何でもこれはちょっと酷いなぁと思うのですが、同一テーブルに対して複数の関連を持つモデルで、関連先の属性で LIKE 検索しようと思うとこうなってしまいます。何かもう少し良い方法はないでしょうか?
+幾ら何でもこれはちょっと酷いなぁと思うのですが、同一テーブルに対して複数の関連を持つモデルで、関連先の属性で LIKE 検索しようと思うとこうなってしまいます。何かもう少し良い方法はないでしょうか?せめて alias の命名戦略をカスタマイズ出来れば良いのですが……。

Rails で同一テーブルに複数回 join する際に明示的 alias を付ける方法はありませんか?

こんにちは。

掲題の通りなのですが、Rails で同一テーブルに複数回 join する場合に自力で join 句を書く以外の方法はあるのでしょうか?色々調べてみたのですが、join 句を書くしか無さそうでしたので気になって質問させて頂きました。

具体例を挙げます。以下のようなモデルがあるとします。

class User < AR::Base
class Manager < User
class Sales < User

class Deal < AR::Base
  belongs_to :manager
  belongs_to :sales

User は単一テーブル継承をしているものとします。ここで Deal を検索する際、その関連先の sales.name および manager.name に対して case insensitive な LIKE 検索をかけたい場合、どのようにすれば綺麗に書くことが出来るでしょうか?

単に片方だけを join したい場合は比較的単純です。

@model.joins(:manager).where("lower(manager.name) LIKE ?", "%#{manager_name.downcase}%")

ところが managersales の順に両方を join しようとすると、Rails だと alias が以下のようになるようです。

  • manager : users
  • sales : sales_deals

どうやら最初に join した方はテーブル名のまま、以降 join したものは「属性名_関連元名」が alias になっているようです。これだと managersales の片方が検索条件として指定されたり、あるいは両方が指定された場合で alias が変化してしまうため、明示的に alias を付けたくなるのですが、alias を明示的に指定する方法は無いでしょうか?もしくは、case insensitive な LIKE 検索を alias を指定せずに実装する方法はあるでしょうか?

現状だと以下のように酷いコードになってしまいます。

@deals = @deals.joins(%(INNER JOIN "users" as "manager" ON "users"."id" = "deals"."manager_id" AND "manager"."type" IN ('Manager'))).where("lower(manager.name) LIKE ?", "%#{params[:manager_name].downcase}%") if params[:manager_name].present?
@deals = @deals.joins(%(INNER JOIN "users" as "sales" ON "users"."id" = "deals"."sales_id" AND "sales"."type" IN ('Sales'))).where("lower(sales.name) LIKE ?", "%#{params[:sales_name].downcase}%") if params[:sales_name].present?

幾ら何でもこれはちょっと酷いなぁと思うのですが、同一テーブルに対して複数の関連を持つモデルで、関連先の属性で LIKE 検索しようと思うとこうなってしまいます。何かもう少し良い方法はないでしょうか?せめて alias の命名戦略をカスタマイズ出来れば良いのですが……。

こんにちは。

掲題の通りなのですが、Rails で同一テーブルに複数回 join する場合に自力で join 句を書く以外の方法はあるのでしょうか?色々調べてみたのですが、join 句を書くしか無さそうでしたので気になって質問させて頂きました。

具体例を挙げます。以下のようなモデルがあるとします。

```ruby
class User < AR::Base
class Manager < User
class Sales < User

class Deal < AR::Base
  belongs_to :manager
  belongs_to :sales
```

```User``` は単一テーブル継承をしているものとします。ここで ```Deal``` を検索する際、その関連先の ```sales.name``` および ```manager.name``` に対して case insensitive な LIKE 検索をかけたい場合、どのようにすれば綺麗に書くことが出来るでしょうか?

単に片方だけを join したい場合は比較的単純です。

```ruby
@model.joins(:manager).where("lower(manager.name) LIKE ?", "%#{manager_name.downcase}%")
```

ところが ```manager``` → ```sales``` の順に両方を join しようとすると、Rails だと alias が以下のようになるようです。

* manager : ```users```
* sales : ```sales_deals```

どうやら最初に join した方はテーブル名のまま、以降 join したものは「属性名_関連元名」が alias になっているようです。これだと ```manager``` と ```sales``` の片方が検索条件として指定されたり、あるいは両方が指定された場合で alias が変化してしまうため、明示的に alias を付けたくなるのですが、alias を明示的に指定する方法は無いでしょうか?もしくは、case insensitive な LIKE 検索を alias を指定せずに実装する方法はあるでしょうか?

現状だと以下のように酷いコードになってしまいます。

```ruby
@deals = @deals.joins(%(INNER JOIN "users" as "manager" ON "users"."id" = "deals"."manager_id" AND "manager"."type" IN ('Manager'))).where("lower(manager.name) LIKE ?", "%#{params[:manager_name].downcase}%") if params[:manager_name].present?
@deals = @deals.joins(%(INNER JOIN "users" as "sales" ON "users"."id" = "deals"."sales_id" AND "sales"."type" IN ('Sales'))).where("lower(sales.name) LIKE ?", "%#{params[:sales_name].downcase}%") if params[:sales_name].present?
```

幾ら何でもこれはちょっと酷いなぁと思うのですが、同一テーブルに対して複数の関連を持つモデルで、関連先の属性で LIKE 検索しようと思うとこうなってしまいます。何かもう少し良い方法はないでしょうか?せめて alias の命名戦略をカスタマイズ出来れば良いのですが……。

質問を投稿

Rails で同一テーブルに複数回 join する際に明示的 alias を付ける方法はありませんか?

こんにちは。

掲題の通りなのですが、Rails で同一テーブルに複数回 join する場合に自力で join 句を書く以外の方法はあるのでしょうか?色々調べてみたのですが、join 句を書くしか無さそうでしたので気になって質問させて頂きました。

具体例を挙げます。以下のようなモデルがあるとします。

class User < AR::Base
class Manager < User
class Sales < User

class Deal < AR::Base
  belongs_to :manager
  belongs_to :sales

User は単一テーブル継承をしているものとします。ここで Deal を検索する際、その関連先の sales.name および manager.name に対して case insensitive な LIKE 検索をかけたい場合、どのようにすれば綺麗に書くことが出来るでしょうか?

単に片方だけを join したい場合は比較的単純です。

@model.joins(:manager).where("lower(manager.name) LIKE ?", "%#{manager_name.downcase}%")

ところが managersales の順に両方を join しようとすると、Rails だと alias が以下のようになるようです。

  • manager : users
  • sales : sales_deals

どうやら最初に join した方はテーブル名のまま、以降 join したものは「属性名_関連元名」が alias になっているようです。これだと managersales の片方が検索条件として指定されたり、あるいは両方が指定された場合で alias が変化してしまうため、明示的に alias を付けたくなるのですが、alias を明示的に指定する方法は無いでしょうか?もしくは、case insensitive な LIKE 検索を alias を指定せずに実装する方法はあるでしょうか?

現状だと以下のように酷いコードになってしまいます。

@deals = @deals.joins(%(INNER JOIN "users" as "manager" ON "users"."id" = "deals"."manager_id" AND "manager"."type" IN ('Manager'))).where("lower(manager.name) LIKE ?", "%#{params[:manager_name].downcase}%") if params[:manager_name].present?
@deals = @deals.joins(%(INNER JOIN "users" as "sales" ON "users"."id" = "deals"."sales_id" AND "sales"."type" IN ('Sales'))).where("lower(sales.name) LIKE ?", "%#{params[:sales_name].downcase}%") if params[:sales_name].present?

幾ら何でもこれはちょっと酷いなぁと思うのですが、同一テーブルに対して複数の関連を持つモデルで、関連先の属性で LIKE 検索しようと思うとこうなってしまいます。何かもう少し良い方法はないでしょうか?

こんにちは。

掲題の通りなのですが、Rails で同一テーブルに複数回 join する場合に自力で join 句を書く以外の方法はあるのでしょうか?色々調べてみたのですが、join 句を書くしか無さそうでしたので気になって質問させて頂きました。

具体例を挙げます。以下のようなモデルがあるとします。

```ruby
class User < AR::Base
class Manager < User
class Sales < User

class Deal < AR::Base
  belongs_to :manager
  belongs_to :sales
```

```User``` は単一テーブル継承をしているものとします。ここで ```Deal``` を検索する際、その関連先の ```sales.name``` および ```manager.name``` に対して case insensitive な LIKE 検索をかけたい場合、どのようにすれば綺麗に書くことが出来るでしょうか?

単に片方だけを join したい場合は比較的単純です。

```ruby
@model.joins(:manager).where("lower(manager.name) LIKE ?", "%#{manager_name.downcase}%")
```

ところが ```manager``` → ```sales``` の順に両方を join しようとすると、Rails だと alias が以下のようになるようです。

* manager : ```users```
* sales : ```sales_deals```

どうやら最初に join した方はテーブル名のまま、以降 join したものは「属性名_関連元名」が alias になっているようです。これだと ```manager``` と ```sales``` の片方が検索条件として指定されたり、あるいは両方が指定された場合で alias が変化してしまうため、明示的に alias を付けたくなるのですが、alias を明示的に指定する方法は無いでしょうか?もしくは、case insensitive な LIKE 検索を alias を指定せずに実装する方法はあるでしょうか?

現状だと以下のように酷いコードになってしまいます。

```ruby
@deals = @deals.joins(%(INNER JOIN "users" as "manager" ON "users"."id" = "deals"."manager_id" AND "manager"."type" IN ('Manager'))).where("lower(manager.name) LIKE ?", "%#{params[:manager_name].downcase}%") if params[:manager_name].present?
@deals = @deals.joins(%(INNER JOIN "users" as "sales" ON "users"."id" = "deals"."sales_id" AND "sales"."type" IN ('Sales'))).where("lower(sales.name) LIKE ?", "%#{params[:sales_name].downcase}%") if params[:sales_name].present?
```

幾ら何でもこれはちょっと酷いなぁと思うのですが、同一テーブルに対して複数の関連を持つモデルで、関連先の属性で LIKE 検索しようと思うとこうなってしまいます。何かもう少し良い方法はないでしょうか?