I'm trying to follow Ryan Bates polymorphic models tutorial (Rails 3), to implement comments in my photo model. I'm having trouble when trying to create a new comment for photos since I'm in Rails 4 and I have to deal with :comment strong parameters.
Error: undefined method `user_comments_path' for #<#:0x00000107c8a200>
I have nested resources
#Nesting Resources
resources :users do
resources :photos do
resources :comments
resources :tags
end
end
So the route should be /users/friendly-id/photos/friendly-id/comments, but it's getting badly constructed, I have <%= form_for [#user, #commentable, #comment] do |f| %> in my form.
Photo Controller
#create
def show
#photo = Photo.friendly.find(params[:id])
#user = #photo.user
#tag = Tag.new
#tag.photo_id = #photo.id
#category = Category.all
#commentable = #photo
#comments = #commentable.comments
#comment = Comment.new
#zone = Zone.all
respond_to do |format|
format.html #show.html.erb
format.json {render json: #photo}
end
end
Form
<%= form_for [#user, #commentable, #comment] do |f| %>
<% if #comment.errors.any? %>
<div class="error_messages">
<h2>Please correct the following errors.</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Comments controller
class CommentsController < ApplicationController
before_filter :load_commentable
def index
#comments = #commentable.comments
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(comment_params)
if #comment.save
redirect_to #commentable, notice: "Comment created."
else
render :new
end
end
private
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
def comment_params
require(:comment).permit(:photo_id, :user_id, :content)
end
###Error 2: When I put friendly.id instead of only id in `load_commentable` method I get a Forbidden Attribute error.
end
Please someone help! Thank you
Related
I set up posts in a folder called 'contents' and then it fell over when I tried to delete the records. Why am I getting this error?
No route matches {:action=>"edit", :controller=>"content/stories", :id=>nil} missing required keys: [:id]
Routes.rb
namespace :content do
resources :posts
end
PostsController
def index
#posts = Post.all
end
def new
#post = Post.new
end
def create
#post = current_user.posts.new(post_params)
if #post.save
redirect_to content_posts_path
else
redirect_to root_path, notice: #post.errors.full_messages.first
end
end
def show
end
def delete
#post = Post.find(params[:id])
end
def destroy
post = Post.find(params[:id]).destroy
redirect_to :back
end
private
def post_params
params.require(:post).permit(:content)
end
end
show.html
<ol>
<% for p in #posts %>
<li>
<%= p.title %>
<%= link_to 'Edit', edit_content_post_path(#post) %>
<%= link_to 'Delete', content_post_path(#post), method: :delete %>
</li>
<% end %>
</ol>
#post is not defined, you probably need to use p in place of #post.
Also in your show.html which corresponds to show action, not sure how you are getting #posts.
I've read other SO articles relating to UrlGenerationError's which seem to point to singularization or plurization of a word, but I don't think that's the issue here.
It works when I remove from valuations/_form.html.erb:
<%= render "comments/comments" %>
<%= render "comments/form" %>
Submit the _form with :name & :tag_list, readd
<%= render "comments/comments" %>
<%= render "comments/form" %>
and then refresh. What's the deal when nil?
routes
resources :valuations do
resources :comments
end
comments_controller
class CommentsController < ApplicationController
before_action :load_commentable
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_action :logged_in_user, only: [:create, :destroy]
def index
#comments = #commentable.comments
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(comment_params)
if #comment.save
#comment.create_activity :create, owner: current_user
redirect_to #commentable, notice: "comment created."
else
render :new
end
end
def edit
#comment = current_user.comments.find(params[:id])
end
def update
#comment = current_user.comments.find(params[:id])
if #comment.update_attributes(comment_params)
redirect_to #commentable, notice: "Comment was updated."
else
render :edit
end
end
def destroy
#comment = current_user.comments.find(params[:id])
#comment.destroy
#comment.create_activity :destroy, owner: current_user
redirect_to #commentable, notice: "comment destroyed."
end
private
def set_comment
#comment = Comment.find(params[:id])
end
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
def comment_params
params.require(:comment).permit(:content, :commentable)
end
end
valuations_controller
class ValuationsController < ApplicationController
before_action :set_valuation, only: [:show, :edit, :update, :destroy]
before_action :logged_in_user, only: [:create, :destroy]
def index
if params[:tag]
#valuations = Valuation.tagged_with(params[:tag])
else
#valuations = Valuation.order('RANDOM()')
end
end
def show
#valuation = Valuation.find(params[:id])
#commentable = #valuation
#comments = #commentable.comments
#comment = Comment.new
end
def new
#valuation = current_user.valuations.build
#commentable = #valuation
#comments = #commentable.comments
#comment = Comment.new
end
def edit
end
def create
#valuation = current_user.valuations.build(valuation_params)
if #valuation.save
redirect_to #valuation, notice: 'Value was successfully created'
else
#feed_items = []
render 'pages/home'
end
end
def update
if #valuation.update(valuation_params)
redirect_to #valuation, notice: 'Value was successfully updated'
else
render action: 'edit'
end
end
def destroy
#valuation.destroy
redirect_to valuations_url
end
private
def set_valuation
#valuation = Valuation.find(params[:id])
end
def correct_user
#valuation = current_user.valuations.find_by(id: params[:id])
redirect_to valuations_path, notice: "Not authorized to edit this valuation" if #valuation.nil?
end
def valuation_params
params.require(:valuation).permit(:name, :private_submit, :tag_list, :content, :commentable, :comment)
end
end
comments/_form.html.erb
<%= form_for [#commentable, #comment] do |f| %>
<% if #comment.errors.any? %>
<div class="error_messages">
<h2>Please correct the following errors.</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="america">
<div class="form-group">
<%= f.text_area :content, rows: 4, class: 'form-control', placeholder: 'Enter Comment' %>
</div>
<div class="america2">
<%= button_tag(type: 'submit', class: "btn") do %>
<span class="glyphicon glyphicon-plus"></span> Comment
<% end %>
</div>
<% end %>
Thank you so much for your time.
When you have a nested resource like that, the url for creating a comment looks like /valuations/123/comments where 123 is the id of the valuation - without a valuation id this url cannot be generated.
On your Valuations#new page, the valuation (i.e. #commentable) is an unsaved object, so it has no id yet, hence the error about a missing valuation_id. In addition having one form nested within another is invalid html and will lead to odd behaviour. On your show page on the other hand, the valuation does have an id and so things should work as they are.
If you want to create a valuation and its initial comment(s) in one go then you should use accepts_nested_attributes_for and fields_for to add the fields for the comments to your valuation form (There are other ways, but accepts_nested_attributes_for is what is built into rails)
To me this is a strange one.
I have 2 models (with User), I have post and I have comment.
What I am trying to do is to have the form_for comments in the post#show view.
However for some reason when I try to create a comment I get Couldn't find Post without an ID.
When I look at the request parameters though I see:
{"utf8"=>"✓", "authenticity_token"=>"7bAXF66sghTKAF7b61gu08hElC+O1nR6RoT92tqQGOI=", "comment"=>{"content"=>"ok"}, "commit"=>"Add comment", "action"=>"create", "controller"=>"comments", "post_id"=>"23"}
which clearly shows that it does in-fact get the post_id and that it is in this case the id of 23.
After countless hours I thought that I'd see if you guys have a solution.
My comments_controller.rb:
class CommentsController < ApplicationController
before_action :load_post
def create
#comment = #post.comments.build(params[:content])
#comment.user = current_user
if #comment.save
#comment.create_activity :create, owner: current_user
redirect_to root_url, notice: "Comment was created."
else
render :new
end
def load_post
#post = Post.find(params[:id])
end
end
My posts_controller.rb
def show
#post = Post.find(params[:id])
#comment = Comment.new
end
the partial for the forms comments/_form.rb
<%= form_for [#post, #comment] do |f| %>
<%= f.text_area :content %>
<%= f.submit "Add comment" %>
<% end %>
My routes.rb
resources :posts do
resources :comments
end
my posts/show.html.erb
<%= render #post %>
<h3>New comment</h3>
<%= render 'comments/form' %>
my posts/_post.html.erb
<h2><%= #post.title %></h2>
<p><%= #post.content %></p>
<em>written by <%= #post.user.fullname %></em>
You are receiving "post_id" not as "id"
You can make load_post action as private for security concerns
private
def load_post
#post = Post.find(params[:post_id])
end
Access the content like
def create
#comment = #post.comments.build(params[:comment][:content])
....
I am trying to write my delete method in my comment controller. My comment model has polymorphic associations with other models but in this case, we'll just focus on trips. In other words, #trip = #commentable.
The comment gets deleted just fine, but I keep getting the error ActionController::ActionControllerError in CommentsController#destroy: Cannot redirect to nil! when I redirect_to #commentable which would be the trip that the comment belonged to.
I also redirected to #commentable in my create action (comment controller) and that works just fine when the user creates a new comment.
Any tips?
view (trips/show.html.erb)
<% if !#commentable.comments.empty? %>
<% #commentable.comments.each do |comment| %>
<!-- Content -->
<%= link_to comment, :method => :delete do %> delete <% end %>
<% end %>
<% end %>
comment form that works for create action
<%= form_for [#commentable, Comment.new] do |f| %>
<%= f.text_area :content %>
<div id="comment_submit_button"><%= f.submit "Comment" %></div>
<% end %>
trips_controller.rb
def show
#trip = #commentable = Trip.find(params[:id])
#comments = Comment.all
end
comments_controller.rb
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
#comment.user_id = current_user.id
if #comment.save
redirect_to #commentable
end
end
def destroy
# #commentable = find_commentable this line was wrong
#comment = Comment.find(params[:id])
#commentable = #comment.commentable #this line fixed it
if #comment.destroy
redirect_to #commentable
end
end
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
Figured out the solution. Will post solution in code above.
def destroy
#comment = Comment.find(params[:id])
#commentable = #comment.commentable
if #comment.destroy
redirect_to #commentable
end
end
I have 2 tables: venues and reviews where 1 venue can have many reviews and a review belongs to a venue. I currently add the reviews to the venues from a link in the venue show page to the reviews new page:
venues/show.html.erb
<div class="button">
<%= link_to 'Add a review', new_venue_review_path(#venue) %>
</div>
reviews/new.html.erb
<% form_for [#venue, #review] do |f| %>
<p>title: <br>
<%= f.text_field :title %></p>
<%= submit_tag %>
<% end %>
reviews controller
def new
#review = Review.new
end
def create
#review = Review.new params[:review]
#review.venue = #venue
if #review.save
flash[:notice] = 'Review added'
redirect_to venue_path(#venue)
else
render :action => :new
end
end
venues controller
class VenuesController < ApplicationController
def index
if
#venues = Venue.with_type(params[:venuetypes]).with_area(params[:areas])
else
#venues = Venue.all
end
end
def new
#venue = Venue.new
end
def create
#venue = Venue.new params[:venue]
if #venue.save
flash[:notice] = 'Venue added'
redirect_to venues_path
else
render :action => :new
end
end
def edit
#venue = Venue.find(params[:id])
end
def update
#venue = Venue.find(params[:id])
#venue.attributes = params[:venue]
if #venue.save!
flash[:notice] = 'Venue updated successfully'
redirect_to venues_path(#venue)
end
end
def show
#venue = Venue.find(params[:id])
end
end
routes
resources :venues do
resources :reviews
end
end
How can I move the add new review form directly into the venues show page? Moving the code over gives a undefined method `model_name' for NilClass:Class error.
Thanks for any help!
Just add #review = Review.new to the show action on your venues controller. Then put the form right in your venue#show view file.
venues_controller.rb
def show
#venue = Venue.find(params[:id])
#review = Review.new
end