testing nested route in functional tests - ruby-on-rails

I have a nested route:
resources :stories do
resources :comments
end
this is my create method in controller:
def create
#story = Story.find(params[:story_id])
#comment = #story.comments.build(params[:comment])
#comments = #story.comments.all
respond_to do |format|
if #comment.save
format.html { redirect_to #story, notice: t('controllers.comments.create.flash.success') }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render template: "stories/show" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
And here is it's test:
setup do
#comment = comments(:one)
#story = stories(:one)
end
....
test "should create comment" do
assert_difference('Comment.count') do
post :create, :story_id => #story.id, comment: { content: #comment.content, name: #comment.name, email: #comment.email }
end
assert_redirected_to #story_path
end
that ends up with this error:
1) Failure:
test_should_create_comment(CommentsControllerTest) [/home/arach/workspace/Web/ruby/nerdnews/test/functional/comments_controller_test.rb:25]:
Expected response to be a redirect to <http://test.host/stories/980190962/comments> but was a redirect to <http://test.host/stories/980190962>
I don't know why the test expect to redirect to stories/:id/comments. I tried other things like story_comment_path but it didn't help either. story_path without # also ends up with another error:
ActionController::RoutingError: No route matches {:action=>"show", :controller=>"stories"}
same error happens for story_path, :story_id => #story.id. Any idea why this happens?

