I have a model Post that has_many :comments. The form that will post the comment will be shown along with the post in posts/show.html.erb. I have a comments_controller that should handle the creation of comments. Searching on google, I found
<%= form_for([#post, Comment.new], :controller => 'comments', :action => 'create') do |f| %>
But this doesn't work. How do I do this ?
class Post < ActiveRecord::Base
has_many :comments
accepts_nested_attributes_for :comments
#...
class Comment < ActiveRecord::Base
belongs_to :post
#...
Then in the form
form_for #post do |f|
f.fields_for :comments do |c|
c.text_field :title
#...
f.submit
this would create the associated object through active record's accepts_nested_attributes_for, which doesn't require a separate comments_controller. you are submitting to the posts controller, which is handling creating the associated object during the update of the post.
with a comments_controller, you could do one of two things:
send item_id as a param to comments_controller#new, grab the item, then build the new comment from it
#post = Post.find(params[:item_id); #comment = #post.comments.build
put the post_id in a hidden field on the form and just create the comment as normal
# in the controller
#comment = Comment.create(params[:comment])
# in the view
form_for #comment do |f|
f.text_field :title
#...
f.hidden_field :post_id, value: #post.id
Related
I have 3 objects : article, comment and user
I want, when a comment is published with a form, that the comment is associated with article AND user.
When I had only article and comment, it was perfect : we could send the form, create the comment, and it was showed.
Comment's form :
<%= form_with(model: [ #article, #article.comments.build ], local: true) do |form| %>
<p>
<%= form.label :body %><br>
<%= form.text_area(:body, {:class => 'form-control'} ) %>
</p>
<p>
<%= form.submit({:class => 'btn btn-success'}) %>
</p>
<% end %>
Create method of CommentsController :
before_action :authenticate_user!
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.build(comment_params)
#comment.commenter = current_user
#comment.save
redirect_to article_path(#article)
end
And models :
class Comment < ApplicationRecord
belongs_to :article
belongs_to :user
end
class User < ApplicationRecord
has_many :comments, dependent: :destroy
# Some devise things
end
class Comment < ApplicationRecord
belongs_to :article
belongs_to :user
end
I want that the comment is pushed on the database, but the actual result is nothing is done : the comment is simply ignored, and I don't know why. I already search here, I found a topic with a similar issue, but the solution was my actual code.
Okay, so I am currently working on a commenting system where posts belong to classrooms and posts have comments. So classrooms have comments through posts.
Here are the models
class Classroom < ActiveRecord::Base
has_many :posts
has_many :comments, through: :posts
...
end
class Comment < ActiveRecord::Base
belongs_to :post
...
end
class Post < ActiveRecord::Base
belongs_to :classroom
has_many :comments
...
end
I'm trying to save post_ids but it won't let me with a simple hidden field so I tried it with a value and it still doesn't work. it says that post_id is an undefined method.
Here is my classroom controller's show method because it is where the new comment form is being rendered.
def show
#classroom = Classroom.find(params[:id])
#posts = #classroom.posts
#comments = #classroom.comments
#comment = Comment.new
end
Here is the new comment form.
<%= simple_form_for(#comment) do |f| %>
<%= f.error_notification %>
<%= f.text_area :content %>
<%= f.hidden_field :post_id, :value => #classroom.post_id %>
<div class="form-actions">
<br>
<%= f.button :submit %>
</div>
<% end %>
Error Message
NoMethodError in Classrooms#show
undefined method `post_id' for Classroom:0x007f52aa646b18
How do I save the post_id?
Thanks!
NoMethodError in Classrooms#show undefined method `post_id' for
Classroom:0x007f52aa646b18
<%= f.hidden_field :post_id, :value => #classroom.post_id %>
The error is obvious as you are doing #classroom.post_id as Classroom don't have a field called post_id
Define a #post with the help of #classroom
def show
#classroom = Classroom.find(params[:id])
#post = Post.where(classroom_id: #classroom.id).first
#posts = #classroom.posts
#comments = #classroom.comments
#comment = Comment.new
end
and use that in the hidden_field
<%= f.hidden_field :post_id, :value => #post.id %>
I have an application where there are a few nested models... Two parent models and two child models.
I'm trying to create comments on the child models and I had it working great for the first one until I realized I have to create comments on the second child so I realized I had to scrap my work because I was targeting the first parent + child model in the comments controller. So I decided to watch Ryan Bates screencast (http://railscasts.com/episodes/154-polymorphic-association) on creating comments that belong to multiple models...unfortunately, it's not working for me and I'm assuming its because I am trying to create comments on the child models. I will show you what I was using before that worked for the one model and I'll show you what im doing now that doesnt work...
here is what i had for the comments controller
def create
#collection = Collection.find(params[:collection_id])
#design = #collection.designs.find(params[:design_id])
#comment = #design.comments.create(comment_params)
#comment.user = current_user
#comment.save
redirect_to collection_design_path(#collection, #design)
end
and here is what it is now after i tried to implement it to work for multiple models
def create
#commentable = find_commentable
#comment = #commentable.comments.build(comment_params)
#comment.user = current_user
#comment.save
end
private
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
here are my crazy routes
resources :collections do
member do
post :like
post :unlike
end
resources :designs do
resources :comments
member do
post :like
post :unlike
end
end
end
anyone have any other different ideas for created comments for multiple nested models? Thanks in advance for the help.
EDIT:
Here was the form I was using for the one model
<%= form_for([#collection, #design, #design.comments.build]) do |f| %>
<%= f.text_area :comment %>
<%= f.submit "Comment", :class => "btn" %>
<% end %>
and here is the one i'm using now
<%= form_for([#collection, #design, #commentable, Comment.new]) do |f| %>
<%= f.text_area :comment %>
<%= f.submit "Comment", :class => "btn" %>
<% end %>
Right now when I try to submit the new comment form I get this error
undefined method `comments' for #<Collection:0x0000010150cf88>
which points back to the create method
EDIT 2
Here is my comment model
belongs_to :commentable, :polymorphic => true
belongs_to :user
Here is my design model (which is a child of the collection model)
has_many :comments, :dependent => :destroy, :as => :commentable
belongs_to :user
belongs_to :collection
and my collection model (which has the child model: design)
belongs_to :user
has_many :designs, :dependent => :destroy
and there is more to the models but its not related to the problem.
I have 3 models: User, Answer and Question.
user.rb
has_many :questions
has_many :answers
question.rb
has_many :answers
belongs_to :user
accept_nested_attributes_for :answers
answer.rb
belongs_to :question
belongs_to :user
In questions/show.html.erb
form_for #question do |f|
f.fields_for :answers, #question.answers.build do |builder|
builder.text_area, :body
end
f.submit
end
Submit calls the questions#update action and, thanks to nested resources, will the new answer be saved in the database. I wonder: how can I save the user_id column for answer, in the database, after the question is submitted? Can I somehow pass current_user.id to answer's user_id column after submitting the form?
You have to pass the user parameter in your controller's create action (also you should build your nested attributes in the controller):
def new
#question = Question.new
#question.answers.build
end
def create
#question = current_user.questions.new(params[:questions])
//The line below is what will save the current user to the answers table
#question.answers.first.user = current_user
....
end
Your view's form should therefore look like:
form_for #question do |f|
f.fields_for :answers do |builder|
builder.text_area, :body
end
f.submit
end
You could do something like this in your controller's update action:
# questions_controller
def update
params[:question][:answers_attributes].each do |answer_attribute|
answer_attribute.merge!(:user_id => current_user.id)
end
if #question.update_attributes(params[:question])
...
end
end
Another more simple solution would be to add the user_id to your form like this:
form_for #question do |f|
f.fields_for :answers, #question.answers.build(:user_id => current_user.id) do |builder|
builder.text_area, :body
builder.hidden_field :user_id # This will hold the the user id of the current_user if the question is new
end
f.submit
end
The problem with this approach is that users would be able to edit the value through a HTML source code inspector (like in chrome), and thereby set the user to someone else. You could of course validate this in some way, but that too would be a bit complex.
'current_user' is a devise helper method. it can be accessed in controllers n views directly.
if i m not wrong, only the new answer should have the current_user.id Old answers should not be updated. u can do this as
f.fields_for :answers, #question.answers.build do |a|
a.hidden_field :user_id, :value => current_user.id
a.submit
I am having troubles with a polymorphic association in Rails. I have an application where it should be possible to comment on different models, such as Posts, Images, Projects
Right now I just have Posts to comment on. On the start page there is an index view of the latest Posts and each Post has a small Comment form underneath to comment on via Ajax, very much like Facebook.
My models look like this:
class Post < ActiveRecord::Base
belongs_to :post_category
belongs_to :user
has_many :comments, :as => :commentable
validates_presence_of :user_id
validates_presence_of :post_category_id
validates_presence_of :title
validates_presence_of :body
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commentable, :polymorphic => true
end
Now in my Comments controller I added the following method (I think I took it from railscasts or something), which I assume tries to find out the #commentable dynamically when creating an comment.
But this always returns the error undefined methodcomments' for nil:NilClass`
# find commentable (parent) item
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value) unless name == 'user_id'
end
end
nil
end
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
if #comment.save
redirect_to #comment, :notice => 'Comment was successfully created.'
redirect_to :id => nil
else
render :action => "new"
end
end
The two things I tried in my partial were:
leaving the commentable info out of the form
= form_for [#commentable, Comment.new], :remote => true do |f|
#new_comment.add_comment
= f.hidden_field :user_id, :value => current_user.id
= f.text_field :content, :size => 55, :value => 'leave a comment...', :class => 'comment_form'
= f.submit "send"
and 2. passing the commentable_id and commentable_type
= form_for [#commentable, Comment.new], :remote => true do |f|
#new_comment.add_comment
= f.hidden_field :user_id, :value => current_user.id
= f.hidden_field :commentable_id, :value => post_id
= f.hidden_field :commentable_type, :value => 'Post'
= f.text_field :content, :size => 55, :value => 'leave a comment...', :onfocus => 'this.select()', :class => 'comment_form'
= f.submit "send"
both without luck. Any help would be highly appreciated.
the whole comments controller code is in this gist: https://gist.github.com/1334286
It seems like the commentable is not assigned correctly in the comments controller. This could have multiple reasons. Here is a setup that should work for you:
In the Posts controller, e.g. action "show":
#post = Post.find(params[:id])
In the posts/show view comments form:
= form_for [#post, #post.comments.new], :remote => true do |f|
You should be able to use your comments controller as it - but you should change the render to e.g. a redirect_to :back in the create action since the comments controller will most probably not have a "new" view on its own (it is dependent from the commentable)
Also, make sure that you have nested routes for all resources that can act as a commentable, like so:
resources :posts do
resources :comments do
end
resources :comments do
resources :comments # subomments
end
UPDATED to reflect information in the comments
Don't use #commentable in the post show view, since it's only defined in the comments controller.
Do this instead:
_comment.html.erb: (the comment partial in the post show view)
<%= form_for ([comments, #vote]), remote: true do |f| %>
posts/posts_controller.rb:
<%= form_for ([#post, #vote]), remote: true do |f| %>