I am working on a (relatively) simple, blog-like Rails app and I'm stumped by how to handle a polymorphic set up.
I have models and controllers for story and comment [i.e., on a story], with comments and submit form displayed oh the story's show.html.erb, as well as user authentication (simple logon) for the app (but without specific hooks to any feature or function yet). So far so good.
I can post and display comments on a given story.
The 'story has_many comments', and 'comment belongs_to story'. The comment db table includes story_id column, which is appropriately populated with each comment post), and user_id column which, mysteriously (to me) is not.
When I try change comment.rb "belongs_to :story" to "belongs_to :story, :user", or "belongs_to :story, polymorphic => true", the page throws up a screen of errors.
To be honest, I've cobbled this together from several different tutorials, and I suspect I'm trying to mix apples and oranges.
I wonder if anyone can point me to a simple description of how to establish this kind of functionality.
As always, looking for the easy(/iest) way out...
check out "this screencast":http://railscasts.com/episodes/154-polymorphic-association
I think this is the best example to explain what the polymorphic association is.
In the situation you're describing, there really aren't any polymorphic associations in your data model. A polymorphic association describes a relationship between one and many models, where the many models all have the same type of relationship with the original model. For example, a Tag model might have polymorphic relationships with Story or User, since either could be possibly tagged.
In your model, the Comment's User and Story associations actually represent different relationships.
I'd create your associations like so:
- @has_many :comments@
- @has_many :stories@
- @belongs_to :story@
- @belongs_to :commenter, :class_name => 'User', :foreign_key => :user_id@
(Sometimes it's good to be explicit when naming associations. In this case, the name commenter is much more descriptive than "User")
- @has_many :comments@
In your comments controller, I'd do something like this:
@story = Story.find(params[:story_id]) @comment = @story.comments.build(params[:story].merge(:commenter => current_user))
Thanks, Pat, you posted while I was composing my reply to Jerry Guo and I guess I wasn't expecting another post quite so soon! You probably guessed that.
And somehow my post got spectacularly munged up. I can't work out the rather cryptic Formatting Help, and I guess the Formatting Help couldn't work out that I did not attempt to apply any Formatting Help, so it just went ahead and Helped! :-)
Just to clarify a couple of things with your suggestions and suppositions: The User has_many comments, but the User doesn't have any Stories (Users aren't allowed to submit stories in my blog-like app).
I had a quick try changing user.rb, comment.rb and comments_controller per your suggestions but the result is throwing errors.
Until I can work out the formatting here, I am posting comments_controller to my website http:www.designartcraft.com/comments_controller.txt
Given your clarifications, here's a revised version: http://gist.github.com/61adb61c97593a26a701
What were the errors you were seeing before?
Thanks for going to the trouble of posting that for me...
Your solution throws the error, " ActiveRecord::RecordNotFound in CommentsController#create Couldn't find Story without an ID"
If I restore comments_controller to my original config (as posted on my website above), the functionality works ok, even with your routes.rb and [models].rb edits still in place (however the user_id is still not recorded).
I'm a bit baffled by the whole belongs_to thing, e.g. Story doesn't belong to user (users don't post stories, as I mentioned previously), although a particular story comment does (users ONLY post comments to stories).
I have re-posed my question on another forum, from a different, foreign keys tack: http://railsforum.com/viewtopic.php?pid=103427#p103427
Take note of the comment display code and submit form, which are on the Story page
As I say in the post: in a nutshell, the new comment record is picking up the story_id, but not the user_id at time of posting (both are present as columns of type integer in the Story table). So I think it boils down to a routing and/or foreign key issue...
I checked your post on railsforum.com carefully again. However this is actually NOT a polymorphic associations problem. Following these steps:
Make sure that you have defined associations of Comment, with both User and Story (belongs_to :user and belogns_to :store)
comments_controller.rb, line 4, should be
@comment = Comment.new(params[:comment].merge(:user => current_user) # or, # @comment = current_user.comments.create(params[:comment])
current_user means the instance of User loaded from session. This is the default helper method name of restful-authentication.
Thanks for your suggestions. I had already ruled out the polymorphic notion and moved on to a mysterious user_id foreign key failure. Unfortunately I had to delete a post to that effect because all the code examples I pasted into it were mangled beyond recognition by our friendly neighborhood Formatting Help.
Incidentally I originally set up my comments function by adapting this tutorial: http://ruby.about.com/od/rubyonrails/ss/blogpart4_2.htm in case that has introduced some wrinkle that can't work according to your suppositions (other parts of my app were copped from other sources, though so far it has all been pretty basic, bog standard stuff AFAICT).
Associations are defined in the respective [model].rb files, as you and Pat suggested: comment belongs to user & story; story and user each has_many comments.
Trying your first suggested change in comments_controller throws the error:
" SyntaxError in CommentsController#create /home/dave/Aptana Studio/topsail/app/controllers/comments_controller.rb:8: syntax error, unexpected kIF, expecting ')'
The second throws a different error:
" NameError in CommentsController#create undefined local variable or method `current_user' for #"
Could the fault lie with my routes setup?
map.resources :comments map.resources :destinations, :has_many => :comments map.resources :users
Got it working.
Thanks all for your help and suggestions. The real issue is my lack of familiarity with ruby scripting and performing fairly basic tasks. But you knew that...
Suffice to say, I now know a great deal more than I did a coupla days ago.
Anyhoo.... the solution that worked for me is here: http://railsforum.com/viewtopic.php?pid=103555#p103555