Rails: Redirecting to post after comment submission - ruby-on-rails

I have a form to submit comments on posts.
After submitting comments, the user should be redirected to the post.
I am getting the following error when I hit the "submit" button:
NameError in CommentsController#create undefined local variable or method `post' for CommentsController...
The error points to the following line in my comments controller:
redirect_to post_path(#post)
Here's my comments_controller.rb:
class CommentsController < ApplicationController
before_action :authenticate_user!
def create
#topic = Topic.find(params[:topic_id])
#post = #topic.posts.find(params[:post_id])
#comment = Comment.new(comment_params)
#comment.post = #post
redirect_to post_path(#post)
end
private
def comment_params
params.require(:comment).permit(:title, :body)
end
end
And here's my route file:
Rclone::Application.routes.draw do
get "comments/create"
devise_for :users
resources :users, only: [:update]
resources :topics do
resources :posts, except: [:index] do
resources :comments, only: [:create]
end
end
get '/posts/:id/comments', to: 'posts#show'
get 'about' => 'welcome#about'
root to: 'welcome#index'
end
What am I doing wrong on the routes file?

Comment.new will not presist or create the post. You need to do #comment.save. Also use pry and pry-nav gem to debug such errors. pry will halt the execution of you program where it finds binding.pry. From that point onwards you can execute your program line by line. Just insert binding.pry one line before where you want to halt execution.
example
def create
binding.pry
#topic = Topic.find(params[:topic_id])
Check you params hash and you will find your bug. My guess is you are going wrong with topic_id or post_id
Links:
http://pryrepl.org/
https://github.com/pry/pry

Related

rails - NoMethodError in PostsController#create undefined method `post_url'

I'm writing a simple website in which users (authenticated with Devise) can create posts. Upon creating a new post, I'm running into this error in which it won't redirect to the post. Here's my Posts controller:
class PostsController < ApplicationController
before_filter :authenticate_user!
def new
#post = current_user.posts.new
end
def create
#post = current_user.posts.new(post_params)
if #post.save
redirect_to #post
end
end
def show
#post = Post.find_by_id(params[:id])
end
private
def post_params
params.require(:post).permit(:title, :content)
end
end
Here's my routes.rb:
Rails.application.routes.draw do
devise_for :users
resources :users do
resources :posts
end
root 'posts#new'
end
Since the posts resource is nested within users I thought perhaps I should have this in my controller:
if #post.save
redirect_to current_user.#post
end
But that produces a SyntaxError in PostsController#create error.
Can anyone see the problem that's preventing the controller from redirecting to the post after it's created? Any help would be much appreciated.
Try this -
redirect_to [current_user,#post]
OR,
redirect_to user_post_path(current_user, #post)
hope it helps!
In your model, have you allowed for nested attributes? In the controller you want to use build instead of new.

Rails 4 Namespace

I am getting a routing error when I attempt to create a new db entry or update a current one.
ERROR: No route matches [POST] "/pubs"
Routes.rb:
resources :people, except: [:show] do
resources :pubs, except: [:create, :new, :edit, :destroy]
end
resources :articles
resources :pubs, except: [:create, :new, :edit, :destroy]
namespace :sekret do
resources :people do
resources :pubs
end
end
sekret/pubs_controller
class Sekret::PubsController < SekretController
def index
#pubs = Pub.all
end
def show
#pub = Pub.find(params[:id])
end
def new
#person = Person.find(params[:person_id])
#pub = #person.pubs.new
end
def create
#pub = Pub.new(pub_params)
if #pub.save
flash[:notice] = "Article created successfully!"
redirect_to sekret_person_pub_path(#pub)
else
render :new, status: :unprocessable_entity
end
end
def edit
#pub = Pub.find(params[:id])
end
def update
#pub = Pub.find(params[:id])
if #pub.update(pub_params)
redirect_to sekret_person_pub_path(#pub)
else
render :edit, status: :unprocessable_entity
end
end
def destroy
pub = Pub.find(params[:id])
pub.destroy
redirect_to sekret_people_path
end
private
def pub_params
params.require(:pub).permit(
:pubmed_id, :journal, :pages, :date, :type, :link, :authors,
:title, :notes, :auth_id, :person_id)
end
end
After going through all of this setup, when I allow the non-namespace pubs to resolve edit, update, etc, the update process goes through without a hitch. Once I limit these functions to within the password protected namespace I get the routing error. After parsing through the routes I can see that sekret_person_pub_path is listed there. I think I am missing something somewhere.
Rake Routes:
pubs#index
pub GET /pubs/:id(.:format) pubs#show
PATCH /pubs/:id(.:format) pubs#update
PUT /pubs/:id(.:format) pubs#update
sekret_person_pubs GET /sekret/people/:person_id/pubs(.:format) sekret/pubs#index
POST /sekret/people/:person_id/pubs(.:format) sekret/pubs#create
new_sekret_person_pub GET /sekret/people/:person_id/pubs/new(.:format) sekret/pubs#new
edit_sekret_person_pub GET /sekret/people/:person_id/pubs/:id/edit(.:format) sekret/pubs#edit
sekret_person_pub GET /sekret/people/:person_id/pubs/:id(.:format) sekret/pubs#show
PATCH /sekret/people/:person_id/pubs/:id(.:format) sekret/pubs#update
PUT /sekret/people/:person_id/pubs/:id(.:format) sekret/pubs#update
DELETE /sekret/people/:person_id/pubs/:id(.:format) sekret/pubs#destroy
sekret_people GET /sekret/people(.:format)
By using resources :pubs, except: [:create, :new, :edit, :destroy], you are preventing the route generation from providing POST /pubs.
The namespace and nested resources will generate a URL POST sekret/people/:person_id/pubs.
In your controller, you should create the Pub as an associated object.
def create
person = Person.find(params[:person_id])
#pub = person.pubs.new(pub_params)
if #pub.save
flash[:notice] = "Article created successfully!"
redirect_to sekret_person_pub_path(#pub)
else
render :new, status: :unprocessable_entity
end
end
If you want to restrict access the create method, you could use an authorization library such as Pundit in which case you would setup a policy to restrict who can do what.
https://github.com/elabs/pundit
You are missing out on the routes because rails form don't use the correct routes when namespacing so you'll have to specify them manually
<%= form for #pub, url: sekret_person_pubs_path do |f| %>
to let the form knows which route to post, if you do not specify the url, rails will use url: person_pubs_path behind the scenes
Edit: forgot to add _path

Controller method #show getting called

I have a link on my #index view:
<%= link_to 'Export Calendar (ICS)', { controller: :tickets, action: :ics_export, format: :ics }, class: "class-needed right" %>
routes.rb that pertains to this:
resources :tickets
get 'tickets/calendar' => 'tickets#ics_export'
post 'tickets' => 'tickets#index'
patch 'tickets/:id/close' => 'tickets#close', as: 'close_ticket'
post 'tickets/:id' => 'ticket_comments#create'
My TicketsController that pertains:
before_action :set_ticket, only: [:show, :edit, :destroy, :update, :close]
def show
#ticket_comment = TicketComment.new
end
def ics_export
tickets = Ticket.all
respond_to do |format|
format.html
format.ics do
cal = Icalendar::Calendar.new
tickets.each do |ticket|
event = Icalendar::Event.new
event.dtstart = ticket.start
event.description = ticket.summary
cal.add_event(event)
end
cal.publish
render :text => cal.to_ical
end
end
end
private
def set_ticket
#ticket = Ticket.find(params[:id])
end
And when I click the link, it takes me to /tickets/calendar.ics which is correct but I get the following error:
ActiveRecord::RecordNotFound in TicketsController#show
Couldn't find Ticket with 'id'=calendar
Extracted source (around line #83):
private
def set_ticket
#ticket = Ticket.find(params[:id])
end
The #ticket = Ticket.find(params[:id]) is highlighted. Which make sense that it is failing to call a ticket with an id of calendar.
Request has parameters:
{"id"=>"calendar",
"format"=>"ics"}
How do I fix this error? Why is it calling the show action?
There is a footnote in the canonical Rails Routing from the Outside In to the effect:
Rails routes are matched in the order they are specified, so if you have a resources :photos above a get 'photos/poll' the show action's route for the resources line will be matched before the get line. To fix this, move the get line above the resources line so that it is matched first.
As commented, the fix is to specify get 'tickets/calendar' => ... ahead of resources :tickets. If the order of routes is in question, you can run rake routes, which, to the best of my knowledge, should render your routes in the order they are checked.

Rails 4: One-to-one controller issue

I'm building an app which consists on sharing résumés. I am using Devise gem. Each user is able to create only one résumé. I made the models and and their relations. Resume belongs_to User and User has_one 'Resume'.
After making the views, I wanted to test my app but I got the error: undefined methodbuild' for nil:NilClass`
Here is my ResumeController and my routes.rb
class ResumeController < ApplicationController
before_action :find_resume, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:show]
def show
# #resume = Resume.find_by(params[:id])
end
def new
#resume = current_user.resume.build
end
def create
#resume = current_user.resume.build(resume_params)
if #resume.save
redirect_to #resume, notice: "resume was successfully created"
else
render 'new'
end
end
def edit
end
def update
if #resume.update(pin_params)
redirect_to #resume, notice: "resume was successfully updated"
else
render 'edit'
end
end
def destroy
#resume.destroy
redirect_to root_path
end
private
def resume_params
params.require(:resume).permit(:title, :description)
end
def find_resume
#resume = resume.find(params[:id])
end
end
Routes.rb
Rails.application.routes.draw do
devise_for :users
resources :resume, except: [:index]
get 'static_pages/index'
root to: "static_pages#index"
end
I just want the user to be able to create only one Resume and then he will be able to share it.
Update: After following messanjah's answer there was another error coming from the _form.html.erb: undefined method resumes_path' for #<#<Class:0x00...>. Here is the gist with forms and model: goo.gl/XvW2LH So you can see all the files closely.
Without more knowledge of where the error is happening, I can only suggest some areas that might be suspect.
To build a has_one relationship, you must use the build_*association* constructor.
def new
#resume = current_user.build_resume
end
def create
#resume = current_user.build_resume(resume_params)
end

rails Redirect to action incorrect URL

I have a scenario being:
resources :magazines do
resources :articles do
resources :comments
end
end
So as to avoid nesting more than 2 levels deep I have re-factored this to be:
resources :magazines do
resources :articles
end
resources :articles do
resources :comments
end
My article show action URL is:
/magazines/3/articles/11
In this view I have a form for creating a new comment.
When a comment is saved successfully the form redirects which all works well.
When the form submission is not successful I wish to redisplay the view with validations errors displayed. I understand the correct way to do this is to render the 'articles/show' view. This also works and the view is redisplayed with the validation errors shown.
The problem is when the save fails and articles/show is rendered the URL is no longer correct and is shown as:
/articles/11/comments
class ArticlesController < ApplicationController
def show
#article = Article.find(params[:id])
#comments = #article.comments.order(created_at: :asc).page(params[:page]).per_page(5)
#comment = Comment.new
end
end
class CommentsController < ApplicationController
def create
#article = Article.find(params[:id])
#comment = #article.comments.new(discussion_params)
#comment.user_id = current_user.id
if #comment.save
redirect_to #article
else
render 'articles/show'
end
end
private
def discussion_params
params.require(:comment).permit(:content)
end
end
I solved this by changing my routes back to the way it originally was and now the article show action includes the magazine in the url.
I understand this breaks the "no more than 2 levels deep" routing rule but it's the only way I can get it to work.

Resources