2
- if clean_book_intro_component(:literary_works).present?
  %h2 Other Books Related to #{@book.title}
  %p.fact-text
    = clean_book_intro_component(:literary_works)

Can above code written by calling clean_book_intro_component(:literary_works) only once?

Implementation of clean_book_intro_component

def clean_book_intro_component(component)
  sanitize @book.intro.send(component), tags: %w(span b i p a), attributes: %w(id class style href)
end
2
  • Why do you want to avoid calling clean_book_intro_component(:literary_works) twice? Is it an expensive method? Commented Jan 5, 2016 at 9:43
  • @spickermann: no, just wondering if there is better way to go about it. Commented Jan 5, 2016 at 9:44

4 Answers 4

1
- clean_book_intro_component(:literary_works).tap do |cbic|
  - if cbic.present?
    %h2 Other Books Related to #{@book.title}
    %p.fact-text
      = cbic

maybe I got haml wrong, but the idea is to use tap instead of explicitly saving the result of the call

Sign up to request clarification or add additional context in comments.

2 Comments

Nice! I was trying to post similar answer, but could not get indentation right and kept getting error.
This is cool, are there any performance caveat for using tap over calling method two times?
1

Assigning variables in view is generally not recommended. However, in this case you can use an inline assignment which is generally accepted (as long as you keep the usage scoped within the context of the condition block):

if (intro = clean_book_intro_component(:literary_works)).present?
  %h2 Other Books Related to #{@book.title}
  %p.fact-text
    = intro

Another solution is to memoize the value inside the function.

def clean_book_intro_component(component)
  @component ||= {}
  @component[component] ||= sanitize @book.intro.send(component), tags: %w(span b i p a), attributes: %w(id class style href)
end

However, this will cause the interpreter to retain the data as long as there is a reference to the instance. Therefore, this is recommended only in very particular cases where the execution is expensive and/or the data to be memoized is limited.

Moreover, it requires some extra complications if the helper accepts parameters. In fact, you will end up memoizing an amount of data which is linear with the possible input of the parameters.

Comments

0

Yes, just save the result of clean_book_intro_component(:literary_works) in a variable and then use that variable instead of invoking the function.

2 Comments

Hmm.. that I know, I'm just wondering if there is any better way to do it.
@SimoneCarletti: Didn't realize it was a view. I'm not really familiar with RoR or Ruby. Still think it's fine, but I guess it should really be in the underlying model instead.
0

You could move the view into a partial and call the partial on a collection. If the collection is empty nothing is rendered. Something like:

# a related_books partial
%h2 Other Books Related to #{@book.title}
  %p.fact-text
    = related_books


# in the calling view
= render partial: related_books, collection: [clean_book_intro_component(:literary_works)]

See the Rails Guide about rendering collections.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.