[memo][Rails]連携先テーブルの条件を指定してfind

Standard
[memo][Rails]連携先テーブルの条件を指定してfind

Railsで多対多の関係を持ったテーブル間で、連携先のテーブル側の条件を指定してfindしたかったんだけど、1時間ぐらいググった挙げ句わきげさんに先を越されたのでメモ。
 

やりたいこと

—————
dinner
—————
id  | name
—————
1  | にくじゃが
2  | シチュー
3  | チキンカレー
 
 
—————
foodstuff
—————
id  | name
—————
1  | にんじん
2  | たまねぎ
3  | 牛肉
4  | とり肉
 
 
—————————
dinners_foodstuffs
—————————
dinner_id  | foodstuff_id
—————————
1       | 1
1       | 2
1       | 3
2       | 1
2       | 2
2       | 3
3       | 1
3       | 2
3       | 4
 
 
みたいなテーブルとデータがあるとしたら、
Dinner.find(:all,:conditions => ‘とり肉が入ってる料理’)
みたいなこと。
 

正解

Dinner.find(:all, :include => :foodstuffs, :conditions => ["foodstuffs.name = ?", 'とり肉'])

 

ためす

  • rails mytest
  • ./script/generate model dinner name:string
  • ./script/generate model foodstuff name:string

 
 
mytest/models/dinner.rb編集

class Dinner < ActiveRecord::Base
  has_and_belongs_to_many :foodstuffs
end

 
mytest/models/foodstuff.rb編集

class Foodstuff < ActiveRecord::Base
  has_and_belongs_to_many :dinners
end

 
mytest/db/migrate/xxxxx_create_foodstuffs.rb編集

class CreateFoodstuffs < ActiveRecord::Migration
  def self.up
    create_table :foodstuffs do |t|
      t.string :name

      t.timestamps
    end

    # join table を作る
    create_table "dinners_foodstuffs", :id => false do |t|
      t.integer "dinner_id", "foodstuff_id"
    end
    add_index "dinners_foodstuffs", "dinner_id"
    add_index "dinners_foodstuffs", "foodstuff_id"
  end

  def self.down
    drop_table :foodstuffs
    drop_table :dinners_foodstuffs
  end
end

 
マイグレート実行

  • rake db/migrate

 
テストデータ作成
mytest/test/fixtures/dinners.yml編集

肉じゃが:
  id: 1
  name: にくじゃが

シチュー:
  id: 2
  name: シチュー

チキンカレー:
  id: 3
  name: チキンカレー

 
mytest/test/fixtures/foodstuffs.yml編集

にんじん:
  id: 1
  name: にんじん

たまねぎ:
  id: 2
  name: たまねぎ

牛肉:
  id: 3
  name: 牛肉

とり肉:
  id: 4
  name: とり肉

 
mytest/test/fixtures/dinners_foodstuffs.yml作成

one:
  dinner_id: 1
  foodstuff_id: 1

two:
  dinner_id: 1
  foodstuff_id: 2

three:
  dinner_id: 1
  foodstuff_id: 3

four:
  dinner_id: 2
  foodstuff_id: 1

five:
  dinner_id: 2
  foodstuff_id: 2

six:
  dinner_id: 2
  foodstuff_id: 3

seven:
  dinner_id: 3
  foodstuff_id: 1

eight:
  dinner_id: 3
  foodstuff_id: 2

nine:
  dinner_id: 3
  foodstuff_id: 4

 
 
 
テストデータ投入

  • rake db:fixtures:load FIXTURES=dinners,foodstuffs,dinners_foodstuffs

 
 
Railsコンソールから確認

  • ./script/console

 
 

Loading development environment (Rails 2.3.4)

>> Dinner.find(:all, :include => :foodstuffs, :conditions => ["foodstuffs.name = ?", 'とり肉'])
Dinner.find(:all, :include => :foodstuffs, :conditions => ["foodstuffs.name = ?", 'とり肉'])

=> [#<dinner id: 3, name: "チキンカレー", created_at: "2009-10-27 06:30:22", updated_at: "2009-10-27 06:30:22">]

>> 
?> 
?> 
?> Foodstuff.find(:all, :include => :dinners, :conditions => ["dinners.name = ?", 'にくじゃが'])
Foodstuff.find(:all, :include => :dinners, :conditions => ["dinners.name = ?", 'にくじゃが'])

=> [#<foodstuff id: 1, name: "にんじん", created_at: "2009-10-27 06:30:22", updated_at: "2009-10-27 06:30:22">, #</foodstuff><foodstuff id: 2, name: "たまねぎ", created_at: "2009-10-27 06:30:22", updated_at: "2009-10-27 06:30:22">, #</foodstuff><foodstuff id: 3, name: "牛肉", created_at: "2009-10-27 06:30:22", updated_at: "2009-10-27 06:30:22">]

>>