Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails Presenter block method

EDIT:

I got many responses with different approaches for solving the problem, thanks a lot!

Sadly, none of them worked until now.

To easily understand and reproduce the failure, I created a small Rails repo on GitHub with a Rspec suite.

One of the specs is passing (where the presenter is initialized in the view). One of the specs is failing (where the presenter is initialized in the controller).

How make them both pass ?

ORIGINAL QUESTION BELOW:

This is my Presenter:

class UserPresenter
  def initialize(user, vc)
    @user = user
    @vc   = vc
  end

  def linkify()
    #
    # HERE IS THE PROBLEM
    #
    vc.link_to("foo") do
      yield
    end
  end
end

This is my Controller:

I initialize my Presenter in the controller, passing the view context of the controller with the presented model.

class UserController
  def show
    @user = User.find(#.....
    @presenter = UserPresenter.new(@user, view_context)
  end
end

In my Slim template, I call my Presenter to put the content in a link:

[email protected] do
  p "123"

My problem is, I can't pass the block from the view to my linkify method.

In the with comment marked above code, the passed block is the whole view content, instead of the p 123.

When I initialize my Presenter in the view via: @presenter = UserPresenter.new(@user, self), it works as expected.

How I can make the linkify method uses the provided block, without initializing the presenter in the view ?

like image 553
astropanic Avatar asked Jan 12 '23 08:01

astropanic


1 Answers

Because if you are going to use the yield command, you mustn't specify the &block, since now you are effectively receiving a block as a parameter using normal parameter syntax.

class UserPresenter
  def initialize(user, vc)
    @user = user
    @vc   = vc
  end

  def linkify() # <-- Remove &block
    vc.link_to("foo") do
      yield
    end
  end
end

# ...
# Somewhere else, assuming you have access to @presenter which is an instance of
# UserPresenter
# ...

def show
  @presenter.linkify do
    # ...
    # do my view stuff here
    # ...
  end
end

show()

# Now, if your "View" is nothing but a block that needs to get passed in
# then you'd do this...

def show(&block)
  @presenter.linkify do
    block.call()
  end
end

# This would be used this way:

show(lambda {  
  # ...
  # View stuff here
  # ..
}) 
like image 199
Marcel Valdez Orozco Avatar answered Jan 19 '23 16:01

Marcel Valdez Orozco