drapergem / draper

Decorators/View-Models for Rails Applications

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

why decorate decorated object

briu opened this issue · comments

Why already decorated object decorates every time on calling decorate?

With this approach, we can lost context, for example

user = User.last
decorated_user = user.decorate(context: { test: 1 })
decorated_user.context
=> {:test=>1}

decorated_user.decorate.context
=> {}

Is it right behaviour?

What is the use case where you are calling decorate twice, but expecting the context to remain the same? That is, what is the need for calling decorate the second time?

Draper works best if you decorate at the very last moment, ideally in the view. Decorating early in the controller lifecycle is not recommended and leads to a whole host of problems.

We are using cells.

For example UserCell,

class UserCell
  def full_name
    user.full_name
  end

  def filtered_email
     user.filtered_email
  end

  def show_in_header?
     user.email.present? && user.show_everywhere?
  end

  def user
     object.decorate
  end
end

class UserDecorator < Draper::Decorator
  def full_name
     "#{object.name} #{object.surname}" 
  end

  def filtered_email
     "#{object.email}[0..5]"
  end

  def show_everywhere?
     context[:online]
  end
end

Inside cell object many times calling decorator methods, and we decorate object inside.

Should object been decorated, before initializing cell?

This cell initializes many times, in different places.

Both cells and Draper are designed to solve similar problems (i.e. alternatives to view helpers). I have never seen them used in conjunction, so that's pretty interesting. I think your problem will go away if you change your user method to:

def user
  @user ||= object.decorate
end

This is a common pattern in Ruby to prevent re-initialization or creation of objects. Let me know if this solves your problem.

We firstly decorate collection with context, and secondly inside cell

The problem could be solved with this

  cell(user.decorated? ? user : user.decorate)

And with usage object instead user inside cell.

But cell always need decorated object, and decorating object inside cell is obvious for me.

So, object.decorate - default, and decorate with context is how option

I'm not sure I followed that last sentence, but it sounds like you have a solution for this. Also, if you are decorating the collection beforehand, I don't think you will need to call decorate when passing it into the cell. For instance:

<% @users.decorate(context: { test: 1 }).each do |user| %>
  <%= cell(user) %>
<% end %>

But long story short, I believe this is the intended / expected behavior when calling decorate again. Let me know if I can help with anything else.