Multiple Foreign Keys for a Single Record in Rails 3?

孤者浪人 提交于 2019-12-03 08:33:14

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.

I think polymorphic association is the way to go. I'd recommend using a plugin instead of "rolling your own". I had great results with ActsAsCommentable (on Github).

As for your attr_accessible problem: You are right, it's more secure to do this. But it doesn't inhibit what you are trying to do.

I assume that you have something that holds the current user, in my example current_user

@student = Student.find(params[:id])
@comment = Comment.new(params[:comment]) # <= mass assignment
@comment.student = @student              # <= no mass assignment
@comment.user    = current_user          # <= no mass assignment
if @comment.save
  # ...
else
  # ...
end

The attr_accessible protects you from somebody sneaking a params[:comment][:student_id] in, but it won't prevent the attribute from being set another way.

You still can get all comments of your users through the has_many :comments association, but you can also display who commented on a student thanks to the belongs_to :user association:

<h1><%= @student.name %></h1>

<h2>Comments</h2>

<%- @student.comments.each do |comment| -%>
    <p><%= comment.text %><br />
    by <%= comment.user.name %></p>
<%- end -%>

PLUS:

Don't over engineer your app. Having a state:string field is perfectly fine unless you want to do something meaningful with a State object, like storing all districts and counties. But if all you need to know a students state, a text field is perfectly fine. This is also true for gender and such.

Well, for the first part. If I understood your question correctly, I think, that since comments are listed within students controller, you should associate them through Student model (it just seems logical to me). However, to protect it from assigning wrong user id, you could do something like this

@student = Student.find params[:id]
@student.comments.create :user => current_user

current_user might be a helper that does User.find session[:user_id] or something like that.

has_many :through association doesn't make sense here. You could use it to associate User and Student through Comment, but not User and Comment through Student

Hope that helps.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!