如何在不遵循任何命名约定的2个字段之间建立关联?

时间:2011-10-18 05:32:50

标签: ruby-on-rails ruby

我的公司有一个很久以前用PHP构建的旧网站。我相信数据库模式代表了从未以战略方式考虑过的请求缓慢积累。现在我们抛出PHP代码并使用Rails构建站点。数据库架构仍然保持不变。

我只是围绕Rails,所以这可能是一个简单的问题。

我有一个文章表,数据如下所示:

id: 1102129
article_type_id: 5
old_article_id: 0
title: Zombie Film Locations
subtitle: Hollywood-inspired survival tips for destinations teeming with the undead
display_date: 0000-00-00
author_id: 29
thumbnail_image_id: 12033473
index_image_id: 12033473
article_image_id: 12033473
is_archived: 0
is_featured: 1
is_published: 1
date_to_show: 2011-10-04 00:00:00
off_the_path: 0
created: 2011-10-04 12:45:07
modified: 2011-10-11 15:33:59
fact_check_date: 0000-00-00 00:00:00
unpublish_date: 0000-00-00
is_qsfeatured: 1
featured_order: 0

第二行:

id: 1102128
article_type_id: 14
old_article_id: 0
title: Hotel Adagio [id]35677
subtitle: Hotel Adagio
display_date: 2011-09-29
author_id: 0
thumbnail_image_id: NULL
index_image_id: NULL
article_image_id: NULL
is_archived: 0
is_featured: 0
is_published: 1
date_to_show: 2011-09-29 12:50:38
off_the_path: 0
created: 2011-09-29 12:50:38
modified: 2011-09-29 12:50:38
fact_check_date: NULL
unpublish_date: NULL
is_qsfeatured: 0
featured_order: NULL

图像数据如下:

id: 6722
old_id: 0
type: Index
association_type: TopTen
association_id: 1102129
position: 0
copyright: AMC
caption: The Walking Dead portrays an abandoned, corpse-ridden downtown Atlanta, one of 10 zombie film locations we've scouted out to help you survive (and hide) should the dead rise.
alt_text: Zombie film locations
url: photos/index-TopTens/walkingdeadindex.jpg
_url: 
name: index
published: 0
description: 

第二行:

id: 6723
old_id: 0
type: Thumbnail
association_type: TopTen
association_id: 1102129
position: 0
copyright: AMC
caption: The Walking Dead portrays an abandoned, corpse-ridden downtown Atlanta, one of 10 zombie film locations we've scouted out to help you survive (and hide) should the dead rise.
alt_text: Zombie film locations
url: photos/thumb-TopTens/walkingdeadthumb.jpg
_url: 
name: thumbnail
published: 0
description:

images表中的association_id是文章的id,尽管数据库中没有指定外键。

获得文章后如何获取所有图像?

现在控制器中我做了:

@articles = Article.where(:article_type_id => 5).order("id DESC").limit(5)

在视图中我做了类似的事情:

<%= article.title %>

但是如何从文章模型中引用图像?

为了使这更复杂,图像是多态的,所以我不能简单地创建从图像到文章的外键。图像有时也会映射到“travel_guides”和“slideshows”,这是我们拥有的另外两张表。

更新:

更改了文章,现在它已经:

has_many:images,:foreign_key =&gt; 'association_id'

将我的控制器代码更改为:

@articles = Article.where(:article_type_id => 5).order("id DESC").limit(5).joins(:images)

但在我看来,我这样做:

&lt;%= article.images.url%&gt;

我得到“no method url”错误。

我在做:

&lt;%= article.image.url%&gt;

在图像上没有“s”,然后我得到“没有方法'图像'”。

更新:

所以,好吧,在命令行中,我运行“rails c”进入控制台,然后运行我在控制器中使用的代码:

@articles = Article.where(:article_type_id =&gt; 5).order(“id DESC”)。limit(5).joins(:image)

