I have an application_controller spec that is failing since I removed the controller/action route from routes.rb. I get the following error:
No route matches {:controller=>"application", :action=>"index"}
I had many tests fail in the same way, but was able to fix them by including the correct parameters in the get call. So for instance, if I wanted to get the standard show route for posts in my spec, I had to change
get :show to get :show, :id => '1'
Unfortunately, I'm not sure now what to pass along for the application controller specs. I've included my test below.
describe ApplicationController do
it "should find the latest published posts and assign them for the view" do
Post.should_receive(:latest).and_return(#posts)
get :index
assigns[:posts].should == #posts
end
it "should find the latest approved comments and assign them for the view" do
Comment.should_receive(:latest).and_return(#comments)
get :index
assigns[:comments].should == #comments
end
end
Consider the ApplicationController as an abstract class not intended to be used for requests. All new controllers generated will inherit from ApplicationController so it is a nice place to put shared behavior.
Related
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
I am writing a basic application that scrapes data. I have the following in my routes.rb.
Rails.application.routes.draw do
constraints subdomain: 'api' do
namespace :api, path: '/' do
resources :apps, :only => :show
end
end
In controllers I have something like this although I am not sure how are resources connected to Controller.
class AppsController < ApplicationController
def show
puts "this works"
respond_to do |format|
format.json { render json: #user }
end
end
def apps
puts "my app"
end
end
Also, I dont have a Model. Does that mean that in my resources :apps calls a method in AppsController called apps?
If I wanted it t call apps then how's it possible ?
how does a controller in rails know what route does it belong to
I am trying to add a GET /apps?filter=5 that returns my scraped data in the form of JSON and with filter as parameter to that it means that return 5 JSON objects to me
#config/routes.rb
constraints subdomain: 'api' do
namespace :api, path: '/' do
get :apps, to: "apps#apps", on: :collection #-> api.url.com/apps
end
end
A much more coherent way to do it would be...
#config/routes.rb
constraints subdomain: 'api' do
namespace :api, path: '/' do
resources :apps #-> api.url.com/apps -> apps#index
end
end
I think you're getting confused with how Rails works, especially with your data.
I post this all the time, maybe it will help you:
As you can see, your request is not tied to a specific "model", nor is a controller bound to it either. I'll explain the importance of the MVC (Model View Controller) aspect of rails in a minute.
Your thought process is that each request / resource has to have a corresponding model / dataset to pull from. Strictly, this is not the case, although many would believe it to be.
Remember that Rails is just an application framework - it has to work with all the same protocols & restrictions as the other frameworks & languages out there.
When you send a request to Rails (through your browser URL), it takes that request, and matches it to the appropriate controller. This controller action will then pull data from your model (if you've set it up like that), render the view with that data, and return the processed HTML to the browser.
Thus, you don't have to have a model bound to a particular controller action, or anything. You just need to make sure your controllers & views are mapped accordingly.
OOP
I think the part you're getting hooked up on is the object orientated nature of Ruby / Rails.
Although every part of the Rails framework is meant to work with objects, this only applies on a request-basis.
For example, whilst it's typically recommended to keep your controllers resourceful, you don't have to adhere to that methodology if you don't want to. Many newbies don't know the difference.
Thus, when you use the following:
#config/routes.rb
constraints subdomain: 'api' do
namespace :api, path: '/' do
resources :apps, only: :show #-> api.url.com/:id -> apps#show
end
end
... what you're denoting is a controller bound by its resourceful nature. This would typically be expected to use model data, but it's not essential...
In controllers I have something like this although I am not sure how
are resources connected to Controller.
Rails.application.routes.draw provides a DSL which hooks into Rack (the interface between the HTTP server and Rails). It generates rules for where to route the response from Rack.
The DSL is provides has a lot of ways to do the same things. In this example, the resources :apps, :only => :show line basically says you want to generate all of the REST verbs for the AppsController, but you only want the :show verb, so the router will only generate a route to AppsController#show. Note that you can run rake routes to get a list of your routes.
Also, I dont have a Model. Does that mean that in my resources :apps
calls a method in AppsController called apps? If I wanted it t call
apps then how's it possible ?
Models are totally separate abstractions. Once the code reaches your controller you are in plain Ruby land until you return out of that controller action. Models are simply plain Ruby objects with the ability to talk to the database.
In your code if you wanted to call apps from the show method (or action) then you can just call it from there since it's in the same scope.
how does a controller in rails know that ok that is my route. In this case, apps
I'm not sure I understand this question, could you elaborate?
I am trying to add a GET /apps?filter=5 that returns my scraped data in the form of JSON and with filter as parameter to that it means
that return 5 JSON objects to me
For one, you'll need to add a route for /apps. There are several ways you can do this. Here's one approach. I'm going to call it index instead of apps since that's more conventional:
# config/routes.rb
get '/apps' => 'apps#index'
# app/controllers/apps_controller.rb
class AppsController < ApplicationController
respond_to :json
def index
limit = params[:filter].to_i
#users = User.first(limit) # Implement this however you wish
respond_with(#users)
end
end
My syntax might be a little off here with the respond_to and respond_with, but it should explain how the controller routes
Routing simply maps URLs to a controller/action, the existence of a model with the same name does not matter.
To get to the apps action that you defined in the AppsController you need to define a route that maps to apps#apps < This syntax means AppsController, apps action.
An example of a route that would map to the AppsController apps action:
get '/apps', to: "apps#apps"
This is a weird example. It's not conventional to have a def apps action inside AppsController, what exactly are you trying to accomplish with this action?
If you want a rest call to /apps that returns a JSON list of apps, then this all you need to do.
router
resources :apps, only: [:index]
controller
class AppsController < ActionController::Base
def index
puts "This is the index route in AppsController"
end
end
In the router, when you specify resource :apps, only: [:index]. This routes the request GET /apps to AppsController#index
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.
I was trying to write an integration test testing, if my controller raises a ActiveRecord::RecordNotFound exeption for deleted articles (which are just marked as deleted):
it "should return 404 for deleted articles" do
#article = Factory :article, :status => "deleted"
expect { get edit_article_path(:id => #article.id) }.to raise_error(ActiveRecord::RecordNotFound)
end
These kind of tests work fine in a controller spec, but inside of the spec/requests I get this error:
expected ActiveRecord::RecordNotFound, got #<ActionController::RoutingError: No route matches {:action=>"edit", :controller=>"articles", :id=>595}>
So it looks up my routes correctly (since it knows the controller etc.) but still raises the error. Why is that?
Thanks, Johannes
If this test is in your spec/controllers directory, then the get method you're calling isn't expecting a path, it's expecting a symbol for the controller action you want to call. So you'd need to change the expect line to something like:
expect { get :edit, :id => #article.id }.to raise_error(ActiveRecord::RecordNotFound)
Take a look at the RSpec Controller Spec documentation for more info.
When I go to my localhost:3000/users page, I get:
Unknown action
The action 'index' could not be found for UsersController.
If you were following Hartl's tutorial,then accessing localhost:3000/users will cause this error. Try localhost:3000/signup instead.
You need not define the default actions (assuming appropriate http method), all you need to do is add the following to your config/routes.rb
resources :users
First you need to make sure that your controller actually has an index action, so
class UsersController < ApplicationController has to include the def index ... end in it.
Also, make sure your routes are set up correctly using
resources :users
and check it by typing
rake routes
in the terminal to check that the routes are right.
You might also want to check that the root is set up correctly in the config/routes.rb file
if you got the same problem with me (I cant access the localhost:3000/users but I can access my localhost:3000/signup), it might be works for u.
First, in your users_controller.rb (Controller for Users) , add
def index
end
Then , make a file "index/html/erb" in your app/views/users/index.html.erb
and put this code
<% controller.redirect_to "/signup" %>
You might have to rerun your server, and it works on my problem.
Remember, if you've included
get 'signup' => 'users#new
resources :users
…in your routes.rb file, then you need to use localhost:3000/signup instead. I believe if you removed get 'signup' => 'users#new and left only resources :users then using localhost:3000/users would take you to the new user signup form.
Remove the debugger line. Also, make sure you have exit the rails console.
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
debugger
end
def new
end
end