ActiveRecord::RecordNotFound in Api::V1::PostsController#show - ruby-on-rails

I am trying to follow Rails Todo API Part 1 from egghead.io https://egghead.io/lessons/angularjs-rails-todo-api-part-1
I am trying to access localhost:3000/api/v1/posts and the page should show the json response of:
[]
but instead I get the error:
ActiveRecord::RecordNotFound in Api::V1::PostsController#show
Couldn't find Post without an ID
def show
respond_with(Post.find(params[:id])) <----- error is here
end
I also tried adding a record which should return the json response of that record but I get the same error. What am I doing wrong?
I have completed the controller and routes as follows:
app/controllers/api/v1/posts_controller.rb
module Api
module V1
class PostsController < ApplicationController
skip_before_filter :verify_authenticity_token
respond_to :json
def index
respond_with(Post.all.order("id DESC"))
end
def show
respond_with(Post.find(params[:id]))
end
def create
#post = Post.new(post_params)
if #post.save
respond_to do |format|
format.json {render :json => #post}
end
end
end
def update
#post = Post.find(params[:id])
if #post.update(post_params)
respond_to do |format|
format.json {render :json => #post}
end
end
end
def destroy
respond_with Post.destroy(params[:id])
end
private
def post_params
params.require(:post).permit(:content)
end
end
end
end
config/routes.rb
WhatRattlesMyCage::Application.routes.draw do
namespace :api, defaults: {format: :json} do
namespace :v1 do
resource :posts
end
end
end
rake routes:
Prefix Verb URI Pattern Controller#Action
api_v1_posts POST /api/v1/posts(.:format) api/v1/posts#create {:format=>:json}
new_api_v1_posts GET /api/v1/posts/new(.:format) api/v1/posts#new {:format=>:json}
edit_api_v1_posts GET /api/v1/posts/edit(.:format) api/v1/posts#edit {:format=>:json}
GET /api/v1/posts(.:format) api/v1/posts#show {:format=>:json}
PATCH /api/v1/posts(.:format) api/v1/posts#update {:format=>:json}
PUT /api/v1/posts(.:format) api/v1/posts#update {:format=>:json}
DELETE /api/v1/posts(.:format) api/v1/posts#destroy {:format=>:json}

Make it resources :posts in your routes.rb
As it is you have malformed routes and the show method is being called instead of the index method

Related

Rails routing not providing the index and using it as the show for nested resources

I had this tutorial working for a different exercise, but now I'm putting the actual work into practice and can't figure out what I'm now doing wrong.
https://www.digitalocean.com/community/tutorials/how-to-create-nested-resources-for-a-ruby-on-rails-application
Here's my Product Categories model
class ProductCategory < ApplicationRecord
has_many :products
end
my Product model:
class Product < ApplicationRecord
belongs_to :product_category
end
My routes.rb:
Rails.application.routes.draw do
root 'product_categories#index'
resources :product_categories do
resource :products
end
end
The actual routes output for rails routes:
% rails routes
Prefix Verb URI Pattern Controller#Action
root GET / product_categories#index
new_product_category_products GET /product_categories/:product_category_id/products/new(.:format) products#new
edit_product_category_products GET /product_categories/:product_category_id/products/edit(.:format) products#edit
product_category_products GET /product_categories/:product_category_id/products(.:format) products#show
PATCH /product_categories/:product_category_id/products(.:format) products#update
PUT /product_categories/:product_category_id/products(.:format) products#update
DELETE /product_categories/:product_category_id/products(.:format) products#destroy
POST /product_categories/:product_category_id/products(.:format) products#create
product_categories GET /product_categories(.:format) product_categories#index
POST /product_categories(.:format) product_categories#create
new_product_category GET /product_categories/new(.:format) product_categories#new
edit_product_category GET /product_categories/:id/edit(.:format) product_categories#edit
product_category GET /product_categories/:id(.:format) product_categories#show
PATCH /product_categories/:id(.:format) product_categories#update
PUT /product_categories/:id(.:format) product_categories#update
DELETE /product_categories/:id(.:format) product_categories#destroy
rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create
rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create
rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create
rails_mandrill_inbound_health_check GET /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#health_check
rails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create
rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create
rails_conductor_inbound_emails GET /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#index
POST /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#create
new_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/new(.:format) rails/conductor/action_mailbox/inbound_emails#new
edit_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id/edit(.:format) rails/conductor/action_mailbox/inbound_emails#edit
rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#show
PATCH /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update
PUT /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update
DELETE /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#destroy
new_rails_conductor_inbound_email_source GET /rails/conductor/action_mailbox/inbound_emails/sources/new(.:format) rails/conductor/action_mailbox/inbound_emails/sources#new
rails_conductor_inbound_email_sources POST /rails/conductor/action_mailbox/inbound_emails/sources(.:format) rails/conductor/action_mailbox/inbound_emails/sources#create
rails_conductor_inbound_email_reroute POST /rails/conductor/action_mailbox/:inbound_email_id/reroute(.:format) rails/conductor/action_mailbox/reroutes#create
rails_service_blob GET /rails/active_storage/blobs/redirect/:signed_id/*filename(.:format) active_storage/blobs/redirect#show
rails_service_blob_proxy GET /rails/active_storage/blobs/proxy/:signed_id/*filename(.:format) active_storage/blobs/proxy#show
GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs/redirect#show
rails_blob_representation GET /rails/active_storage/representations/redirect/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations/redirect#show
rails_blob_representation_proxy GET /rails/active_storage/representations/proxy/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations/proxy#show
GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations/redirect#show
rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
The ProductCategoriesController:
class ProductCategoriesController < ApplicationController
before_action :set_product_category, except: [:index, :new, :create]
def index
#categories = ProductCategory.all
end
def show
end
def new
#category = ProductCategory.new
end
def create
#category = ProductCategory.new(category_params)
respond_to do |format|
if #category.save
format.html { redirect_to root_path }
else
format.html { render :edit, status: :unprocessable_entity }
end
end
end
private
def set_product_category
#product_category = ProductCategory.find(params[:id])
#name = #product_category.name
end
def category_params
params.require(:product_category).permit(:name)
end
end
and finally, the ProductsController:
class ProductsController < ApplicationController
before_action :get_product_category
before_action :set_product, except: [:index, :new, :create]
def index
#products = #product_category.products
end
def show
end
def new
#product = #product_category.products.build
end
def edit
end
def create
#product = #product_category.products.build(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to product_category_products_path(#product_category), notice: "Product was successfully created." }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: "Product was successfully updated." }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: "Product was successfully destroyed." }
format.json { head :no_content }
end
end
private
def get_product_category
#product_category = ProductCategory.find(params[:product_category_id])
end
def set_product
#product = #product_category.products.find(params[:id])
end
def product_params
params.require(:product).permit(:name, :description, :product_type)
end
end
So when you create a new product, it should redirect to the product's show page, but instead I get the error it and find Product without an ID. I do see in the routes that while a show is being generated, an index route is not.
Any help would be appreciated. Thanks.
You have a typo in your routes file:
resource :products
should be
resources :products
(Note the missing 's'.) Once you correct this, you should see that the correct routes are generated by Rails and things work more as you expect.

How to define routes that include a dynamic organization name in Rails

I'm building a Rails 5.2 SaaS application that allows users to belong to many "organizations". Users will only see content for their currently active organization.
I started down the path of using subdomains, but after a little more research have decided to avoid them for now.
My new approach (to make it explicit to the user what organization they are using, support sharing links, browser history etc..) is to embed the organization name in the path. For example:
https://app.example.com/foo/posts # Posts for org "foo"
https://app.example.com/foo/posts/7 # Post for org "foo"
https://app.example.com/bar/posts # Posts for org "bar"
https://app.example.com/settings # General account settings
https://app.example.com/signin # Sign in
My problem is how to do this with Rails routes? I've tried to use a dynamic scope:
scope ':org' do
resources :posts
end
Results in errors like:
No route matches {:action=>"show", :controller=>"posts", :org=>#<Organization id: 1, name: "My Organization", ...}, missing required keys: [:id]
For the code:
# layouts/application.html.erb
<%= link_to post, post, class: 'dropdown-item' %>
Any suggestions on how to configure routes to support this use case?
Use the resources macro:
Rails.application.routes.draw do
resources :posts, except: [:new, :create]
resources :organizations, path: '/', only: [] do
resources :posts, module: :organizations, only: [:new, :index, :create]
end
end
$ rails routes:
Prefix Verb URI Pattern Controller#Action
posts GET /posts(.:format) posts#index
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
organization_posts GET /:organization_id/posts(.:format) organizations/posts#index
POST /:organization_id/posts(.:format) organizations/posts#create
new_organization_post GET /:organization_id/posts/new(.:format) organizations/posts#new
By using the module: option you can setup a separate controller for the nested context:
# app/controllers/organizations/posts_controller.rb
class Organizations::PostsController < ApplicationController
before_action :set_organization!
# Index for posts belonging to a specific organization
# GET /:organization_id/posts
def index
#posts = #organization.posts
end
# GET /:organization_id/posts/new
def new
#post = #organization.posts.new
end
# POST /:organization_id/posts
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post, notice: 'Post was successfully created.'
else
render :new
end
end
private
def set_organization!
#organization = Organization.includes(:posts)
.find_by!(name: params[:organization_id])
end
def post_params
params.require(:post).permit(:title)
end
end
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# Index for posts belonging to all organizations
# GET /posts
def index
#posts = Post.all
end
# GET /posts/1
def show
end
# GET /posts/1/edit
def edit
end
# PATCH/PUT /posts/1
def update
if #post.update(post_params)
redirect_to #post, notice: 'Post was successfully updated.'
else
render :edit
end
end
# DELETE /posts/1
def destroy
#post.destroy
redirect_to posts_url, notice: 'Post was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def post_params
params.require(:post).permit(:title)
end
end
However you should be beware when creating routes that start with a dynamic segment - routes have priority in the order that they are defined and a route that starts with a dynamic segment will be "greedy" and swallow other routes if they are not defined first.

I am getting a No route matches error while trying to reroute to a new page?

I am new to ruby on rails , I was making a basic app that lets you display posts, after which we can access a new page where a user can enter new posts.
But the problem now is , upon clicking the submit button I get this error
No route matches {:action=>"show", :controller=>"posts"} missing required keys: [:id]
This is the content inside my post controller
class PostsController < ApplicationController
def index
#posts = Post.all
end
def show
#post = Post.find(params[:id])
end
def new
#post =Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to post_path,:notice=>"success"
else
render "new"
end
end
def edit
end
def update
end
def destroy
end
private
def post_params
params.require(:post).permit(:Title, :Content)
end
end
after this i tried to reload to check if there was an update at all , but all i got was empty entries
rake route command displays
nevin#NevinSunny:~/Workspace/Rails/Test1/blog$ rake routes
Prefix Verb URI Pattern Controller#Action
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
Change your create action:
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post, :notice => "success"
else
render "new"
end
end
Edit:
In response to your comment:
def create
#post = Post.new(post_params)
if #post.save
redirect_to posts_path, :notice=>"success"
else
render "new"
end
end
This is simple, When you say:
redirect_to post_path
you need to pass ID, as the error indicates:
redirect_to post_path(#post)
alternatively follow convention:
redirect_to #post

Pretty urls in rails

Im trying to make it work. THis is my rake routes right now:
groups GET /groups(.:format) groups#index
POST /groups(.:format) groups#create
new_group GET /groups/new(.:format) groups#new
edit_group GET /groups/:id/edit(.:format) groups#edit
group GET /groups/:id(.:format) groups#show
PATCH /groups/:id(.:format) groups#update
PUT /groups/:id(.:format) groups#update
DELETE /groups/:id(.:format) groups#destroy
what i want to do is remove "groups" from the link and add slug instead of id.
This is my controller right now:
class GroupsController < ApplicationController
before_action :find_group, only: [:show]
after_action :assign_slug, only: [:create, :update]
def index
#groups = Group.all
end
def show
end
def new
#group = Group.new
end
def create
#group = Group.new(group_params)
if #group.save
flash.notice = "Group has been successfully created!"
redirect_to #group
binding.pry
else
flash.alert = "oops!"
redirect_to action: :new
end
end
private
def group_params
params.require(:group).permit(:title, :description, :country, :city, :category_id)
end
def find_group
#group = Group.find_by_slug(params[:slug])
end
def assign_slug
#group.update(slug: #group.title.parameterize)
end
end
How do i make it work? Thanks.:)
If this is what you want:
routes.rb
get ':slug', to: 'pages#show', as: :groups_show
put ':slug', to: 'pages#update', as: :groups_update
delete ':slug', to: 'pages#destroy', as: :groups_delete
This way the slug will be catched as param and sended to the controller.

Ruby On Rails: ActionController::RoutingError No route matches, action show

I am using this example for uploading files in Ruby on Rails.
I have some problems with routing:
Error:
ActionController::RoutingError (No route matches {:action=>"show", :controller=>"cars", :locale=>#<Car id: 19, car_name: "bwl",, created_at: "2013-01-27 19:12:13", updated_at: "2013-01-27 19:12:13">}):
app/models/arraydb.rb:46:in `to_jq_car'
I have found out that the problem is in the to_jq_car function and in the line:
"delete_url" => car_path(self)
But I have no idea how to correct it.
routes.rb:
resources :cars
match '/show', :to =>'car#index'
root :to => 'cars#index'
cars_controllers.rb
class CarsController < ApplicationController
def index
#cars = Car.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #cars.map{|car| car.to_jq_car } }
end
end
def show
#car = Car.find(params[:id])
respond_to do |format|
format.html
format.json { render json: #car }
end
end
end
and in car.rb I have the following function:
def to_jq_car
{
"name" => (read_attribute(:arraydb_name)).split(".").first,
"url" => car.url(:original),
"delete_url" => car_path(self),
"delete_type" => "DELETE",
}
end
rake routes:
cars GET (/:locale)/cars(.:format) cars#index {:locale=>/en|de|es|ru|zh_cn|ar/}
POST (/:locale)/cars(.:format) cars#create {:locale=>/en|de|es|ru|zh_cn|ar/}
new_car GET (/:locale)/cars/new(.:format) cars#new {:locale=>/en|de|es|ru|zh_cn|ar/}
edit_car GET (/:locale)/cars/:id/edit(.:format) cars#edit {:locale=>/en|de|es|ru|zh_cn|ar/}
car GET (/:locale)/cars/:id(.:format) cars#show {:locale=>/en|de|es|ru|zh_cn|ar/}
PUT (/:locale)/cars/:id(.:format) cars#update {:locale=>/en|de|es|ru|zh_cn|ar/}
DELETE (/:locale)/cars/:id(.:format) cars#destroy {:locale=>/en|de|es|ru|zh_cn|ar/}
show (/:locale)/show(.:format) car#index {:locale=>/en|de|es|ru|zh_cn|ar/}
root /(:locale)(.:format) cars#index {:locale=>/en|de|es|ru|zh_cn|ar/}
Thanks in advance
error causes by :locale param
you have in routes
cars#index {:locale=>/en|de|es|ru|zh_cn|ar/}
so :locale value must be one of this in list en|de|es|ru|zh_cn|ar
and you need to find where you pass this param to controller and correct it
you can use (or maybe you already use) in ApplicationController
def default_url_options
{:locale => I18n.locale}
end

Resources