0

I created this class for assembling the text based on the length of the product attributes for sharing on twitter.

My questions:

  • Is this the good approach to tackle the problem? If not this then what? (where should I put the class and the methods, how to invoke it, etc.)
  • If this is the good approach then what should be changed? For instance I feel the def twitter_share_text shouldn't be in the product.rb.

show.html.erb

<a class="twitter-share" data-behavior="twitter-share" 
                         data-twittertext="<%= @product.twitter_share_text %>" 
                         data-twitterurl="<%= product_url(@product) %>" 
                         data-twitteranchor>
  <i class="fa fa-lg fa-twitter"></i>
</a>

product.rb

def twitter_share_text
  TwitterProductShare.new(self).return_text
end

app/services/twitter_product_share.rb

class TwitterProductShare
  URL_LENGTH = 23 #defined by twitter API
  SPACE_LENGTH = 1
  TWITTER_MAX = 140
  attr_reader :name, :oneliner

  def initialize(product)
    @name = product.name
    @oneliner = product.oneliner
  end

  def return_text
    if full_length <= TWITTER_MAX
      return basic_text
    else
      return basic_text[0...-(difference + text_end.length)] + text_end
    end
  end

  private

    def basic_text
      "#{name}: #{oneliner}"
    end

    def difference
      full_length - TWITTER_MAX
    end

    def full_length
      basic_text.length + SPACE_LENGTH + URL_LENGTH
    end

    def text_end
      "..."
    end
end
Sean Magyar
  • 2,360
  • 1
  • 25
  • 57

1 Answers1

1

I think code like that belongs into a view helper:

# in app/helpers/product_helper.rb
def twitter_share_link(product)
  data = {
    behavior:      'twitter-share',
    twittertext:   TwitterProductShare.new(product).return_text,
    twitterurl:    product_url(product),
    twitteranchor: 'twitteranchor'
  }

  link_to(class: 'twitter-share', data: data) do
    tag(:i, class: 'fa fa-lg fa-twitter')
  end
end

In your view use this helper like this:

<%= twitter_share_link(@product) %>

Or you could even return the whole data hash from the TwitterProductShare.

spickermann
  • 100,941
  • 9
  • 101
  • 131
  • Thanks spickermann! Could you also tell me something about the `TwitterProductShare` class? Is it good to put all the methods in that class? Besides that is it okay to put that class into `app/services` folder or it should be somewhere else? – Sean Magyar Jun 11 '16 at 14:22
  • I think it makes perfectly sense to combine all methods in one place in a `TwitterProductShare` class, because they all serves the purpose to generate the Twitter link. I would place that class in the `app/models` folder. I don't see a reason to have a `services` folder. – spickermann Jun 11 '16 at 14:35
  • spickermann, isn't it better to put these kind of classes (not AR) to somewhere else like in `lib` folder or `services` folder? – Sean Magyar Jun 11 '16 at 14:47
  • That is primarily opinion-based. I would argue that a PORO (Plain Old Ruby Object) still might be a model in the meaning of the *M* in MVC (Model-View-Controller). In your example that class represents a model in your business domain and therefore belongs into the `models` folder. But you could also argue that it is unrelated to your app and therefore should live in the `lib` folder or should be extracted into a gem. I think both is fine as long as your team agrees. – spickermann Jun 11 '16 at 16:00