Rails 3中单个记录的多个外键? [英] Multiple Foreign Keys for a Single Record in Rails 3?

查看:169
本文介绍了Rails 3中单个记录的多个外键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个应用程序,用于管理参加课程的学生。该应用程序将有用户可以登录和操作学生。用户还可以对学生发表评论。所以我们的三个主要课程是学生,用户和评论。问题是我需要将个人评论与其他模型:用户和学生。所以我已经开始使用这样的基本代码...

pre $ class Student< ActiveRecord :: Base
has_many:comments
end
$ b $ class User< ActiveRecord :: Base
has_many:comments
end
$ b $ class评论< ActiveRecord :: Base
belongs_to:student
belongs_to:user
attr_accessible:comment
end

因此,在评论表中,一个记录将具有以下字段:

$ $ p $ $ $ $ $ $ $
comment
student_id
user_id
created_at
updated_at



这提出了几个问题。首先,用于创建关联对象的良好的Rails语法被打破。如果我想发表新的评论,我必须在外键之间进行选择。所以...

$ p $ User.comments.create(attributes = {})

OR

  Student.comments.create(attributes = {})

另一种方法是任意选择一个外键,然后手动添加attrs散列。所以...

  User.comments.create(:comment =>Lorem ipsum,:student_id => 1 )

这个选项的问题是我必须在我的Comment模型中列出attr_accessible下的student_id。但是我的理解是,这会带来安全风险,因为有人可能会在技术上出现,并使用批量分配与其他学生重新联系评论。



一般使用Rails进行数据建模。我目前在Rails中构建的应用程序是我最初几年前在PHP / MySQL中编写的应用程序。当我第一次学习SQL时,非常重视正常化的思想。因此,例如,如果您有一个存储名称和地址的联系人表,则可能会使用很多外键关系来避免重复数据。如果你有一个状态栏,你不想直接列出状态。否则,您可能会有成千上万的行都包含像Texas这样的字符串值。有一个单独的状态表更好,并使用外键关系将其与联系人表关联起来。我对优秀SQL理论的理解是,任何可重复的值都应该被分解到自己的表中。当然,为了完全标准化数据库,你最终可能会在联系人表中获得不少外键。 (state_id,gender_id等)

那么在Rails方式下如何去做这件事?



<澄清(对不起,我知道这是越来越长)我已经考虑了另外两种常见的方法:has_many:through =>和多态关联。尽我所知,既不能解决上述问题。原因如下:



has_many:through =>在博客的情况下工作正常。所以我们有评论,文章和用户模型。用户通过文章有很多评论。 (顺便说一下,Apress的Beginning Rails 3出现了这样的一个例子)。问题是,为了这个工作(如果我没有弄错的话),每篇文章都必须属于一个特定的用户。在我的情况下(我的学生模型在这里类似于文章)没有一个用户拥有一个学生。所以我不能说一个用户有很多评论通过学生。可能有多个用户对同一个学生发表评论。

最后,我们有多态关联。这对于多个外键很有效,假设没有一个记录需要属于多个外部类。在RailsCasts第154集中,Ryan Bates举了一个例子,其中评论可以属于文章或照片或事件。但是,如果一个评论需要属于一个以上的话呢?

因此,总而言之,我可以通过手动指定一个或两个外部键,但是这并不能解决attr_accessible的问题。



在此先感谢您的任何建议!

解决方案

当我开始使用rails时,我有你的问题。如何在create方法中整齐地设置两个关联,同时确保association_id被保护。



Wukerplank是正确的 - 您不能通过批量分配来设置第二个关联,但是您仍然可以直接在一个新行中分配association_id。

这种类型的关联赋值是非常常见的,遍布在我的代码中,因为在很多情况下,超过一个协会。

另外,要清楚:多态协会和has_many:通过将不会解决你的情况。你有两个单独的关联(评论的所有者和评论的主体) - 他们不能合理化为一个。



编辑:这里是你应该怎么做:

