Reputation: 1673
I migrate an application from rails 5.2 to rails 6. There is only have one thing left to do but I don't know how.
I have this depreciation warning:
DEPRECATION WARNING: ActionView::Base instances should be constructed with a lookup context, assignments, and a controller. (called from new at /Users/xxx/xxxx/app/models/stock.rb:42)
from this code:
view = ActionView::Base.with_empty_template_cache.new(
ActionController::Base.view_paths,
categories: categories,
periods: periods
)
result = view.render formats: [:xlsx],
handlers: [:axlsx],
template: 'admin/reports/logistics/stocks_by_age'
I don't understand how to fix it. I went to see the depreciation in the source code, but it didn't help me figure out what I should do, and I didn't really find any documentation for this 'lookup'.
Please, could someone help me to understand this depreciation?
Upvotes: 13
Views: 7641
Reputation: 141
Using ApplicationController.render
didn't work for me so I built up my custom reusable solution.
# lib/custom_action_view.rb
module CustomActionView
extend self
delegate :view_paths, to: "ApplicationController"
def build
ActionViewExtended.with_view_paths(custom_view_paths)
end
# This method shouldn't be necessary but in some cases overriding
# +compiled_method_container+ (as the deprecation message suggests)
# is not enough
def custom_view_paths
return view_paths if Rails.env.production?
view_paths.each(&:clear_cache)
end
class ActionViewExtended < ActionView::Base
include Rails.application.routes.url_helpers
def compiled_method_container
self.class.superclass # => ActionView::Base
end
def default_url_options
Rails.application.config.url_options
end
end
end
then if you have something like
view = ActionView::Base.new
view.extend MyParticularHelper
view.render(options)
can now be
view = CustomActionView.build
view.extend MyParticularHelper
view.render(options)
It also removes the deprecation message.
Upvotes: 0
Reputation: 1458
This deprecation warning appears because you passed ActionController::Base.view_paths
to ActionView::Base.new
as the first argument. This used to be okay but now an instance of ActionView::LookupContext
is expected. If you look at the most recent version of ActionView::Base#initialize
you'll see that where the message appears it calls ActionView::Base.build_lookup_context
using your first argument to ActionView::Base.new
. You can easily silence this warning by passing ActionView::LookupContext.new(ActionController::Base.view_paths)
or ActionView::Base.build_lookup_context(ActionController::Base.view_paths)
since that's what it ends up using anyways.
While ApplicationController.render
is helpful for rendering a view outside of a request sometimes you need an instance of ActionView::Base
by itself (in my case I use one as the view context for my presenter classes in their tests).
Upvotes: 5
Reputation: 3352
It looks like you are trying to render view outside of the request. Rails added a feature in the past, that simplified this. Now only thing you need to do is to call ApplicationController.render
with your params. In your case it should look something like this:
ApplicationController.render(
template: 'admin/reports/logistics/stocks_by_age',
locals: { categories: categories, periods: periods } # maybe assigns: { ... }
handlers: [:axlsx],
formats: [:xlsx]
)
Also following code should work as well if you have logistics controller:
Admin::Reports::LogisticsController.render(:stocks_by_age, ...other params same as above..., handlers: [:axlsx], formats: [:xlsx])
See the following article for better description of how to do it. https://blog.bigbinary.com/2016/01/08/rendering-views-outside-of-controllers-in-rails-5.html
Upvotes: 21