Is there a way to create a view helper file that will be available to all views in a namespace? Like application_helper.rb, but only working for a given namespace.
Specifically, I have a namespace called "office". I want to set up a view helper that is accessible to any view within the "office" namespace.
Thanks.
I would suggest that you have a BaseController for that specific namespace. For example,
class Office::BaseController < ApplicationController
helper :office
end
And inherit this controller in all the other controllers within that namespace.
class Office::UsersController < Office::BaseController
def index
..
end
end
Now all the methods within the helper office_helper.rb is present within this namespace.
Also, this is a good practice to separate the concerns / code for the controller namespaces.
Related
I have a Padrino application with a controller and a corresponding helper (similar to Rails). Sorbet is reporting a method defined in the helper as being missing in the controller which is calling it. Is there anything to do about this in the current implementation of Sorbet?
You can define in an rbi file that the controller includes the helper. That will trick Sorbet to include the methods from the helper
# — foo_controller.rbi
class FooController
include BarHelper
end
I'm using Attribute Routing in WebAPI. My question is more on creating sub-folders under controllers in WebAPI (not in MVC, I'm using Areas for that)
I searched what kind of impact it would cause to the existing routing pattern and mostly they referred like adding custom routing template in WebAPIConfig.cs. But since I'm using AttributeRouting, is it really required to create custom template??
I tested my code and it seems to be working fine without any custom templates and I'm also able to achieve modularization by creating sub-folders under Controllers folder but would like to know the best practice and solution.
No - as you've found you don't need to create custom templates if you're using Attribute Routing.
The underlying method (MapAttributeRoutes) calls into the Controller factory to find all classes that inherit from Controller and then checks those for a Route attribute - so where they sit in the namespace hierarchy shouldn't matter.
If you are trying to mix Attribute and Convention routing and have sub-folders for convention based routes then you will need to define a custom template.
FYI: There is one small 'catcha' that you need to be aware off when (re)organizing your controllers in subfolders using attribute routing. Make sure your controller class has a unique name! Otherwise attribute routing gets confused and will not work. To illustrate:
// File: ~/Controllers/Customers/DetailsController.cs
namespace MyProject.Controllers.Customerss
{
[RoutePrefix("~/api/customers/{id}")]
public class DetailsController: ApiController {
[HttpGet]
public IHttpMessageResult GetItem(int id) {...}
}
}
and
// File: ~/Controllers/Orders/DetailsController.cs
namespace MyProject.Controllers.Orders
{
[RoutePrefix("~/api/orders/{id}")]
public class DetailsController: ApiController {
[HttpGet]
public IHttpMessageResult GetItem(int id) {...}
}
}
Although, cleary having different routes and certainly pointing to different controller classes it will throw off the attribute routing. By changing the controller classes to CustomerDetailsControlller and OrderDetailsController the routing issue resolved itself.
Background
I am creating a application that is made up of a core and several modules. The modules are rails engines, and provide the actual functionality as the core itself only acts as a host.
The engines are hosted from /lib and mounted at their respective paths.
coreApp
└──lib
├── module1
├── module2
└── etc
The modules are then mounted like this
mount Module1::Engine => "/module1", :as => "module1"
mount Module2::Engine => "/module2", :as => "module2"
The core is also responsible for handeling the session, although the login itself is done by a module.
Problem
I have yet to find a great way of sharing the core application layout with the engines. As of now, this is how I make the layout available to the engines:
coreApp
└── app
└── views
└── layouts
├── application.html.erb
└── core.html.erb
The file core.html.erb only contains
<%= render :template => 'layouts/application' %>
Is is then included in each module like this
module Module1
class ApplicationController < ActionController::Base
layout "core"
end
end
Although it isn't particularly elegant, it works fine, and the content of the module is rendered where the yield statement in the application layout.
The problems are as follows:
1. Module specific stylesheets are not included in the header
I need a way to include the stylesheets of the active module.
2. The header needs access to information about the logged in user
The header contains information about the logged in user, like
Logged in as <%= #user[:realname] %>
This comes from the cores home_controller
def index
#user = User.find_by_id(session[:user])
end
But when I try to access the module, I get the following error
NoMethodError in Module1/home#index
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
Obviously referring to #user.
Question
How can this be solved in as elegantly and DRY as possible without too much tampering on the engine side?
I have Googled this a lot but can't really get my head around how to solve it. It might be total lack of insight in how rails works, so there is a good chance this question doesn't even make sense for someone that knows rails well.
Please comment if anything is unclear or ambiguous, and I'll try to elaborate.
I have successfully used layouts of my parent application in my engines. Firstly, based on Section 4.3.2 of the Rails Guides (Engines), in order to access the parent applications ApplicationController's variables (like session, as you're using above), you need to replace the engine's application_controller.rb from this that you currently have:
module Module1
class ApplicationController < ActionController::Base
layout "core"
end
end
to this:
class Module1::ApplicationController < ::ApplicationController
end
This will inherit the parent application's ApplicationController, along with all it's variables.
Secondly, you'll need to delete the file app/views/layouts/application.html.erb from your engine views, as it will not be needed since you're using the parent application's one.
Now when you render a view of Module1 from the parent application, the layout of the parent application will be used, and all the session[] variables will be evaluated correctly.
Do not forget to add the words "main_app." before each link in your layouts, otherwise it will try and look for the paths in the engine instead of the parent application. For example, if the layout in the parent application includes a link to some_path (that is a view in the parent application), when showing a view in the engine that uses this layout will try and look for some_path in the Engine instead of the parent application. You will need to change the link to main_app.some_path for it to work.
Hope this helps.
Use layout 'layouts/application'
And if you don't want to use main_app.your_path you can also add:
module YourEngine
module ApplicationHelper
def method_missing(method, *args, &block)
if (method.to_s.end_with?('_path') || method.to_s.end_with?('_url')) && main_app.respond_to?(method)
main_app.send(method, *args)
else
super
end
end
end
end
I also did the same thing in my application. All I did was:
Delete the engine layout in /app/view/layouts/
Change your application_controller to
module EngineModule
class ApplicationController < ::ApplicationController
layout 'layouts/application'
end
end
In your views, if you want to refer to any path such as login_path, it can be referred via main_app.login_path
I have a Rails 3 controller which is not pluralized (IphoneUser) - it already has some controller methods, and a model generated.
However I'd like now rather than when it gets too late into the game, to pluralize it.
What's the best way to pluralize this controller without a nightmare of 1-by-1 guess and checks?
You should just need to rename the controller, it's class name, it's views folder, its helper and its functional tests. The only other option is to use the rails generator to destroy it rails destroy and then recreate it named properly. I'd just copy the controller methods and paste them into the new file. rails destroy won't affect your model.
I have a Rails 3 partial that lists all categories as a navigation menu - it's on most, but not all of my template pages...let's say about 75%. I'm trying to test the partial (in RSpec) right now, and I've just realised a few things:
At the moment, I'm calling Categories.all in the actual view. The difficulty is that, because that touches the database, my mocks/stubs in the view spec are ignored, and consequently the test fails.
I'm guessing the alternative is to assign the variable in the application controller, and then pass it as a local variable to the partial. Still, about 25% of my pages won't use the variable and I'm wondering if there's a more graceful way of doing things.
In short, I want view specs to pass without touching the test DB, but I'm not sure a global variable passed to my partial is the best way to do it...and I'm not declaring the variable in every (& only) those controllers who require it.
Any suggestions appreciated...
Why not create a helper method for all categories?
# in categories helper
def all_categories
#all_categories ||= Category.all
end
Or...
# application controller
helper_method :all_categories
def all_categories
...
You can then stub out this method in your specs and you won't be touching the DB