What is the best and correct approach to do caching for actions?
Am I forced to ActionController::Base?
Is there another way (keeping ActionController::API present)?
Do I have to push caching down to Model layer?
I saw that Rails 6 (maybe prior) does not support action caching out of the box anymore. The caching was extracted to a gem: actionpack-action_caching https://github.com/rails/actionpack-action_caching. I installed it, but it seems not working with ActionController::API, it only works with ActionController::Base.
class ApplicationController < ActionController::API
must be changed to
class ApplicationController < ActionController::Base
Then, and only then I can cache an action like so:
class CategoryController < ApplicationController
caches_action :index
def index
#root_categories = Category.roots
end
end
Thank you in advance
The gem adds these methods to your controllers by including ActionController::Caching in ActionController::Base (see here). To add this behaviour to controllers that don't extend from ActionController::Base, simply include ActionController::Caching.
e.g.
class ApplicationController < ActionController::API
include ActionController::Caching
end
Related
Rails version is 6.0.0.3 and Ruby version is ruby 2.6.6-p146
I need to send the incoming request to the application controller to 2 different concerns based on the request format.
I have an application controller
class ApplicationController < ActionController::Base
include Authentication
include Authorization
before_action :authenticate_or_authorize
private
def authenticate_or_authorize
request.format.json? ? :authorize_request : :authenticate_request
end
end
I have 2 concerns namely authentication and authorization. if the incoming request is of type JSON, I need to call the authorization concern.
If it is a non json request i need to call authenticate_request.
Here are my concerns.
module Authentication
extend ActiveSupport::Concern
included do
before_action :authenticate_request, :return_url
end
private
def authenticate_request
// do something to authenticate
end
end
Here is the second concern.
module Authorization
extend ActiveSupport::Concern
include ::JwtVerifiable
included do
before_action :authorize_request
end
private
def authorize_request
// do something to authorize.
end
end
The current behavior is request always goes to the Authentication concern. Then afterward comes to the authenticate_or_authorize defined in the ApplicationController.
Can anyone help to correct the issue?
Thanks in advance.
The Concerns are already providing their own before_action calls when they are included (that's what included do (block) end is doing). This means that :authenticate_request, :return_url and :authorize_request are going to be run on every request. If you can't remove those from the concerns themselves, you skip them with:
skip_before_action :authenticate_request, :authorize_request
after including the concerns in ApplicationController. The before_action you've defined in ApplicationController will still run.
I have a RoR app with an admin_controller, the admin is able to CRUD Item, now I am a bit confused when it comes to routing. How can I create the app in a way that I can have a link to new_item be like: admin/item/new instead of creating an item controller with a authenticate_admin? method (since I use Device)
All in all how is this kind of routing achieved in rails
e.g. admin/orders/:id
or
store/sales/lates
Ideally , your admin_controller shouldn't do any CURD actions on an Item object. You should use an items_controller for that.
to achieve what you are trying to do, you can use an admin name space and maybe get the item_controller to be inherited from the admin controller.
So, you can have something like,
#app/controllers
AdminController < ApplicationController
end
#app/controllers/admin/
module Admin
ItemsController < AdminController
end
end
#config/routes
namespace :admin do
resources :items
end
rails namespaces
I'm using Grape to build an API.
I created an ActiveSupport::Concern let's say with the name Authentication and I applied some before filter so my concern looks like:
module Authentication
extend ActiveSupport::Concern
included do
before do
error!('401 Unauthorized', 401) unless authenticated?
end
....
end
end
Now let's say in my UserController I want to apply this concern only for a specific action. How can I do that?
class SocialMessagesController < Grape::API
include Authentication
get '/action_one' do
end
get '/action_two' do
end
end
Any easy way to specify the concern for a specific method just like before_filter in rails with only option?
Separate your actions into different classes and then mount them within a wrapper class:
class SocialMessagesOne < Grape::API
include Authentication
get '/action_one' do
# Subject to the Authentication concern
end
end
class SocialMessagesTwo < Grape::API
get '/action_two' do
# Not subject to the Authentication concern
end
end
class SocialMessagesController < Grape::API
mount SocialMessagesOne
mount SocialMessagesTwo
end
More information on mounting is available in the Grape README.
I have a model an a controller for a pages resource.
I need to be able to access the names of the pages
and the pages and link_to from within the
Application.html.erb
I have tried rendering a navigation partial.
But you can't access the controller from a partial.
I need to be able to render a navbar that has access
the #pages variable so I can loop through them.
What's the best way to do this?
Inside your ApplicationController, app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :get_pages
protected
def get_pages
#pages ||= Page.all
end
end
This way you're able to use the #pages instance variable from within any view.
By using memoization through the ||= operator you're only assigning the variable the first time you need it, so no need to worry about calling that method every time.
This is probably a stupid question, can you have a function available to multiple controllers?
I have 2 controllers
class C1Controller < ActionController::Base
def add(input_value)
#output_value = input_value * 2
end
end
now I would like to use this add function in another controller like so
class C2Controller < ActionController::Base
#new_value = add(2)
end
Define that function in app/controllers/application_controller.rb, and it will be available in all controllers.
ApplicationController can be used for this.
Make sure your other controllers are derived from ApplicationController and not directly from ActionController, as they should be. Then you can configure filters, common methods etc in the single ApplicationController.
But it might be wise to define a parent controller and have your controllers derive from it, as the ApplicationController is not really meant for random code sharing, but for specific purposes like filters and forgery protection.
You could also define the function in a helper and then include this helper in your ApplicationController. As follows:
include SessionsHelper