I think it should be story_path(#story.id). See here.

Related

Bad Redirect On Create Method - Rails 4

I am trying to change the redirect when I create a listing, but I keep getting a No route matches {:action=>"manage_photos", :controller=>"listings"} missing required keys: [:id]. What am I missing? My route is nested and there is a manage_photos method in my controller. Not sure where to go from here.
routes.rb
resources :listings do
member do
get 'like'
get 'unlike'
get 'duplicate'
get 'gallery'
delete 'gallery' => 'listings#clear_gallery'
get 'manage_photos'
get 'craigslist'
get "add_to_collection"
get 'request_photos'
get 'rsvp'
end
end
rake routes:
manage_photos_listing GET /listings/:id/manage_photos(.:format) listings#manage_photos
listings_controller:
create method:
def create
#listing = Listing.new(listing_params)
respond_to do |format|
if #listing.save
format.html { redirect_to manage_photos_listing_path, notice: 'Listing was successfully created.' }
format.json { render json: #listing, status: :created, location: #listing }
else
format.html { render action: "new", notice: "Correct the mistakes below to create the new listing" }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
manage_photos method:
def manage_photos
#listing = Listing.find(params[:id])
end
error:
Since it is a nested resource you have to add the id of the parent element. Try:
manage_photo_listing(#listing)
so it can actually use the id of #listing and build the route

Create and Update Redirect with Nested Resources Rails 4

to avoid deep nesting routes I have done the following:
routes.rb
resources :clients, controller: 'clients' do
resources :sites, controller: 'clients/sites', except: [:index]
end
resources :sites, controller: 'clients/sites', except: [:index] do
resources :site_contacts, controller: 'sites/site_contacts', except: [:index]
end
My problem right now is after I Create a new Site Contact I Get an error that states
undefined method `site_contact_url' for #<Sites::SiteContactsController:0x007f9dcb980100>
Did you mean? site_contact_params
my associations are all set up and correct but I am not sure how to handle the re-directs in the site contact create and update methods (below)
site_contacts_controller.rb
def create
#site = Site.friendly.find(params[:site_id])
#site_contact = SiteContact.new(site_contact_params)
#site_contact.site = #site
respond_to do |format|
if #site_contact.save
format.html { redirect_to #site_contact, notice: 'Site contact was successfully created.' }
format.json { render :show, status: :created, location: #site_contact }
else
format.html { render :new }
format.json { render json: #site_contact.errors, status: :unprocessable_entity }
end
end
end
def update
#site = Site.friendly.find(params[:site_id])
respond_to do |format|
if #site.update(site_contact_params)
format.html { redirect_to #site_contact, notice: 'Site contact was successfully updated.' }
format.json { render :show, status: :ok, location: #site_contact }
else
format.html { render :edit }
format.json { render json: #site_contact.errors, status: :unprocessable_entity }
end
end
end
I originally changed #site_contact to #site in both create and update methods and it was throwing the error, I changed them back to original for now as it clearly wasn't working.
Im lost here and am having a hell of a time trying to find a solution. Any help would be greatly appreciated!
Thanks in advance, please let me know if you require any further details.
EDIT #1: Adds rake routes output for sites
site_site_contacts POST /sites/:site_id/site_contacts(.:format) sites/site_contacts#create
new_site_site_contact GET /sites/:site_id/site_contacts/new(.:format) sites/site_contacts#new
edit_site_site_contact GET /sites/:site_id/site_contacts/:id/edit(.:format) sites/site_contacts#edit
site_site_contact GET /sites/:site_id/site_contacts/:id(.:format) sites/site_contacts#show
PATCH /sites/:site_id/site_contacts/:id(.:format) sites/site_contacts#update
PUT /sites/:site_id/site_contacts/:id(.:format) sites/site_contacts#update
DELETE /sites/:site_id/site_contacts/:id(.:format) sites/site_contacts#destroy
Here are the client/sites rake routes output
client_sites POST /clients/:client_id/sites(.:format) clients/sites#create
new_client_site GET /clients/:client_id/sites/new(.:format) clients/sites#new
edit_client_site GET /clients/:client_id/sites/:id/edit(.:format) clients/sites#edit
client_site GET /clients/:client_id/sites/:id(.:format) clients/sites#show
PATCH /clients/:client_id/sites/:id(.:format) clients/sites#update
PUT /clients/:client_id/sites/:id(.:format) clients/sites#update
DELETE /clients/:client_id/sites/:id(.:format) clients/sites#destroy
So I do see an issue here in the outputs, it should be redirecting to client/:client_id/sites/:site_id/site_contacts/:id as there is no sites controller, or no sites/show it is nested to clients.
EDIT #2 New ERROR
No route matches {:action=>"show", :controller=>"sites/site_contacts", :site_id=>#<SiteContact id: 3, site_id: 1, name: "Shawn Wilson", tel_number: "403-615-5915", tel_ext: "", email: "swilson#taurenltd.com", contact_type: "Management", after_hours: true, notes: "Primary", created_at: "2016-09-23 06:47:42", updated_at: "2016-09-23 06:47:42", slug: "shawn-wilson-b7a18908-34ae-4385-bcf7-17c97547dabb">} missing required keys: [:id]

Nested Routes - Broken Form, NoMethodError - undefined method

To learn Rails, I'm working on a simple calendar app. To get started, I created two scaffolds and the proper associations/routes:
calendars
content_items
app/models/calendar.rb
class Calendar < ActiveRecord::Base
has_many :content_items
end
app/models/content_item.rb
class ContentItem < ActiveRecord::Base
belongs_to :calendar
end
routes.rb
resources :calendars do
resources :content_items
end
controllers/content_items_controller.rb
def create
#content_item = ContentItem.new(content_item_params)
#calendar = Calendar.find(params[:calendar_id] )
respond_to do |format|
if #content_item.save
format.html { redirect_to calendar_content_item_path(#calendar,#content_item), notice: 'Content item was successfully created.' }
format.json { render :show, status: :created, location: #content_item }
else
format.html { render :new }
format.json { render json: #content_item.errors, status: :unprocessable_entity }
end
end
end
When I created the nested routes, I began to run into errors when trying to create new content_items. Whenever I submit the form, I get this error:
NoMethodError in ContentItems#create
undefined method `content_items_path'
The error is coming from:
views/content_items/index.html.erb
<%= form_for [#calendar, #content_item] do |f| %>
UPDATE
Using the code posted below by #Gaurav GuptA fixed the form issue, but led to a new errror. Whenever I visit /calendars/1/content_items, I recieve an error - but only after creating an entry. With an empty database, it works fine.
ActionController::UrlGenerationError
No route matches {:action=>"show", :calendar_id=>#, :controller=>"content_items", :format=>nil, :id=>nil} missing required keys: [:id]
I believe this is because the content_item is being saved without a calendar_id. How do I set the content_item to save with the calendar_id it belongs to?
UPDATE 2
It now saves with a calendar_id, but when an item is saved, the links for edit/shpw/destroy throw errors.
No route matches {:action=>"show", :calendar_id=>#<ContentItem id: 1, , content_type: "Test", content_text: "Tetst\r\n", calendar_id: 1, created_at: "2015-05-26 07:06:42", updated_at: "2015-05-26 07:06:42", content_image_file_name: nil, content_image_content_type: nil, content_image_file_size: nil, content_image_updated_at: nil>, :controller=>"content_items", :format=>nil, :id=>nil} missing required keys: [:id]
It highlights this part of the file:
<td><%= link_to 'Show', calendar_content_item_path(content_item) %></td>
GitHub link: https://github.com/JeremyEnglert/baked
Try to change your create action of content_items_controller as:
def create
#calendar = Calendar.find(params[:calendar_id] )
#content_item = #calendar.content_items.new(content_item_params) #Edit
respond_to do |format|
if #content_item.save
format.html { redirect_to calendar_content_item_path(#calendar,#content_item), notice: 'Content item was successfully created.' }
format.json { render :show, status: :created, location: #content_item }
else
format.html { render :new }
format.json { render json: #content_item.errors, status: :unprocessable_entity }
end
end
end
Hope this will work for you.
Ok so with the routes you have:
resources :calendars do
resources :content_items
end
You get a path like this for example:
/calendars/50
/calendars/50/content_items/77
Which are then routed to:
app/controllers/calendars_controller.rb
app/controllers/content_items_controller.rb
Your error comes from your create action in your ContentItemsController. The params you are posting to the action include your calendar id "calendar_id"=>"1"
but nothing is there to receive it.
You need to get the instance of Calendar associated with the item you are creating.
#calendar = Calendar.find(params[:calendar_id] )
Then after you save #content_item pass to the calendar_content_item_path (as indicated in your routes) both objects:
format.html { redirect_to calendar_content_item_path(#calendar,#content_item), notice: 'Content item was successfully created.' }
In your create method in the ContentItemsController should look like this:
def create
#calendar = Calendar.find(params[:calendar_id] )
#content_item = #calendar.content_items.build(params[:content])
respond_to do |format|
if #content_item.save
format.html { redirect_to calendar_content_item_path(#calendar,#content_item), notice: 'Content item was successfully created.' }
format.json { render :show, status: :created, location: #content_item }
else
format.html { render :new }
format.json { render json: #content_item.errors, status: :unprocessable_entity }
end
end
end
I have also noticed that you are passing the calendar id to your strong params. That would through an error since the calendar's id is not assigned by the user.
You can read more on Strong Parameters.

Functional Testing Rails, No route matches error

I am trying to fix the following rails functional test:
test "should create broadcast" do
login_as(:one_details)
assert_difference('Broadcast.count') do
post :create, feeds: [:twitter, {alumni_email: 'test#email.com'}], broadcast: {id: 2, content: #broadcast.content, user: #user_details.user_id}
end
assert_redirected_to "#{broadcast_path}?page=1"
end
Here is the error:
1) Error:
BroadcastsControllerTest#test_should_create_broadcast:
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"broadcasts"} missing required keys: [:id]
test/controllers/broadcasts_controller_test.rb:35:in `block in <class:BroadcastsControllerTest>'
I have this in the routes file:
resources :broadcasts, except: [:edit, :update]
In the broadcasts_controller the show method looks like this:
def show
if is_admin?
respond_to do |format|
format.js { render partial: 'show_local',
locals: {broadcast: #broadcast, current_page: #current_page},
layout: false }
format.html # show.html.erb
format.json # show.json.builder
end
else
indicate_illegal_request I18n.t('not allowed to view this')
end
end
The broadcast controller create method:
def create
#broadcast = Broadcast.new(broadcast_params)
# Wire up broadcast with the current user (an administrator)
# Will be an admin user (see before_filter)
# Note the current_user is a user_detail object so we need
# to navigate to its user object
#broadcast.user = current_user.user
# Doing the next line forces a save automatically. I want to defer this
# until the "if" statement
#current_user.user.broadcasts << #broadcast
no_errors = false
respond_to do |format|
if #broadcast.save
# Only after saving do we try and do the real broadcast. Could have been
# done using an observer, but I wanted this to be more explicit
results = BroadcastService.broadcast(#broadcast, params[:feeds])
if results.length > 0
# Something went wrong when trying to broadcast to one or more of the
# feeds.
#broadcast.errors[:base] << ("#{I18n.t('broadcasts.unable-message')}: #{results.inspect}")
flash[:error] = I18n.t('broadcasts.saved-but-message')
else
flash[:notice] = I18n.t('broadcasts.saved-message')
no_errors = true
end
if no_errors
format.html { redirect_to(broadcasts_url(page: #current_page)) }
format.json { render json: #broadcast, status: :created, location: #broadcast }
else
format.html { render :new }
format.xml {
# Either say it partly worked but send back the errors or else send
# back complete failure indicator (couldn't even save)
if results
render json: #broadcast.errors, status: :created, location: #broadcast
else
render json: #broadcast.errors, status: :unprocessable_entity
end
}
end
end
end
end
Change
assert_redirected_to "#{broadcast_path}?page=1"
to
 assert_redirected_to "#{broadcasts_path}?page=1"
also change
post :create, feeds: [:twitter, {alumni_email: 'test#email.com'}], broadcast: {id: 2, content: #broadcast.content, user: #user_details.user_id}
to
post :create, feeds: [:twitter, {alumni_email: 'test#email.com'}], broadcast_params: {id: 2, content: #broadcast.content, user: #user_details.user_id}
you are not passing an id in the redirect check so you either make it broadcasts_path

No route matches {:action=>"show", :controller=>"controller_name"}

I'm always getting this error and I don't understand where I am wrong. I think I have everything I need action in controller, resources in route file and view for controller action. I put the route current_events/new in the browser when I get this error. I also try with just resources :current_events
output of rake routes:
current_events GET /current_events(.:format) current_events#index
new_current_event GET /current_events/new(.:format) current_events#new
current_event GET /current_events/:id(.:format) current_events#show
config/routes.rb:
appname::Application.routes.draw do
devise_for :users, controllers: { omniauth_callbacks: "omniauth_callbacks"}
resources :current_events, only: [:show, :new, :index]
end
CurrentEventsController:
class CurrentEventsController < ApplicationController
def index
#current_event = CurrentEvent.all
respond_to do |format|
format.html
format.json { render json: #current_event }
end
end
def create
#current_event = CurrentEvent.new(params[:current_event])
respond_to do |format|
if #current_event.save
format.html { redirect_to #current_event, notice: 'current event was created.' }
format.json { render json: #current_event, status: :created, location: #current_event }
else
format.html { render action: "new" }
format.json {render json: #current_event.errors, status: :unprocessable_entity}
end
end
end
def new
#current_event = CurrentEvent.new
respond_to do |format|
format.html
format.json { render json: #current_event }
end
end
def edit
#current_event = CurrentEvent.find(params[:id])
end
def destroy
#current_event = CurrentEvent.find(params[:id])
#current_event.destroy
respond_to do |format|
format.html { redirect_to current_event_url}
format.json { head :no_content }
end
end
def show
#current_event = CurrentEvent.find(params[:id])
respond_to do |format|
format.html
format.json{ render json: #current_event}
end
end
end
I forgot to say, I am trying to go to new page so in browser I say current_events/new
It will still throw an error if there's a link that doesn't work on the page.
In your view, the link should look something like this:
<%= link_to "name of current event", current_event_path(#current_event) %>
update
based on your rake routes
current_event GET /current_events/:id(.:format) #note ":id"
when you're trying to see a specific current event, you need to pass it an :id which makes sense - if you're trying to call a specific person you need to use their telephone number. so your code should look like this:
<%= link_to 'Back', current_event_path(#event) %>
But keep in the mind that #event won't work unless you define it correctly in the controller action for this view.

Resources