ActiveRecordでレガシーテーブル
に繋いだらスタンド攻撃を受けた話
@ryonext
•

タイトルは釣りです
自己紹介
•

Twitter ID @ryonext

•

ハンターランク151のモンハン厨です

•

新横浜にあるOA機器メーカーでビデオ会議のシステム
作ってます

•

RailsでAPIとかテスト書いたりとか
ActiveRecordは便利ですね
1 class CreateUsers < ActiveRecord::Migration!
2
def change!
3
create_table :users do |t|!
4
t.string :...
14
15
16
17
18
19
20
21
22
23
24

ActiveRecord::Schema.define(version: 20131116064854) do!
!
create_table "users", force: ...
mysql> desc users;
+------------+--------------+------+-----+---------+----------------+
| Field
| Type
| Null | Key | Def...
ActiveRecordの規約に沿ってい
ないテーブル
+--------------------+
| Tables_in_legacydb |
+--------------------+
| legacy_user
|
+--------...
こんな感じでつなげます
config/database.yml
14 legacy:!
15
adapter: mysql2!
16
database: legacyDB!
17
username: root!
18
password:!
19
...
ただし
こんなテーブルが合ったとする
mysql> desc hyper_legacy_tbl;
+-----------+---------+------+-----+---------+-------+
| Field
| Type
| Null ...
つないでみる

1 class HyperLegacyTbl < ActiveRecord::Base!
2
establish_connection(:legacy)!
3
self.table_name = "hyper_legacy_tb...
繋がったようにみえる

[5] pry(main)> h = HyperLegacyTbl.new
=> #<HyperLegacyTbl legacy_id: 0, id: nil>
‘id’を更新してみる