$ p $ @student = Student.find_by_id(params [:id])
@comment = @ student.comments.build(params [:comment])#第一个关联在这里设置
@ comment.user = current_user#第二个关联在这里设置
if @ comment.save
# ..
else
#...
end

使用Object.associations.build,Rails会自动创建一个新的关联对象,并在保存时将其与Object关联。


I am working on an app that will manage students enrolled in a course. The app will have users who can log in and manipulate students. Users can also comment on students. So three of our main classes are Student, User, and Comment. The problem is that I need to associate individual comments with both of the other models: User and Student. So I've started with some basic code like this...

class Student < ActiveRecord::Base
  has_many :comments
end

class User < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :student
  belongs_to :user
  attr_accessible :comment
end

So in the comments table, a single record would have the following fields:

id
comment
student_id
user_id
created_at
updated_at

This presents several problems. First, the nice Rails syntax for creating associated objects breaks down. If I want to make a new comment, I have to choose between the foreign keys. So...

User.comments.create(attributes={})

OR

Student.comments.create(attributes={})

Another option is to arbitrarily pick one of the foreign keys, and manually add it to the attrs hash. So...

User.comments.create(:comment => "Lorem ipsum", :student_id => 1)

The problem with this option is that I have to list student_id under attr_accessible in my Comment model. But my understanding is that this poses a security risk since someone could technically come along and reassociate the comment with a different student using mass assignment.

This leads to a further question about data modeling in general using Rails. The app I'm currently building in Rails is one that I originally wrote in PHP/MySQL a few years ago. When I first studied SQL, great importance was placed on the idea of normalization. So, for example, if you have a contacts table which stores names and addresses, you would use a lot of foreign key relationships to avoid repeating data. If you have a state column, you wouldn't want to list the states directly. Otherwise you could potentially have thousands of rows that all contain string values like "Texas." Much better to have a separate states table and associate it with your contacts table using foreign key relationships. My understanding of good SQL theory was that any values which could be repeating should be separated into their own tables. Of course, in order to fully normalize the database, you would likely end up with quite a few foreign keys in the contacts table. (state_id, gender_id, etc.)

So how does one go about this in "the Rails way"?

For clarification (sorry, I know this is getting long) I have considered two other common approaches: "has_many :through =>" and polymorphic associations. As best I can tell, neither solves the above stated problem. Here's why:

"has_many :through =>" works fine in a case like a blog. So we have Comment, Article, and User models. Users have many Comments through Articles. (Such an example appears in Beginning Rails 3 from Apress. Great book, by the way.) The problem is that for this to work (if I'm not mistaken) each article has to belong to a specific user. In my case (where my Student model is here analogous to Article) no single user owns a student. So I can't say that a User has many comments through Students. There could be multiple users commenting on the same student.

Lastly, we have polymorphic associations. This works great for multiple foreign keys assuming that no one record needs to belong to more than one foreign class. In RailsCasts episode #154, Ryan Bates gives an example where comments could belong to articles OR photos OR events. But what if a single comment needs to belong more than one?

So in summary, I can make my User, Student, Comment scenario work by manually assigning one or both foreign keys, but this does not solve the issue of attr_accessible.

Thanks in advance for any advice!

解决方案

I had your EXACT question when I started with rails. How to set two associations neatly in the create method while ensuring the association_ids are protected.

Wukerplank is right - you can't set the second association through mass assignment, but you can still assign the association_id directly in a new line.

This type of association assignment is very common and is littered throughout my code, since there are many situations where one object has more than one association.

Also, to be clear: Polymorphic associations and has_many :through will not solve your situation at all. You have two separate associations (the 'owner' of a comment and the 'subject' of a comment) - they can't be rationalised into one.

EDIT: Here's how you should do it:

@student = Student.find_by_id(params[:id])
@comment = @student.comments.build(params[:comment]) #First association is set here
@comment.user = current_user #Second association is set here
if @comment.save
  # ...
else
  # ...
end

By using the Object.associations.build, Rails automatically creates a new 'association' object and associates it with Object when you save it.

这篇关于Rails 3中单个记录的多个外键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