这给了我:

 @articles = Article.where(:article_type_id => 5).order("id DESC").limit(5).joins(:image)
  Article Load (11.5ms)  SELECT `articles`.* FROM `articles` INNER JOIN `images` ON `images`.`association_id` = `articles`.`id` WHERE `articles`.`article_type_id` = 5 ORDER BY id DESC LIMIT 5
 => [#<Article id: 1102129, article_type_id: 5, old_article_id: 0, title: "Zombie Film Locations", subtitle: "Hollywood-inspired survival tips for destinations t...", display_date: nil, author_id: 29, thumbnail_image_id: 12033473, index_image_id: 12033473, article_image_id: 12033473, is_archived: false, is_featured: true, is_published: true, date_to_show: "2011-10-04 00:00:00", off_the_path: false, created: "2011-10-04 12:45:07", modified: "2011-10-18 10:44:15", fact_check_date: nil, unpublish_date: nil, is_qsfeatured: true, featured_order: 1, slug: "zombie-film-locations">, #<Article id: 1102129, article_type_id: 5, old_article_id: 0, title: "Zombie Film Locations", subtitle: "Hollywood-inspired survival tips for destinations t...", display_date: nil, author_id: 29, thumbnail_image_id: 12033473, index_image_id: 12033473, article_image_id: 12033473, is_archived: false, is_featured: true, is_published: true, date_to_show: "2011-10-04 00:00:00", off_the_path: false, created: "2011-10-04 12:45:07", modified: "2011-10-18 10:44:15", fact_check_date: nil, unpublish_date: nil, is_qsfeatured: true, featured_order: 1, slug: "zombie-film-locations">, #<Article id: 1102129, article_type_id: 5, old_article_id: 0, title: "Zombie Film Locations", subtitle: "Hollywood-inspired survival tips for destinations t...", display_date: nil, author_id: 29, thumbnail_image_id: 12033473, index_image_id: 12033473, article_image_id: 12033473, is_archived: false, is_featured: true, is_published: true, date_to_show: "2011-10-04 00:00:00", off_the_path: false, created: "2011-10-04 12:45:07", modified: "2011-10-18 10:44:15", fact_check_date: nil, unpublish_date: nil, is_qsfeatured: true, featured_order: 1, slug: "zombie-film-locations">, #<Article id: 1102122, article_type_id: 5, old_article_id: 0, title: "Nude Vacations", subtitle: "These places to get naked around the world make for...", display_date: nil, author_id: 574, thumbnail_image_id: 12024629, index_image_id: 12024629, article_image_id: 12024629, is_archived: false, is_featured: true, is_published: true, date_to_show: "2011-09-23 00:00:00", off_the_path: false, created: "2011-09-23 13:13:41", modified: "2011-10-18 10:44:15", fact_check_date: nil, unpublish_date: nil, is_qsfeatured: true, featured_order: 2, slug: "nude-vacations">, #<Article id: 1102122, article_type_id: 5, old_article_id: 0, title: "Nude Vacations", subtitle: "These places to get naked around the world make for...", display_date: nil, author_id: 574, thumbnail_image_id: 12024629, index_image_id: 12024629, article_image_id: 12024629, is_archived: false, is_featured: true, is_published: true, date_to_show: "2011-09-23 00:00:00", off_the_path: false, created: "2011-09-23 13:13:41", modified: "2011-10-18 10:44:15", fact_check_date: nil, unpublish_date: nil, is_qsfeatured: true, featured_order: 2, slug: "nude-vacations">] 

因此,尽管有联接,但没有任何图像数据显示出来。

更新:

嗯,现在我看到我在轨道控制台上的那个块,我看到每篇文章都返回了3次,我假设因为JOIN:

文章编号:1102129,article_type_id:5,old_article_id:0,标题:“Zombie Film Locations”,副标题:“好莱坞风格的目的地生存技巧...”,display_date:nil,author_id:29,thumbnail_image_id: 12033473,index_image_id:12033473,article_image_id:12033473,is_archived:false,is_featured:true,is_published:true,date_to_show:“2011-10-04 00:00:00”,off_the_path:false,created:“2011-10-04 12 :45:07“,修改:”2011-10-18 10:44:15“,fact_check_date:nil,unpublish_date:nil,is_qsfeatured:true,featured_order:1,slug:”zombie-film-locations“&gt;,< / p>

所以我得到3篇文章,因为3个与图像的关联,但我没有得到图像。这是两个世界中最糟糕的。

真的,对图像进行单独查询会更容易。

更新:

这个SQL给了我想要的东西,但我似乎无法将其变成Rails查询:

SELECT articles.title, articles.subtitle, images.url, images.caption 
FROM articles 
JOIN images ON articles.id = images.association_id 
WHERE images.type='Thumbnail' 
ORDER BY articles.id desc 
LIMIT 5 \G

更新:

我无法让它发挥作用。我认为Ruby导师会教我一些基本的Ruby和Rails东西。我很乐意付钱。我在这里发布我的问题:http://tutorruby.com/question/show?id=3235

4 个答案:

答案 0 :(得分:1)

要访问文章中的图像,您需要在Article类中添加关联:

class Article
  has_many :images, :foreign_key => :association_id
end

您提到有时图像会映射到travel_guides和幻灯片(另外两张表)。您必须为每个表添加关联。所以你可以这样做:

class Article < ActiveRecord::Base
  has_many :images, :foreign_key => :association_id
  has_many :travel_guides, :foreign_key => :association_id
  has_many :slideshow_images, :foreign_key => :association_id
end

建立反向关联通常也是一个好主意:

class Image < ActiveRecord::Base
  belongs_to :article, :foreign_key => :association_id
end
class TravelGuide < ActiveRecord::Base
  belongs_to :article, :foreign_key => :association_id
end
class SlideshowImage < ActiveRecord::Base
  set_table_name :slideshows
  belongs_to :article, :foreign_key => :association_id
end

需要考虑的一些事项:

  • 我在* has_many *关联中省略了:dependent选项。这通常不是一个好主意。您可以设置:depedent =&gt; :destroy ,以便您可以在图像类中调用一些清理逻辑(删除图像文件)。

  • 如果您没有简单连接,则应考虑将:conditions 选项添加到has_many(或属于)。

  • 如果上述建议无法解决您的所有问题,则可以使用单表继承和/或多态关联。

答案 1 :(得分:1)

在图像关联中指定“has_many”时,表示文章包含图像集合,因此article.images返回一个数组。数组上没有定义'url'方法。要访问url方法,您需要访问每个单独的数组成员,并调用该对象上的url。类似的东西:

article.images[0].url

article.images.first.url

答案 2 :(得分:0)

您需要在模型中指定关联。有一个像你一样的namin惯例,但你的表并没有遵循,但这根本不是问题。有两种可能的解决方案。

1。)你重命名数据库中的列(当应用程序仍在使用PHP生产时,什么不会工作)

