Getting 'Unknown action in controller' - ruby-on-rails

I'm getting this error :
"The action 'create' could not be found for ObjectController"
I know it should be obvious but I'm missing something, that's my controller :
class ObjectController < ApplicationController
def index
end
def create
end
end
And that is my routes :
Rails.application.routes.draw do
get 'object/index'
get 'object/create'
match ':controller(/:action(/:id))', :via => :get
resources :objets
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'object#index'

You probably want to scrap those routes and try something simpler like
resources :objects, only: [:get, :create, :show]
Then use
$ rake routes
To make sure your routes are as the should be. You will want a POST route to /objects to create a new object etc..

Ok that one was dumb, actually I had two directories and I wasn't modifying the right one, sorry about that...

Your routes could be greatly improved:
#config/routes.rb
Rails.application.routes.draw do
root 'objects#index'
resources :objects
--
Next, the "standard" way to achieve what you're looking for is to use the new action; IE not the "create" action. If you wanted to use the create path name (instead of new), you'll be able to define it in the path_names argument:
#config/routes
resources :objects, path_names: { new: "create", create: "create" } #-> url.com/objects/create
To understand why you should be using new instead of create, you should look up resourceful routing, and how it pertains to object orientated programming.
Finally, your controller should be named in the plural:
#app/controllers/objects_controller.rb
class ObjectsController < ApplicationController
...
end
Whilst you can call it whatever you like, Rails defaults to plural controller names, singular model names.

Related

Create views in resource in Rails

I am a beginner working with Rails: I have this routes.rb:
Rails.application.routes.draw do
resources :requirements
root "department#index"
get "department/about"
end
How can I create a view that has a path like requirements/major?
Thank you so much!
You can extend resources and add custom actions, like this:
resources :requirements do
collection do
get :major
end
end
You'll need an action in the RequirementsController that matches, e.g.
class RequirementsController < ApplicationController
def major
# set up whatever resource 'major' corresponds to
end
...
end
That's at least one way of doing it. You could also have a controller that directly supports the nested 'major' resource, which would be similar to above - just with a controller: 'name of controller' directive inline..
It'd probably pay to get your head around the "Rails Routing from the Outside In" guide: https://guides.rubyonrails.org/routing.html

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.

Routing to non-restfull controller

I have a controller Sagepay, which have number of custom method (not RESTfull resources). How can I write routes for those actions? So far I tried:
namespace :sagepay, controller: :sagepay, as: :sagepay do
post :notification
get :iframe_breaker
get :accept_payment
end
This however tries mapping to sagepay/sagepay_controller instead simple sagepay_controller.
Obviously I can do this:
match '/sagepay/notification' => 'sagepay#notification', via: :post, as: sagepay_notification
(etc)
which works, but this is not a solution I am looking for. Is there any way I can write it in common block?
The reason you get sagepay/sagepay_controller is the reason why namespaces are used. In order to get sagepay/notification you can define a resource and add collection routes within it, as follows:
# config/routes.rb
resource :sagepay, controller: :sagepay do
collection do
post :notification
get :iframe_breaker
get :accept_payment
end
end
Update:
In order to define only the routes defined within the collection and avoid definition of the seven restful routes that Rails create you can pass in only option to the resource definition as follows:
# config/routes.rb
resource :sagepay, controller: :sagepay, only: [] do
collection do
post :notification
get :iframe_breaker
get :accept_payment
end
end
I think I found the solution:
scope 'sagepay', controller: :sagepay, as: :sagepay do
post :notification
get :iframe_breaker
get :accept_payment
end

Dynamic named routes in Rails

I have a simple problem where in a routes/url name is determined by a user role. Currently the route displayed is /new_admin/dispensaries. If the user has a role of either manager or executive then the named route should be '/dashboards/dispensaries'.
It's kind of simple but the hard part is that in my routes.rb:
namespace :new_admin do
resources :vendor_templates
resources :markdown_docs
resources :email_lists
namespace :moderation do
resources :reported_reviews
end
resources :users do
member do
get :user_bans
post :ban_unban, to: 'user_bans#create'
delete :ban_unban, to: 'user_bans#destroy'
end
end
# TODO - this should be written generically to support dispensary/doctors/whatever
get '/dispensaries/reviews', :to => "reviews#all", :as => :all_reviews
get '/dispensaries/pictures', :to => "pictures#all", :as => :all_pictures
get '/dispensaries/videos', :to => "videos#all", :as => :all_videos
get "/dispensaries/autocomplete", to: "dispensaries#autocomplete"
resources :vendors do
resources :ownership_transfers, only: [:new, :create]
end
...
I'm kind of stuck since if I change the new_admin routes, so many other routes will be affected. Any idea guys?
We've actually done something like this. It's not pretty, but this solution worked for us:
Slugs
You're basically alluding to a type of your routes called Slugs. This is where you use a name instead of an ID, allowing you to make a user-friendly route (such as /delivery/today). The problem is that in order to create these routes, you have to define them individually in the routes file
There are two Gems you can use to handle your slugged routes -- FriendlyID & Slugalicious. Both of these allow you to create slugged routes, but FriendlyID basically just changes the ID, whilst Slugalicious is a totally independent system
We used Slugalicious for the code below, however, you'll probably want FriendlyID (there's a RailsCast for it here):
Routing
The problem you have is that routes are outside the scope of the RESTful controller interface, which means you'll have to call all the routes exclusive of your resources references in the routes.rb file
If you use Slugalicious, it has its own Slugs database, which means we can use it to create the routes on the fly, like this:
#Slugs
begin
Slug.all.each do |s|
begin
get "#{s.slug}" => "#{s.sluggable_type.downcase.pluralize}#show", :id => s.slug
rescue
end
end
rescue
end
This is live code, and outputs all the slugs in the routes file dynamically. The way we managed to get this to update programmatically was to use an Observer Class like this:
class SlugObserver < ActiveRecord::Observer
def after_save(slug)
Rails.application.reload_routes!
end
def after_destroy(slug)
Rails.application.reload_routes!
end
end
I appreciate you may have your answer already, but as you're a beginner, I felt I could help out by explaining the slug stuff for you

The action 'index' could not be found for Controller

I am trying to make a controller with one action and when i try and go to the localhost:3000/controllername/action i get this error:
The action 'show' could not be found for LearnController
Here is my controller:
class LearnController < ApplicationController
def more
end
end
and in routes i do this:
resources :learn
I know that resources creates all the show, edit, index and all that but how do I make it so only the actions i create are created in the routes?
As you mention, resources :learn will create a bunch of routes according to the resourceful convention.
If you don't want those, don't use resources in your config/routes.rb file. Instead, use get, match, and friends to define your routes manually. E.g.
get 'learn/more'

Resources