rails 学习笔记


layout: post
title: 第十一章困惑 外键 及 反转relationships表
categories:

  • rails
    tags:
  • railstutorail 学习笔记

不知道有谁学到11章时和我一样困惑的,所谓的对调两列的位置,组建成reverse_ralationships表究竟是什么意思。毕竟表根本没变就是原来那个表阿,已经完整的体现了用户间关系。谁是关注谁是被关注根本没变,追人的没突然变成被追啊,携带信息完全一样。

没错,真相就是:其实表就是原来的表,根本没变。表没有反转,反转的是外键,从而反转查询方向。因为Users表和relationships表通过外键一一对应,所以把表重命是为了另设外键。根本就没有任何将表进行反转的处理。。你把User.rb中的reverse_relationships 都改成 same_relationships 试试,结果一样。取名reverse, 其实是外键和查询方向的reverse。

先说外键

第十章的user.microposts比较简单, 生成micropost时无须指定外键,因为micopost 模型中就是user_id,只要正确定义了用户和微博之间的关联关系(has_many,belongs_to),使用user.microposts.build创建新微薄时,rails 会自动将micropost中的user_id赋值为相应的user.id。

运行验证一下,rails console --sandbox:
1.9.3-p429 :001 > User.first.microposts.build
会新建一个micropost,micropost的user_id属性 自动赋值为 user.id (此例为User.first.id, "1"),其他属性为nil,待给参数
User Load (0.5ms) SELECT "users".* FROM "users" LIMIT 1
=> #<Micropost id: nil, content: nil, user_id: 1, created_at: nil, updated_at: nil>

而relationship表中没有叫user_id 的,只有对应User的follower_id和followed_id,所以User表必须通过指定的外键和relationship表一一对应。

书中先指定的外键是follower_id(你完全可以先指定followed_id),那么使用 user.relationships.build(followed_id: ...)建立relationship时,被设为外键的follower_id 会被自动赋对应的 user.id值,而followed_id是你给的参数,从而得到relationship表中的一行具体的relationship


1.9.3-p429 :002 > User.first.relationships
会列出 User.first 的所有的 follower_id =1的 relationships表
User Load (0.4ms) SELECT "users".* FROM "users" LIMIT 1
Relationship Load (46.7ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = 1
=> [#<Relationship id: 21, follower_id: 1, followed_id: 2, created_at: "2013-07-21 13:52:10", updated_at: "2013-07-21 13:52:10">]


1.9.3-p429 :003 > User.first.relationships.build
会新建一个relationship, 其中follower_id 是User指定的外键,被赋值User.first.id,而followed_id则是nil,待给参数
User Load (0.4ms) SELECT "users".* FROM "users" LIMIT 1
=> #<Relationship id: nil, follower_id: 1, followed_id: nil, created_at: nil, updated_at: nil>


1.9.3-p429 :004 > User.first.relationships.build(followed_id: 2)
(想让用户1关注用户2,传入参数。注意没save,relationship_id 为nil。要save 用 User.first.relationships.create!(followed_id: 2))。
User Load (0.4ms) SELECT "users".* FROM "users" LIMIT 1
=> #<Relationship id: nil, follower_id: 1, followed_id: 2, created_at: nil, updated_at: nil>

relationship表建立后,就可以通过
has_many:followeds,through: :relationships
使用followed_id 生成 user.followeds 数组。为了好听,书中用
has_many:followed_users, through: :relationships, source: :followed 把user.followeds改成了 user.followed_users

user.followed_users 通过relationships表将 follower_id =(user.id) 所有对应的 followed_id 从数据库中找出生成数组。即该user的“关注的人”列表。
(例如下面我找User.first所有关注的人,即查询follower_id = 1 对应的 followed_id)

运行rails console --sandbox:
1.9.3-p429 :005 > User.first.followed_users
得到了User.first 的所有关注的人(我这只有一个,User.id=2的, 说明User1 只关注了 User2)。
User Load (0.4ms) SELECT "users".* FROM "users" LIMIT 1
User Load (0.4ms) SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = 1
=> [#<User id: 2, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2013-07-21 10:50:11", updated_at: "2013-07-21 10:50:11", password_digest: "$2a$.....", remember_token: "9c2eccc....."]


困惑的revese_relationships表

上面说明了指定了follower_id为外键的情况

所以User.rb模型中这两句的意思就是

has_many :relationships,foreign_key:"follower_id",dependent: :destroy
对于relationships表,User_id固定对应follower_id,所以使用user.relationships得到的是所有 follower_id值为user_id的 relationship数组
has_many :followed_users, through: :relationships, source: :followed
通过表查询对应的followed_id拥有了很多followed_users。所以使用user.followed_users可得到该user的followed_users数组,即在追哪些人。

下面说怎么通过关系表(再次强调,就是一张表) 查找出该user所有的“粉丝”列表。

通过调换 followed_id为外键(所以通过表查询的方向就反过来了,现在固定的是followed_id,来查询表中对应的follower_id数组。(比如对于user2, user.followers则通过relationships表 将 followed_id =2 对应的所有 follower_id 找出来,即user2的粉丝数组)

所以User.rb模型中这两句的意思就是

has_many :same_relationships, foreign_key: "followed_id",class_name: "Relationship",dependent: :destroy
对于same_relationships表(呵呵,不用reverse试试),User_id固定对应于followed_id,所以使用user.same_relationships得到的是所有 followed_id值为user_id的 relationship数组
has_many :followers, through: :same_relationships, source: :follower
通过表查询对应的follower_id拥有了很多followers.所以使用user.followers可得到该user的followers数组,即粉丝团)

外键和表一一对应,所以表得改名,否则查询关系就冲突了,user.relationships 不知道user_id赋值给谁查询。)


(其实认真的看看下面4句中的SELECT语句就明白了,全是通过relationship表,变的只是查询的外键值)

1.9.3-p429 :006 > user2 = User.find(2)
1.9.3-p429 :007 > user2.relationships Relationship Load (0.2ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = 2 => [#<Relationship id: 24, follower_id: 2, followed_id: 1, created_at: "2013-07-29 13:29:56", updated_at: "2013-07-29 13:29:56">]


1.9.3-p429 :008 > user2.same_relationships
Relationship Load (30.8ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."followed_id" = 2
=> [#<Relationship id: 21, follower_id: 1, followed_id: 2, created_at: "2013-07-21 13:52:10", updated_at: "2013-07-21 13:52:10">]


1.9.3-p429 :009 > user2.followers User Load (0.3ms) SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = 2 => [#<User id: 1, name: "lafmad", email: "inaircastle@gmail.com", created_at: "2013-07-16 14:01:47", updated_at: "2013-07-20 03:14:16", password_digest: "$2a$10$....", remember_token: "tRLqtITZxX..."]


1.9.3-p429 :010 > user2.followed_users User Load (0.5ms) SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = 2 => [#<User id: 1, name: "lafmad", email: "inaircastle@gmail.com", created_at: "2013-07-16 14:01:47", updated_at: "2013-07-20 03:14:16", password_digest: "$2a$10$m5bBDpsDXDv......", remember_token: "tRLqtIT..."]


写完了我是更明白了,如果有读者的话,希望没把你搞的更糊涂。沉住气,忽然间一回头就明白了(然后又糊涂了,然后又明白了,嗯嗯。)


以上


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容