Rails: NoMethodError Undefined method - ruby-on-rails

I'm trying to build a basic Rails/React app which takes in a series of user inputs, then displays them on the screen within a letter template (think MadLibs.) I've followed several React tutorials and I have a decent amount of experience with Rails but I've gotten amazingly hung up with an API I've created. For context I'm using this tutorial here as a guide, but am building my own app.
This is my routes file:
Rails.application.routes.draw do
root to: 'site#index'
namespace :api do
namespace :v1 do
resources :letters, only: [:index, :create]
end
end
end
This is my base_controller.rb file:
class Api::V1::BaseController < ApplicationController
respond_to :json
end
and this is my letters_controller.rb file:
class Api::V1::LettersController < Api::V1::BaseController
def index
respond_with Letter.all
end
def create
respond_with :api, :v1, Letter.create(letter_params)
end
private
def letter_params
params.require(:letter).permit(:id, :param_one, :param_two)
end
end
The controller files are both stored in controllers/api/v1 and this is reflected in my routes file. I'm able to use the index method no problem and get all Letter objects to display. I'm able to use the create method somewhat, in that a new Letter is created and saved to the database (sqlite btw.) Problem comes with the response, as in there isn't one. Instead of a response coming back to my AJAX call I'm getting the following:
NoMethodError (undefined method `api_v1_letter_url' for #<Api::V1::LettersController:0x007f3085f1d300>):
app/controllers/api/v1/letters_controller.rb:7:in `create'
I have no earthy idea why this isn't working. From everything that I've read feeding the respond_with call the parameters I have should cause the returned url to work and come back with a response. Instead I get this strange 500.
I've never had so much trouble with a program that it's given me a migraine before. If anyone can help it will be greatly appreciated.

If you run rake routes, you will see that there is no declaration for api_v1_letter_url.
This is because you do not declare a show method on routes.rb (you explicitly only use index and create). If you want the call in your controller to work as-is, you need a show method:
Rails.application.routes.draw do
root to: 'site#index'
namespace :api do
namespace :v1 do
resources :letters, only: [:index, :create, :show]
end
end
end
Now, run rake routes, you'll see it's there.
To implement show in your controller:
def show
respond_with Letter.find(params[:id])
end

Related

New action not being reached in my Ruby app

I'm just learning Ruby on Rails and building a fairly simple app that stores info to a rake generated db. I'm trying to add a new action to the controller but I can't trigger it. There's a before_action getting triggered which shouldn't be.
class GamesController < ApplicationController
before_action :set_entry, only: %i[ show edit update destroy ]
before_action :authenticate_user!
def index
end
def analyse
#The function here doesnt matter, its not reaching it because its hitting the set_entry instead
puts 'howdy'
end
private
def set_entry
#entry = Entry.find(params[:id])
end
end
The error I'm hitting is Couldn't find Game with 'id'=analyse", highlighting the set_entry action, which to my understanding should only be running with the show, edit, update, and destroy actions (which are also in the full controller and running fine). There are other actions in the controller (such as create and new) which don't seem to trigger that set_entry and are running just fine as expected. For example, linking to the new path takes me to /entry/new, while linking to an edit path takes me to /entry/:id/edit, which is all fine. But it keeps linking my new analyse action trying for entry/:id/analyse when I want it to go to entry/analyse.
My button to trigger it is simply:
<%= link_to "Analyse", analyse_path %>
Which is in a navbar in my application.html.erb
And here's my routes.rb:
Rails.application.routes.draw do
resources :entry
devise_for :users
resources :users
root to: "entry#index"
get 'entry/index'
get 'entry/analyse', as: 'analyse'
end
The path /entry/analyse is matched two routes:
entry#show action in resources :entry
entry#analyse action in get 'entry/analyse', as: 'analyse'
Because the route matching is interpreted through config/routes.rb in order, and resources :entry is the first route the path is matched. At the result, entry#show action will handle the requests from /entry/analyse.
The solution is simple, just switch the order of resources :entry and get 'entry/analyse', as: 'analyse' in config/routes.rb. For example:
Rails.application.routes.draw do
get 'entry/analyse', as: 'analyse' # <- to here
resources :entry
devise_for :users
resources :users
root to: "entry#index"
get 'entry/index'
# from here ...
end
Move all of your resources to the end of your route configuration. I am not sure why its getting tripped up but it seems something within your routes is matching analyse to your entry resource and routes within rails are matched in order. All custom routes really should come first to prevent something like a generic route catching your expected action.
Best practices also state your root to: should be at the top of the configuration since it is your most popular route generally in an application.

Rails 5 API mode: can't reach show action for a nested resource

I'm using rails 5.2.1 in API mode with 2.5.3.
I have the following routes.rb file..
Rails.application.routes.draw do
namespace :api do
resource :groups, only: [:show]
end
end
.. and the following app/controllers/api/groups_controller.rb file
class Api::GroupsController < ApplicationController
def show
binding.pry
end
end
The following request http://localhost:3000/api/groups arrives in the controller's action properly, triggering the binding.pry.
The issue is that the following request http://localhost:3000/api/groups/1 thraws a Routing error:
No route matches [GET] "/api/groups/1"
Why is that happening ?
Since you want to pass the id to show action, I guess probably you need this in your routes:
Rails.application.routes.draw do
namespace :api do
resources :groups, only: [:index, :show]
end
end
and have index and show actions in your Api::GroupsController.
I suggest you go through rails guides. Understand the difference between resource and resources

Rails keeps displaying home page on root even when I delete the method in the Pages Controller

This is more of a question than a real issue, but I created a new rails project. I've changed the
Rails.application.routes.draw do
get 'pages/about'
get 'pages/contact'
devise_for :users
root to: 'pages#home'
end
and my Pages controller looks like this
class PagesController < ApplicationController
skip_before_action :authenticate_user!, only: [:home]
def home
end
def about
end
def contact
end
end
My homepage gets displayed even if I remove the home method.
I just wanted to know more about how this works.
I've looked around before posting and couldn't find an answer.
This is my first post here.
Thanks in advance
This is part of Rails 'convention over configuration' mantra. See Rendering by Default: Convention Over Configuration in Action
From the guide:
By default, controllers in Rails automatically render views with names that correspond to valid routes.
So, even if the home action is undefined, Rails will still render the home view because there is a valid route.

Rails controller using wrong method

I'm working on a Rails project that is giving me some problems. I've got a controller characters_controller.rb that has two methods.
class CharactersController < ApplicationController
before_action :authenticate_player!
def view
#character = Character.find(params[:id])
unless #character.player_id == current_player.id
redirect_to :root
end
end
def new
end
end
I've got routes set up for each of those.
get 'characters/:id', to: 'characters#view'
get 'characters/new', to: 'characters#new'
The first route works fine. I can get go to /characters/1 and I'm shown the appropriate view and the requested information. If I visit /characters/new I'm shown an error that references characters#view.
raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
and
app/controllers/characters_controller.rb:6:in `view'
So /characters/new is trying to get a Character from the database with an id of "new" but that doesn't work well. Any idea what I may be doing wrong?
Order matters in routes.rb, the router will find the first route that matches.
In your case, it would never go to characters#new, because the line above it will always match.
A simple solution would be to swap the two lines.
A better solution might be to use resource routing as documented in the Rails routing guide.
Rails parses routes sequentially and therefore it is considering 'new' as the :id for characters/:id route (which encountered first).
Just swap the order of routes as follow:
get 'characters/new', to: 'characters#new'
get 'characters/:id', to: 'characters#view'
If using this order in your routes.rb, for /character/new request, rails will understand that request is handled by view action with paramas[:id] = 'new'
Let characters/new before the other will resolve your problem:
get 'characters/new', to: 'characters#new'
get 'characters/:id', to: 'characters#view'
Try to use resourceful routes, much cleaner:
resources :characters, only: [:new, :show]
Also I suggest rename def view to def show to follow rails convention
Just use
resources :characters, :path => "characters"
in your routes.rb

Rails namespaced routes to wrong Controller

So I'm just beginning with RoR and figured I do a basic blog with API endpoints aswell. The problem is that my api requests seem to be routed to the wrong controller,
I have the following as my routes.rb
Blog::Application.routes.draw do
namespace :api do
namespace :v1 do
resources :articles
end
end
end
I also have controllers/api/v1/articles_controller.rb, which has the following content:
module API
module V1
class ArticlesController < ApplicationController
respond_to :json
def index
respond_with Article.all
end
end
end
end
My logic says that when I hit http://localhost:3000/api/v1/articles, this should be the Controller to respond, however the actual Controller that responds is the one in the root of controllers (controllers/articles_controller.rb) and not the one in the /api/v1 path. When I remove the Controller that actually responds, I'll get uninitialized constant Api::V1::ArticlesController instead.
Even rake routes gives me the expected routes, however actually hitting those endpoints fails. Output of rake routes is the following:
api_v1_articles GET /api/v1/articles(.:format) api/v1/articles#index
POST /api/v1/articles(.:format) api/v1/articles#create
new_api_v1_article GET /api/v1/articles/new(.:format) api/v1/articles#new
edit_api_v1_article GET /api/v1/articles/:id/edit(.:format) api/v1/articles#edit
api_v1_article GET /api/v1/articles/:id(.:format) api/v1/articles#show
PUT /api/v1/articles/:id(.:format) api/v1/articles#update
DELETE /api/v1/articles/:id(.:format) api/v1/articles#destroy
The only similar question I found on SO is nested namespace route going to wrong controller however, there's no accepted answer there and it's been a year. Maybe another attempt will help resolve this issue
Your module is API, but Rails is looking for Api. Ruby's modules are case-sensitive.

Resources