I have been developing in Ruby on Rails for a while now so I am completely confused at why this is happening. I created a controller called ApiController as you can see below.
class ApiController < ActionController::Metal
def documentation
end
def request_manager
end
end
Here are the routes I set to setup the documentation view.
Rails.application.routes.draw do
root 'landing#home'
get 'api' => 'api#documentation'
end
There is an documentation.html.erb file in the api folder as well, but
No matter what I do I get the following error.
It makes no sense to me why it's not routing correctly and has me completely baffled.
As a side note, the landing controller works perfectly fine and routes to the home page with no problem so it's just this controller.
Actually I just figured it out. Turns out that ActionController::Metal turns off must functionality including rendering so when you attempt to make it render as a normal controller, it faults while loading and the error is somewhere in the class files of Ruby's main code. Hence me not being able to find what was going wrong exactly till I looked up more documentation for the Metal controller.
I was using ActionController::Metal for it's speed and just didn't realize how much it stripped away from functionality in the process.
Related
I am trying to define some helper methods to be used in the app's controller, but it seems that rails don't even call the controller. just for the test I have the following controller in my app/controllers/my_engine/application_controller.rb and as the documents say rails should find it first and an error should raise because THIS_SHOULD_PRODUCE_ERROR is unknown, but the rspec happily executing without any errors!
class ApplicationController < ActionController::Base
THIS_SHOULD_PRODUCE_ERROR
end
I even tried to mimic the devise's way but the results are the same!
The guide section on the app directory suggests that the application_controller in an engine "will provide any common functionality for the controllers of the engine".
So I wouldn't expect that any additions to that controller will be available to all controllers in an application.
That also means that your application_controller is, I suspect, not getting called when you're running your test. Which would explain why you're not seeing an error.
In terms of how devise does it I think you need to be looking at how define_helpers works. The code you've linked to in your question is the application controller in the test app for the devise gem.
I noticed that I have got things wrong, and the application_controller in the engine does not get applied to application_controller in the app! Also, I couldn't figure out how the devise did it, but I have come up with the simple workaround for this:
require_relative 'controllers/helpers'
module Acu
module Injectors
class << self
ActiveSupport::Notifications.subscribe "start_processing.action_controller" do |**args|
eval((Acu::Configs.get :base_controller).to_s).class_eval do
include Acu::Controllers::Helpers
end
end
end
end
end
This will inject controller helpers to the user's base controller (which I get from the user, default: :ApplicationController) at the end of the class, which is perfect for me (but don't know how to add it to begging of the class if anyone needs it)
I am new to programming in general, someone referred me to railstutorial.org.
Specs: I am working on a cloud9 IDE, as suggested in the tutorial.
Information: I am on 1.3 of the rails tutorial, which is setting the root route.
The problem was initially my route did not effect the server launch (root page was still ruby default, not to 'application#hello'). Here are the files that the tutorial said to edit.
routes.rb
Rails.application.routes.draw do
root to: 'application#hello'
end
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def hello
render text: "Hello, world!"
end
end
There are a lot of comments that were defaulted into the files that I left out.
I have followed the instructions precisely. After I first had trouble, I thought I may have made an installation error, so I deleted my IDE and restarted, paying extreme attention to detail, especially versions.
I have tried $ rake routes, and my understanding it gives the message:
You don't have any routes defined!
That leads me to believe that the problem is the routes.rb file. I have tried changing the syntax to:
root to: 'application#hello'
I don't know a whole lot, such as how it would work using application, so I also tried:
root 'ApplicationController#hello'
and
root to: 'ApplicationController#hello'
These all result in the no routes defined message. I have no idea what is going on.
Thanks for any input or help!
You could try root 'application#hello' in your routes. Also, when starting out simple things like forgetting to save the file before trying things out on the browser can slip by; restarting the server takes care of a surprising number of foibles.
The rails documentation can also provide you a bit more information beyond the tutorial.
You probably want to move that action outside of the ApplicationController to another controller, but if you really insist, you can put this into your routes.rb:
get '/hello', to: 'application#hello', as: :hello
If you want the page to be the root, I would recommend creating a StaticPagesController and defining hello there, instead of putting it inside ApplicationController.
Here's what you can do:
Run rails g controller static_pages
Inside your StaticPagesController.rb, copy and paste your hello method that was inside ApplicationController.
Change the routes.rb to root 'static_pages#hello.
and you should have your desired result.
I've followed the same tutorial and I can say that the materials covered in the first two chapters are quite complicated at first if you are new to programming. It's only after you've done the entire tutorial that it will become clear to you how this routing thing (or any other details in these chapters for that matter) actually works.
However, since this idea of routing is very important, it's not a bad idea to understand how it works even if you are at an early stage in the tutorial.
The way you can create a route in rails is that you first specify a proper HTTP verb (GET, POST, PATCH, DELETE) with an appropriate path, the name of a controller, followed by a hash sign (#) and the name of an action defined in the controller.
Here controller is just a ruby class and an action a ruby method. (Since the basic principle of ruby on rails is "convention over configuration", it's important to get used to the terminology like controller, action, routing etc...)
When you say
get '/hello' => "application#hello"
(yes, you can use => in place of to:) as takeriho suggests, what happens is that a GET request to a URL of the type /hello(/ being "root path" as in www.example.com/(note the / at the end)) will get routed to the action, or method, named hello defined in a controller, or a class, named ApplicationController.
If you take a look at application_controller.rb, you can see that a method hello is defined within a class ApplicationController.
class ApplicationController < ActionController::Base
.....
def hello
render text: "Hello, world!"
end
end
Now if you want to specify a root route, which is your original question, you can just do root followed by the name of a controller, a hash sign (#), and the name of a class. So the code
root "application#hello"
means that a request to a url of the form /, or a root_path as it's called in rails convention, will get routed to the action (or method) named hello defined in a controller (or a class) named ApplicationController. You could accomplish the same result by doing
get '/' => "application#hello", as: :root
(you can name a route by adding as: :custom_name) but rails is smart enough to know that the two are equivalent. The task is made easier by following the rails conventions.
If you are completely new to Rails, I highly suggest you check out the Rails courses in Pragmatic Studio before going through the Ruby on Rails Tutorial which, as the author suggests, is not for a complete beginner. This approach worked perfectly for me. The rails courses offered by Pragmatic Studio assumes you have no prior knowledge about programming, and explains the basics in a manner much clearer than I did in this answer.
Happy coding :)
So I'm upgrading a Rails 2 app to Rails 3.2, which is mostly going smooth. However, I have a controller that handles uploading import files, ImportsController, and it uses some actions from a module Importable that provides the same actions to another controller.
class ImportsController
# standard REST stuff
include Importable
end
module Importable
def status
# code to return json has of state machine status
end
end
# routes
resources :imports do
member do
get :status
end
end
Which blows up with: The action 'status' could not be found for ImportsController. If I were to say, copy the status action into the ImportsController, everything is fine, however then I'd have to do the same thing in the second controller, so boo duplication. Any ideas what could be causing this?
It was a red herring. With the introduction Rails introduced ActionController::Metal, which defines def status
So I believe it's blowing up because Rails is now trying to use my method to get the HTTP status code and blowing up because it's not returning something that makes sense. Will refactor.
I'm trying to make a Rails application that serves simple static HTML pages. I followed Mikel's tutorial here (it involves making a Pages controller and setting up some routing) but I keep getting an error message.
I made a app/views/site/pages/_about.html.erb file to contain my About page. After starting the rails server, I try to go to http://localhost:3000/about/ but it gives me a Routing Error because I have an "uninitialized constant Site."
My project is uploaded to GitHub if you want to take a look at the code.
Edit: here's my config/routes.rb file:
NINAgallery::Application.routes.draw do
match ':page_name' => 'site/pages#show'
end
And here's the important part of my app/controllers/pages_controller.rb file:
class PagesController < ApplicationController
layout 'site'
def show
#page_name = params[:page_name].to_s.gsub(/\W/,'')
unless partial_exists?(#page_name)
render 'missing', :status => 404
end
end
# extra code for handling 404 errors goes here
end
site/pages#show means the show action in Site::PagesController
You either need to put your controller in the namespace your routes imply or change the route
The last line in the PagesController is this:
ValidPartials = Site::PagesController.find_partials
That means that the PagesController is contained in a Site module. But there is no Site module in your app.
I think simple removing Site:: should fix the problem:
ValidPartials = PagesController.find_partials
Plus the route:
match ':page_name' => 'pages#show'
Your application is called NINAgallery.
Replace Site in pages_controller.rb line 27 by NINAgallery.
PS:
I just took a peek at the so-called tutorial. You are taking really really really bad habits.
Some resources to take very good basics:
http://guides.rubyonrails.org/
http://api.rubyonrails.org/
If you like tutorials: http://ruby.railstutorial.org/
And there are plenty of books about rails. All good.
Besides the namespace problem, you also needed to add the 'app' Gem to the Gemfile, as explained in the tutorial.
I don't know why you removed the caching of the static pages in your working code. I made a pull request with the app working and maintaining the cache problem. If another person is interested, the code is here
Also ryan bates has a tutorial called "Semi static pages" that does something similar. I would encourage you to follow his solutions because there are very rarely mistaken.
I have an engine (developed by me / the company I work for) that we use on several different projects. I just converted it to work with rails 3.1 w/ assets pipeline and everything seems to be working... for the most part.
My problem is that I need to extend the functionality of the UsersController with a little bit of app-specific spice, but I'm not sure about the best way to do it. The engine doesn't define a Users#show action, but this app does need it, so I added to the routes file:
JobEngine::Application.routes.draw do
root :to => 'home#index'
resource :users, :only => [:show]
resources :jobs, :only => [:show]
end
Then in my application I created the UsersController:
class UsersController < MyEngine::UsersController
def show
end
end
Then I made a users/show.html.haml view, I've stripped it down to only show one of the problem lines:
= link_to "Somewhere", job_path(3)
This gives me an error that reads undefined method 'job_path' for #<#<Class:0x00000102d69900>:0x00000102d4ed30>
Which is bizarre because before I made my app's UsersController inherit from MyEngine::UsersController it worked just fine.
When I do rake routes in the console, there are these lines:
users GET /users(.:format) {:action=>"show", :controller=>"users"}
job GET /jobs/:id(.:format) {:action=>"show", :controller=>"jobs"}
I can alter the class definition to be:
class UsersController < ApplicationController
and then the link works just fine. However, the engine's controller MyEngine::UsersController already inherits from ApplicationController. I can put code into my app's ApplicationController (like a before_filter) and it will run as expected, so I know my class definition does ultimately hit my app's ApplicationController, why is the job_path helper not working?
When I change the show action to read:
def show
job_path(3)
end
I get the error:
ActionController::RoutingError (No route matches {:action=>"show", :controller=>"jobs", :id=>3}):
app/controllers/users_controller.rb:9:in `show'
Which further confuses me because now it actually does recognize job_path as a method, but somehow the router isn't picking up where to go with all the correct parameters.
What am I doing wrong? What is the correct way to extend engine controller functionality? I saw the extending engine functionality question here.
And followed that code example, changing my class definition to instead re-open MyEngine::UsersController but I still get the exact same results concerning job_path(NUMBER)
UPDATE:
Ok I sort of figured out what's going on. Let's say your engine has a job_path route, and your application has a job_path route. If you're on a page that was accessed via an engine's controller, you can call the engine's helper with just job_path, but you can also call the main application's helper with main_app.job_path.
Likewise, if you're on a page accessed via one of your application's controllers, you access the engine's helper with my_engine.job_path and your own application's helper with job_path. This is assuming that you have something like mount MyEngine::Engine => "/my_engine", :as => 'my_engine'.
When you inherit an engine controller from your application, it then completely changes your route helpers to think you're in the context of the engine through the controller/view lifecycle. So to fix my problem all I really have to do is change it to be main_app.job_path(3) and it works.
I'm not completely satisfied with this solution because it feels a little...weird. Maybe I have a partial on this page that will be used on a separate non-inheriting page. Now the link helper will only work for one of the two pages, but never both =\ Am I missing something here...?
Try changing your Mount path in main app's routes with below,
mount MyEngine::Engine => "/"
This would solve your problem.
Though you can make this approach work, the semantics do not create a clean architecture. You can surmise this from the duplication of the Users controller - which implies that some User functionality is handled in the AppEngine, and some is handled in the parent app itself.
Instead, think about what functionality exists uniquely within the app, and which is packaged into the AppEngine gem. Perhaps with JobEngine, as you call it, your Users controller there is actually a UsersStatisticsController and, in the app, the controller there is the 'true generic' UsersController that handles CRUD, profiles, message queue, etc.
If you feel you must unify them into a single controller (rather than giving them distinct nomenclature), then you are best to create a Namespaced controller, where the various functionality can be conjoined thereby.
Even though this adds complexity, it's generally arguable that this is the most sound solution. Here's another post on SO about it