2.。)使用:foreign_key参数指定关联,如下所示:

文章:

has_many :images, :foreign_key => 'association_id'

照片:

belongs_to :article, :foreign_key => 'association_id'

但是你需要参加一些事情。您将在命名表格图像时遇到一些问题,因为它们还有一个公共文件夹“images”,当您调用以数字开头的图片时,rails将其解释为id并尝试从数据库中获取Image实例而不是传送图像。

Secound问题可能会导致一个名为“association_type”的字段,它会暗示这些字段是多态关联。当你切换到rails时,你也可以重命名。

答案 3 :(得分:0)

articles = Article.includes(:images).where(:article_type_id => 5, :images => { :image_type => 'Thumbnail' }).order('articles.id DESC').limit(5) #no database query is fired yet by rails
article = articles.first # Here we fire the first query, and this query also fetches the image of the article 
article.images.first #again fires no query but returns the first image of the article

还有另一种情况,您应该触发数据库查询以从数据库中仅获取一个图像。 那你应该做点什么,

articles = Article.where(:article_type_id => 5).order("id DESC").limit(5) #again fires no db query
article = articles.first #fires db query to get first article
image = article.images.first #fires query for only first image of the article 

如果每篇文章的图像数量较少,则第一种方法是有效的,但如果每篇文章有大量图像,则第二种方法是有效的

现在你的rails查询上面发布的sql,

SELECT articles.title, articles.subtitle, images.url, images.caption 
FROM articles 
JOIN images ON articles.id = images.association_id 
WHERE images.type='Thumbnail' 
ORDER BY articles.id desc 
LIMIT 5
articles = Article.joins(:images).select("articles.title, articles.subtitle, images.url, images.caption").where("images.type = 'Thumbnail'").order("articles.id DESC").limit(5)
article = articles.first 
first_image = article.images.first