[6] pry(main)> h.id = 100
=> 100
[7] pry(main)> h.save
ファッ!?
(0.2ms) BEGIN
SQL (0.3ms) INSERT INTO `hyper_legacy_tbl`
(`legacy_id`) VALUES (100)
(0.1ms) COMMIT
=> true
[8] pry(m...
なぜなのか

•

“#id”によるアクセスはprimary_keyへのアクセスになっ
ている

•

“id”という名前のパラメータへのアクセスではない
対処:既存レコードの場合
取得には“#attributes[“id”]”を使う
[36] pry(main)> h = HyperLegacyTbl.first
HyperLegacyTbl Load (0.4ms) SELECT `hyper...
対処:既存レコードの場合
更新には“update_column”を使う
[45] pry(main)> h.update_column("id", 1000)
SQL (0.3ms) UPDATE `hyper_legacy_tbl` SET ...
新規の場合

•

Insertのときはupdate_columnが使えないので違う方法
が必要?(未調査)

•

直接SQLを発行してしまえば

•

それもうActiveRecordつかわなくていいよね説
どこで定義されているのか
•

#id
•

lib/active_record/attribute_methods/primary_key.rb
•

•

#define_method_attribute(attr_name)

#id=
•...
まとめ

•

‘id’っていう名前を持つテーブルにActiveRecordでつな
ぐときは注意しましょう
ActiveRecordでレガシーテーブルにつないだ話
Upcoming SlideShare
Loading in …5
×

ActiveRecordでレガシーテーブルにつないだ話

1,696 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,696
On SlideShare
0
From Embeds
0
Number of Embeds
358
Actions
Shares
0
Downloads
4
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

ActiveRecordでレガシーテーブルにつないだ話

  1. 1. ActiveRecordでレガシーテーブル に繋いだらスタンド攻撃を受けた話 @ryonext
  2. 2. • タイトルは釣りです
  3. 3. 自己紹介 • Twitter ID @ryonext • ハンターランク151のモンハン厨です • 新横浜にあるOA機器メーカーでビデオ会議のシステム 作ってます • RailsでAPIとかテスト書いたりとか
  4. 4. ActiveRecordは便利ですね 1 class CreateUsers < ActiveRecord::Migration! 2 def change! 3 create_table :users do |t|! 4 t.string :name! 5 t.integer :age! 6 t.string :type! 7 ! 8 t.timestamps! 9 end! 10 end! 11 end
  5. 5. 14 15 16 17 18 19 20 21 22 23 24 ActiveRecord::Schema.define(version: 20131116064854) do! ! create_table "users", force: true do |t|! t.string "name"! t.integer "age"! t.string "type"! t.datetime "created_at"! t.datetime "updated_at"! end! ! end
  6. 6. mysql> desc users; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | age | int(11) | YES | | NULL | | | type | varchar(255) | YES | | NULL | | | created_at | datetime | YES | | NULL | | | updated_at | datetime | YES | | NULL | | +------------+--------------+------+-----+---------+----------------+ 6 rows in set (0.00 sec)
  7. 7. ActiveRecordの規約に沿ってい ないテーブル +--------------------+ | Tables_in_legacydb | +--------------------+ | legacy_user | +--------------------+ mysql> desc legacy_user; +-------------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------------+--------------+------+-----+---------+-------+ | userID | int(11) | NO | PRI | 0 | | | name | varchar(255) | YES | | NULL | | | age | int(11) | YES | | NULL | | | someLegacyParams1 | varchar(255) | YES | | NULL | | | someLegacyParams2 | varchar(255) | YES | | NULL | | | someLegacyParams3 | varchar(255) | YES | | NULL | | +-------------------+--------------+------+-----+---------+-------+ 6 rows in set (0.00 sec)
  8. 8. こんな感じでつなげます config/database.yml 14 legacy:! 15 adapter: mysql2! 16 database: legacyDB! 17 username: root! 18 password:! 19 pool: 5! 20 timeout: 5000 app/models/legacy_user.rb 1 class LegacyUser < ActiveRecord::Base! 2 establish_connection(:legacy)! 3 self.table_name = "legacy_user"! 4 end
  9. 9. ただし
  10. 10. こんなテーブルが合ったとする mysql> desc hyper_legacy_tbl; +-----------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+---------+------+-----+---------+-------+ | legacy_id | int(11) | NO | PRI | 0 | | | id | int(11) | YES | | NULL | | +-----------+---------+------+-----+---------+-------+ 2 rows in set (0.01 sec) ‘id’というカラムをもつが、主キーではなく普通のカラム
  11. 11. つないでみる 1 class HyperLegacyTbl < ActiveRecord::Base! 2 establish_connection(:legacy)! 3 self.table_name = "hyper_legacy_tbl"! 4 end
  12. 12. 繋がったようにみえる [5] pry(main)> h = HyperLegacyTbl.new => #<HyperLegacyTbl legacy_id: 0, id: nil>
  13. 13. ‘id’を更新してみる [6] pry(main)> h.id = 100 => 100 [7] pry(main)> h.save
  14. 14. ファッ!? (0.2ms) BEGIN SQL (0.3ms) INSERT INTO `hyper_legacy_tbl` (`legacy_id`) VALUES (100) (0.1ms) COMMIT => true [8] pry(main)> h => #<HyperLegacyTbl legacy_id: 100, id: nil>
  15. 15. なぜなのか • “#id”によるアクセスはprimary_keyへのアクセスになっ ている • “id”という名前のパラメータへのアクセスではない
  16. 16. 対処:既存レコードの場合 取得には“#attributes[“id”]”を使う [36] pry(main)> h = HyperLegacyTbl.first HyperLegacyTbl Load (0.4ms) SELECT `hyper_legacy_tbl`.* FROM `hyper_legacy_tbl` ORDER BY `hyper_legacy_tbl`.`legacy_id` ASC LIMIT 1 => #<HyperLegacyTbl legacy_id: 100, id: 200> [37] pry(main)> h.id => 100 [38] pry(main)> h.legacy_id => 100 [39] pry(main)> h.attributes["id"] => 200
  17. 17. 対処:既存レコードの場合 更新には“update_column”を使う [45] pry(main)> h.update_column("id", 1000) SQL (0.3ms) UPDATE `hyper_legacy_tbl` SET `hyper_legacy_tbl`.`id` = 1000 WHERE `hyper_legacy_tbl`.`legacy_id` = 100 => true ただし、データを取りなおさないで2連続でやると失敗する [46] pry(main)> h.update_column("id", 3000) SQL (0.3ms) UPDATE `hyper_legacy_tbl` SET `hyper_legacy_tbl`.`id` = 3000 WHERE `hyper_legacy_tbl`.`legacy_id` = 1000 => false
  18. 18. 新規の場合 • Insertのときはupdate_columnが使えないので違う方法 が必要?(未調査) • 直接SQLを発行してしまえば • それもうActiveRecordつかわなくていいよね説
  19. 19. どこで定義されているのか • #id • lib/active_record/attribute_methods/primary_key.rb • • #define_method_attribute(attr_name) #id= • lib/active_record/attribute_methods/write.rb • #write_attribute(attr_name, value)
  20. 20. まとめ • ‘id’っていう名前を持つテーブルにActiveRecordでつな ぐときは注意しましょう

×