All threads / Decorators From Scratch Discussion

Ask A Question

Notifications

You’re not receiving notifications from this thread.

Decorators From Scratch Discussion

Dicussion for Decorators From Scratch

Nailed it. Thanks again Chris - could never find a good explanation on Decorators, hence I never used them, will be sure to use them now!

That's awesome to hear. Thanks Nick! :)

Reply

Thanks, Chris, helpful as always! You also can use SimpleDelegator to handle the ActiveRecord (and delegation) issues. Here's an example https://hashrocket.com/blog...

That's pretty neat. I know I've seen SimpleDelegator mentioned before in but never looked into it. I'll have to fiddle with it now!🤘

Yea I learned of the technique in this context from Noel Rappin's book, Rails 4 Test Prescriptions (which is a great book, link here: https://www.amazon.com/Rail.... He uses it for presenters, which I've used and liked.

Reply

mmm... looks like a lot of dependency and complexity to keep a eye for.

Reply

When should use decorators VS helpers?

Reply

Great episode Chris! Definitely going to be using this. One thing I'm curious about, I often use partials to render collections instead of iterating through them in the view, e.g. render @users instead of @users.each do |user|... How would this work (or would it work) with the decorated user objects? I suppose you would just need to specify the partial name and local variables instead of relying on the rails shorthand of render @users right?

Whoops, I had this tab open to reply to at some point...9 days later. :P

Yeah, you'd probably need to pass the partial name in to pass over the presenters that way. I'm sure there's some way you could override some things in the presenter trick Rails into rendering the proper partial name automatically. The draper gem might be able to do that and have some insights on how to pull that off with your own implementation. I know that they have a Relation-esque collection object that might be what you'd need to add to your own implementation from scratch to do that.

Reply

Thanks. Great Episode !
I have one remark though: Is it really a good idea to use the view context in the decorator, for creating things like html tags ? Doesn't this create a coupling of the decorator with the view format? I mean you this way, you will need a different decorator for xml or json views (which do not use content_tag helpers etc...)

That's a great question. If you need to build decorators that work in both cases, then yes, you'd want to do one of two things:

1. Separate decorators for JSON and HTML and wrap them accordingly depending on the response type. Downside to this is more decorators.
2. Build generic decorators and leave it up to your views. Downside to this is that part of the benefit of having the link_to's and etc in the decorator is that your view can remove logic entirely. That's probably not possible if you're not able to write logic in the decorator.

Reply

Hi Chris, if we are using Rails 4+, we don't actually need to modify the `auto_load_paths` anymore, as:

> All subdirectories of app in the application and engines present at boot time. For example, app/controllers. They do not need to be the default ones, any custom directories like app/workers belong automatically to autoload_paths
> http://guides.rubyonrails.o...

I thought that was the case! It didn't work for me the first time I tried it, but it could have been spring caching things or something. Thanks for sharing that. :D

Reply

Awesome episode! One thought on collections of presenters. I found it annoying to keep writing out the collection.map { |object| ObjectPresenter.new(object) } syntax every time.

In my situation I use a BasePresenter that all my other presenters inherit from. I then add a class method "collection(...)" that allows me to create a collection of presenters with cleaner syntax.

The above syntax now looks like this:

@objects = ObjectPresenter.collection(Object.all, view_context)

class BasePresenter < SimpleDelegator
def self.collection(objects, view = nil)
objects.map { |object| new(object, view) }
end

def initialize(object, view = nil)
@object = object
@view = (view || ActionController::Base.helpers)
super(@object)
end
end

Reply

Found this very useful, thank you! If you have any more patterns wisdom, please bring it on :)

Reply

Amazing episode! I guess this kind of decorators are different to the decorators in the GoF book. Those inherit from the class they decorate to adhere the Liskov's substitution principle. I suppose this can't be done because active record naming conventions would not be compatible with this.

Reply

What exactly is view_context? Also what exactly is happening in config.autoload and why do we have to create a module in the application.rb ? is a decorator just a class that wraps around a model or something to extend its functionality in a well-encapsulated manner so that the scope of itis separate and gives us a way to separate the concerns of an application more?

Reply
Join the discussion

Want to stay up-to-date with Ruby on Rails?

Join 37,629+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    logo Created with Sketch.

    Ruby on Rails tutorials, guides, and screencasts for web developers learning Ruby, Rails, Javascript, Turbolinks, Stimulus.js, Vue.js, and more. Icons by Icons8

    © 2020 GoRails, LLC. All rights reserved.