# dry-view: how to define a helper method, with an arg, in view class which can be invoked from view template

**URL:** https://discourse.dry-rb.org/t/dry-view-how-to-define-a-helper-method-with-an-arg-in-view-class-which-can-be-invoked-from-view-template/1596
**Category:** Support
**Created:** [January 19, 2023, 11:13am UTC](https://discourse.dry-rb.org/t/dry-view-how-to-define-a-helper-method-with-an-arg-in-view-class-which-can-be-invoked-from-view-template/1596 "2023-01-19T11:13:09Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![jignesh](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/jignesh/32/832_2.png) [@jignesh](https://discourse.dry-rb.org/u/jignesh)
#### Post date: [January 19, 2023, 11:13am UTC](https://discourse.dry-rb.org/t/dry-view-how-to-define-a-helper-method-with-an-arg-in-view-class-which-can-be-invoked-from-view-template/1596/1 "2023-01-19T11:13:09Z")

</div>

Let’s assume following is my view

```auto
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

```auto
- articles.each do |article_obj|
  %h1= article_obj.title
  %div<
     %a{ href: "/articles/#{article_obj.id}/edit" } Edit

```

Now I would like to move the edit link construction to a helper method in my `ArticlesListingView` class like following

```auto
def article_edit_link_path(article_id:)
   "/articles/#{article_id}/edit"
end

```

so that in the template I can use it in following manner

```auto
- articles.each do |article_obj|
  %h1= article_obj.title
  %div<
     %a{ href: article_edit_link_path(article_id: article_obj.id) } Edit

```

So how can I achieve that?

I tried experimenting with using exposures in following shown 3 ways for achieving that but it didn’t worked:

```auto
  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?

Thanks.

---

<div class="post-metadata">

### Author: ![alassek](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/alassek/32/314_2.png) [@alassek](https://discourse.dry-rb.org/u/alassek)
#### Post date: [January 19, 2023, 7:00pm UTC](https://discourse.dry-rb.org/t/dry-view-how-to-define-a-helper-method-with-an-arg-in-view-class-which-can-be-invoked-from-view-template/1596/2 "2023-01-19T19:00:40Z")

</div>

An exposure is for passing values into the view, not behavior. You want to use [Context](https://dry-rb.org/gems/dry-view/0.7/context/) in this case.

---

<div class="post-metadata">

### Author: ![jignesh](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/jignesh/32/832_2.png) [@jignesh](https://discourse.dry-rb.org/u/jignesh)
#### Post date: [January 20, 2023, 1:39pm UTC](https://discourse.dry-rb.org/t/dry-view-how-to-define-a-helper-method-with-an-arg-in-view-class-which-can-be-invoked-from-view-template/1596/3 "2023-01-20T13:39:48Z")

</div>

@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

> <https://github.com/dry-rb/dry-view/blob/main/lib/dry/view.rb#L470>

a `scope` is passed while rendering (ref: [dry-view/renderer.rb at main · dry-rb/dry-view · GitHub](https://github.com/dry-rb/dry-view/blob/main/lib/dry/view/renderer.rb#L32)) 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**

```auto
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**

```auto
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`.

Thanks.

---

<div class="post-metadata">

### Author: ![alassek](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/alassek/32/314_2.png) [@alassek](https://discourse.dry-rb.org/u/alassek)
#### Post date: [January 22, 2023, 6:09am UTC](https://discourse.dry-rb.org/t/dry-view-how-to-define-a-helper-method-with-an-arg-in-view-class-which-can-be-invoked-from-view-template/1596/4 "2023-01-22T06:09:25Z")

</div>

If it helps, this pattern is pretty much universal across all templating systems that I’m familiar with.

Consider [how ERB does the same thing](https://github.com/ruby/erb/blob/master/lib/erb.rb#L417-L430). Every template system that executes code accepts a string template, and a binding context.

`Dry::View::Scope` is a formalized way of customizing your binding context when the template renders.
