require "dry/view"
class ArticlesListingView < Dry::View
config.paths = [File.join(__dir__, "templates")]
config.part_namespace = Parts
config.layout = "application"
config.template = "articles/index"
attr_reader :article_repo
def initialize(article_repo:)
@article_repo = article_repo
super
end
expose :articles do
article_repo.find_all
end
end
and following is the template (implemented using HAML) rendered by that view
I tried experimenting with using exposures in following shown 3 ways for achieving that but it didn’t worked:
expose :article_edit_link_path do |article_id: nil|
construct_article_edit_link_path(article_id)
end
expose :article_edit_link_path do |article_id:|
construct_article_edit_link_path(article_id)
end
expose :article_edit_link_path do |article_id|
construct_article_edit_link_path(article_id)
end
private
def construct_article_edit_link_path(article_id:)
"/articles/#{article_id}/edit"
end
Which makes me ask the question are exposures meant for the purpose I mentioned or there is a different provision in dry-view for achieving the need at hand?
@alassek Thanks for your reply and recommendation of defining the helper method in Context class. I explored more around it and trying to understand the runtime workflow found that when a template gets rendered by following code
a scope is passed while rendering (ref: dry-view/renderer.rb at main · dry-rb/dry-view · GitHub) and thus checking out Dry::View::Scope implementation found that if no scope class is explicitly defined for a view then by default Dry::View::Scope (L63 in this class implementation) should be used and any methods invoked in the template not found in the scope class should be looked for in Context class through method_missing defined at L155 in Dry::View::Scope class.
Now in my understanding usually a Context should remain same for all views in an application so instead of bloating the Context class with desired behaviour helpers for views of different nature, it is better to use custom scope class for a specific view. That custom scope class should encapsulate the helpers relevant only for a desired view . For e.g. I tried following and it worked:
views/articles/scopes/listing.rb
require "dry/view/scope"
module Views
module Articles
module Scopes
class Listing < Dry::View::Scope
private
def article_edit_link_path(article_id:)
"/articles/#{article_id}/edit"
end
end
end
end
end
views/articles/listing.rb
require "dry/view"
module Views
module Articles
class Listing < Dry::View
config.paths = [File.join(__dir__, "templates")]
config.layout = "application"
config.template = "articles/index"
# Note this
config.scope = Scopes::Listing
attr_reader :article_repo
def initialize(article_repo:)
@article_repo = article_repo
super
end
expose :articles do
article_repo.find_all
end
end
end
end
And then in the view I could successfully use article_edit_link_path(article_id:) I defined in the Views::Articles::Scopes::Listing scope class defined and configured specifically for Views::Articles::Listing.